wai-extra-3.1.14: test/Network/Wai/Middleware/RealIpSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.Wai.Middleware.RealIpSpec (
spec,
) where
import qualified Data.ByteString.Lazy.Char8 as B8
import qualified Data.IP as IP
import Network.HTTP.Types (RequestHeaders, status200)
import Network.Wai
import Test.Hspec
import Network.Wai.Middleware.RealIp
import Network.Wai.Test
spec :: Spec
spec = do
describe "realIp" $ do
it "does nothing when header is missing" $ do
resp <- runApp "127.0.0.1" [] realIp
simpleBody resp `shouldBe` "127.0.0.1"
it "uses X-Forwarded-For when present" $ do
let headers = [("X-Forwarded-For", "1.1.1.1")]
resp <- runApp "127.0.0.1" headers realIp
simpleBody resp `shouldBe` "1.1.1.1"
it "ignores X-Forwarded-For from non-trusted ip" $ do
let headers = [("X-Forwarded-For", "1.1.1.1")]
resp <- runApp "1.2.3.4" headers realIp
simpleBody resp `shouldBe` "1.2.3.4"
it "ignores trusted ip addresses in X-Forwarded-For" $ do
let headers = [("X-Forwarded-For", "1.1.1.1, 10.0.0.1")]
resp <- runApp "127.0.0.1" headers realIp
simpleBody resp `shouldBe` "1.1.1.1"
it "ignores invalid ip addresses" $ do
let headers1 = [("X-Forwarded-For", "1.1.1")]
resp1 <- runApp "127.0.0.1" headers1 realIp
let headers2 = [("X-Forwarded-For", "1.1.1.1,foo")]
resp2 <- runApp "127.0.0.1" headers2 realIp
simpleBody resp1 `shouldBe` "127.0.0.1"
simpleBody resp2 `shouldBe` "1.1.1.1"
it "takes the last non-trusted address" $ do
let headers = [("X-Forwarded-For", "1.1.1.1, 2.2.2.2, 10.0.0.1")]
resp <- runApp "127.0.0.1" headers realIp
simpleBody resp `shouldBe` "2.2.2.2"
it "takes the first address when all are trusted" $ do
let headers = [("X-Forwarded-For", "192.168.0.1, 10.0.0.2, 10.0.0.1")]
resp <- runApp "127.0.0.1" headers realIp
simpleBody resp `shouldBe` "192.168.0.1"
it "handles repeated headers" $ do
let headers = [("X-Forwarded-For", "1.1.1.1"), ("X-Forwarded-For", "2.2.2.2")]
resp <- runApp "127.0.0.1" headers realIp
simpleBody resp `shouldBe` "2.2.2.2"
it "handles ipv6 addresses" $ do
let headers = [("X-Forwarded-For", "2001:db8::ff00:42:8329,10.0.0.1")]
resp <- runApp "::1" headers realIp
simpleBody resp `shouldBe` "2001:db8::ff00:42:8329"
describe "realIpHeader" $ do
it "uses specified header" $ do
let headers = [("X-Forwarded-For", "1.1.1.1"), ("X-Real-Ip", "2.2.2.2")]
resp <- runApp "127.0.0.1" headers $ realIpHeader "X-Real-Ip"
simpleBody resp `shouldBe` "2.2.2.2"
describe "realIpTrusted" $ do
it "uses provided trusted predicate" $ do
let headers = [("X-Forwarded-For", "10.0.0.1, 1.1.1.1")]
isTrusted1 ip = any (ipInRange ip) ["127.0.0.1/32", "1.1.1.1/32"]
isTrusted2 = flip ipInRange "1.1.1.1/32"
resp1 <- runApp "127.0.0.1" headers $ realIpTrusted "X-Forwarded-For" isTrusted1
resp2 <- runApp "10.0.0.2" headers $ realIpTrusted "X-Forwarded-For" isTrusted2
simpleBody resp1 `shouldBe` "10.0.0.1"
simpleBody resp2 `shouldBe` "10.0.0.2"
runApp :: IP.IP -> RequestHeaders -> Middleware -> IO SResponse
runApp ip hs mw =
runSession
( request
defaultRequest{remoteHost = IP.toSockAddr (ip, 80), requestHeaders = hs}
)
$ mw app
where
app req respond = respond $ responseLBS status200 [] $ renderIp req
renderIp = B8.pack . maybe "" (show . fst) . IP.fromSockAddr . remoteHost