-- | Infer the remote IP address using the given header, but only if the
-- request came from an IP that is trusted by the provided predicate.
--
-- The last non-trusted address is used to replace the 'remoteHost' in
-- the 'Request', unless all present IP addresses are trusted, in which
-- case the first address is used. Invalid IP addresses are ignored, and
-- the remoteHost value remains unaltered if no valid IP addresses are
-- found.
--
-- Examples:
--
-- @ realIpTrusted "X-Forwarded-For" $ flip ipInRange "10.0.0.0/8" @
--
-- @ realIpTrusted "X-Real-Ip" $ \\ip -> any (ipInRange ip) defaultTrusted @
--
-- @since 3.1.5
realIpTrusted :: HeaderName -> (IP.IP -> Bool) -> Middleware
realIpTrusted header isTrusted app req respond = app req' respond
  where
    req' = fromMaybe req $ do
             (ip, port) <- IP.fromSockAddr (remoteHost req)
             ip' <- if isTrusted ip
                      then findRealIp (requestHeaders req) header isTrusted
                      else Nothing
             Just $ req { remoteHost = IP.toSockAddr (ip', port) }

-- | Standard private IP ranges.
--
-- @since 3.1.5
realIpTrusted :: HeaderName -> (IP.IP -> Bool) -> Middleware
realIpTrusted header isTrusted app req respond = app req' respond
  where
    req' = fromMaybe req $ do
             (ip, port) <- IP.fromSockAddr (remoteHost req)
             ip' <- if isTrusted ip
                      then findRealIp (requestHeaders req) header isTrusted
                      else Nothing
             Just $ req { remoteHost = IP.toSockAddr (ip', port) }

-- | Standard private IP ranges.
--
-- @since 3.1.5
realIpTrusted header isTrusted app req respond = app req' respond
  where
    req' = fromMaybe req $ do
             (ip, port) <- IP.fromSockAddr (remoteHost req)
             ip' <- if isTrusted ip
                      then findRealIp (requestHeaders req) header isTrusted
                      else Nothing
             Just $ req { remoteHost = IP.toSockAddr (ip', port) }

-- | Standard private IP ranges.
--
-- @since 3.1.5