Towards #4946. Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
127 lines
5.2 KiB
Haskell
127 lines
5.2 KiB
Haskell
module Feature.CorsSpec where
|
|
|
|
import Network.HTTP.Types
|
|
import Test.Hspec
|
|
import Test.Hspec.Wai
|
|
|
|
import PostgREST.Config (AppConfig (..))
|
|
|
|
import Protolude
|
|
import SpecHelper
|
|
|
|
spec :: SpecWithConfig
|
|
spec withConfig = do
|
|
withConfig baseCfg $ describe "CORS" $ do
|
|
it "replies naively and permissively to preflight request" $
|
|
request methodOptions "/"
|
|
[ ("Accept", "*/*")
|
|
, ("Origin", "http://example.com")
|
|
, ("Access-Control-Request-Method", "POST")
|
|
, ("Access-Control-Request-Headers", "Foo,Bar") ]
|
|
""
|
|
`shouldRespondWith`
|
|
""
|
|
{ matchHeaders = [ "Access-Control-Allow-Origin" <:> "*"
|
|
, "Access-Control-Allow-Methods" <:> "GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD"
|
|
, "Access-Control-Allow-Headers" <:> "Authorization, Foo, Bar, Accept, Accept-Language, Content-Language"
|
|
, "Access-Control-Max-Age" <:> "86400" ]
|
|
}
|
|
|
|
it "exposes necesssary response headers to regular request" $
|
|
request methodGet "/items"
|
|
[("Origin", "http://example.com")]
|
|
""
|
|
`shouldRespondWith`
|
|
ResponseMatcher
|
|
{ matchStatus = 200
|
|
, matchBody = MatchBody (\_ _ -> Nothing) -- match any body
|
|
, matchHeaders = [ "Access-Control-Expose-Headers" <:>
|
|
"Content-Encoding, Content-Location, Content-Range, Content-Type, \
|
|
\Date, Location, Server, Transfer-Encoding, Range-Unit"]
|
|
}
|
|
|
|
it "allows INFO body through even with CORS request headers present to postflight request" $ do
|
|
request methodOptions "/items"
|
|
[ ("Host", "localhost:3000")
|
|
, ("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0")
|
|
, ("Origin", "http://localhost:8000")
|
|
, ("Accept", "text/csv, */*; q=0.01")
|
|
, ("Accept-Language", "en-US,en;q=0.5")
|
|
, ("Accept-Encoding", "gzip, deflate")
|
|
, ("Referer", "http://localhost:8000/")
|
|
, ("Connection", "keep-alive") ]
|
|
""
|
|
`shouldRespondWith`
|
|
""
|
|
{ matchHeaders = [ "Access-Control-Allow-Origin" <:> "*" ] }
|
|
|
|
request methodOptions "/items"
|
|
[ ("Accept", "application/json") ]
|
|
""
|
|
`shouldRespondWith`
|
|
""
|
|
{ matchHeaders = [ "Access-Control-Allow-Origin" <:> "*" ] }
|
|
|
|
request methodOptions "/shops"
|
|
[ ("Accept", "application/geo+json") ]
|
|
""
|
|
`shouldRespondWith`
|
|
""
|
|
{ matchHeaders = [ "Access-Control-Allow-Origin" <:> "*" ] }
|
|
|
|
withConfig baseCfg { configServerCorsAllowedOrigins = ["http://example.com", "http://example2.com"] } $
|
|
describe "test preflight/non-preflight request and cors server allowed config" $ do
|
|
it "OPTIONS preflight request should return Access-Control-Allow-Origin equal to origin" $
|
|
request methodOptions "/items"
|
|
[ ("Accept", "*/*")
|
|
, ("Origin", "http://example.com")
|
|
, ("Access-Control-Request-Method", "POST")
|
|
, ("Access-Control-Request-Headers", "Content-Type") ]
|
|
""
|
|
`shouldRespondWith`
|
|
ResponseMatcher
|
|
{ matchStatus = 200
|
|
, matchBody = MatchBody (\_ _ -> Nothing) -- match any body
|
|
, matchHeaders = [ "Access-Control-Allow-Origin" <:> "http://example.com"
|
|
, "Access-Control-Allow-Credentials" <:> "true" ]
|
|
}
|
|
|
|
it "GET no preflight request should return Access-Control-Allow-Origin equal to origin" $
|
|
request methodGet "/items"
|
|
[ ("Accept", "*/*")
|
|
, ("Origin", "http://example.com") ]
|
|
""
|
|
`shouldRespondWith`
|
|
ResponseMatcher
|
|
{ matchStatus = 200
|
|
, matchBody = MatchBody (\_ _ -> Nothing) -- match any body
|
|
, matchHeaders = [ "Access-Control-Allow-Origin" <:> "http://example.com" ] }
|
|
|
|
it "GET no preflight request should not return Access-Control-Allow-Origin" $
|
|
request methodGet "/items"
|
|
[ ("Accept", "*/*")
|
|
, ("Origin", "http://invalid.com") ]
|
|
""
|
|
`shouldRespondWith`
|
|
ResponseMatcher
|
|
{ matchStatus = 200
|
|
, matchBody = MatchBody (\_ _ -> Nothing) -- match any body
|
|
, matchHeaders = [ matchHeaderAbsent "Access-Control-Allow-Origin" ] }
|
|
|
|
withConfig baseCfg { configServerCorsAllowedOrigins = [] } $
|
|
describe "test preflight request with empty cors allowed origin config" $
|
|
it "OPTIONS preflight request should allow all origins when config is not set or empty" $
|
|
request methodOptions "/items"
|
|
[ ("Accept", "*/*")
|
|
, ("Origin", "http://anyorigin.com")
|
|
, ("Access-Control-Request-Method", "POST")
|
|
, ("Access-Control-Request-Headers", "Content-Type") ]
|
|
""
|
|
`shouldRespondWith`
|
|
ResponseMatcher
|
|
{ matchStatus = 200
|
|
, matchBody = MatchBody (\_ _ -> Nothing) -- match any body
|
|
, matchHeaders = [ "Access-Control-Allow-Origin" <:> "*"
|
|
, matchHeaderValuePresent "Access-Control-Allow-Methods" "POST" ]
|
|
}
|