1{-# OPTIONS_GHC -fno-warn-orphans #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE StandaloneDeriving #-}
5module RequestSpec (main, spec) where
7import Network.Wai.Handler.Warp.File (parseByteRanges)
8import Network.Wai.Handler.Warp.Request
9import Network.Wai.Handler.Warp.Types
11import Test.Hspec.QuickCheck
12import qualified Data.ByteString as S
13import qualified Data.ByteString.Char8 as S8
14import qualified Network.HTTP.Types.Header as HH
22 describe "headerLines" $ do
23 it "takes until blank" $
24 blankSafe >>= (`shouldBe` ("", ["foo", "bar", "baz"]))
25 it "ignored leading whitespace in bodies" $
26 whiteSafe >>= (`shouldBe` (" hi there", ["foo", "bar", "baz"]))
27 it "throws OverLargeHeader when too many" $
28 tooMany `shouldThrow` overLargeHeader
29 it "throws OverLargeHeader when too large" $
30 tooLarge `shouldThrow` overLargeHeader
31 it "known bad chunking behavior #239" $ do
33 [ "GET / HTTP/1.1\r\nConnection: Close\r"
36 (actual, src) <- headerLinesList' chunks
37 leftover <- readLeftoverSource src
38 leftover `shouldBe` S.empty
39 actual `shouldBe` ["GET / HTTP/1.1", "Connection: Close"]
40 prop "random chunking" $ \breaks extraS -> do
41 let bsFull = "GET / HTTP/1.1\r\nConnection: Close\r\n\r\n" `S8.append` extra
42 extra = S8.pack extraS
43 chunks = loop breaks bsFull
44 loop [] bs = [bs, undefined]
48 (bs1, bs2) = S8.splitAt ((x `mod` 10) + 1) bs
49 (actual, src) <- headerLinesList' chunks
50 leftover <- consumeLen (length extraS) src
52 actual `shouldBe` ["GET / HTTP/1.1", "Connection: Close"]
53 leftover `shouldBe` extra
54 describe "parseByteRanges" $ do
55 let test x y = it x $ parseByteRanges (S8.pack x) `shouldBe` y
56 test "bytes=0-499" $ Just [HH.ByteRangeFromTo 0 499]
57 test "bytes=500-999" $ Just [HH.ByteRangeFromTo 500 999]
58 test "bytes=-500" $ Just [HH.ByteRangeSuffix 500]
59 test "bytes=9500-" $ Just [HH.ByteRangeFrom 9500]
60 test "foobytes=9500-" Nothing
61 test "bytes=0-0,-1" $ Just [HH.ByteRangeFromTo 0 0, HH.ByteRangeSuffix 1]
63 describe "headerLines" $ do
64 it "can handle a nomarl case" $ do
65 src <- mkSourceFunc ["Status: 200\r\nContent-Type: text/plain\r\n\r\n"] >>= mkSource
66 x <- headerLines True src
67 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
69 it "can handle a nasty case (1)" $ do
70 src <- mkSourceFunc ["Status: 200", "\r\nContent-Type: text/plain", "\r\n\r\n"] >>= mkSource
71 x <- headerLines True src
72 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
74 it "can handle a nasty case (1)" $ do
75 src <- mkSourceFunc ["Status: 200", "\r", "\nContent-Type: text/plain", "\r", "\n\r\n"] >>= mkSource
76 x <- headerLines True src
77 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
79 it "can handle a nasty case (1)" $ do
80 src <- mkSourceFunc ["Status: 200", "\r", "\n", "Content-Type: text/plain", "\r", "\n", "\r", "\n"] >>= mkSource
81 x <- headerLines True src
82 x `shouldBe` ["Status: 200", "Content-Type: text/plain"]
84 it "can handle an illegal case (1)" $ do
85 src <- mkSourceFunc ["\nStatus:", "\n 200", "\nContent-Type: text/plain", "\r\n\r\n"] >>= mkSource
86 x <- headerLines True src
88 y <- headerLines True src
89 y `shouldBe` ["Status: 200", "Content-Type: text/plain"]
92 blankSafe = headerLinesList ["f", "oo\n", "bar\nbaz\n\r\n"]
93 whiteSafe = headerLinesList ["foo\r\nbar\r\nbaz\r\n\r\n hi there"]
94 tooMany = headerLinesList $ repeat "f\n"
95 tooLarge = headerLinesList $ repeat "f"
97headerLinesList :: [S8.ByteString] -> IO (S8.ByteString, [S8.ByteString])
98headerLinesList orig = do
99 (res, src) <- headerLinesList' orig
100 leftover <- readLeftoverSource src
101 return (leftover, res)
103headerLinesList' :: [S8.ByteString] -> IO ([S8.ByteString], Source)
104headerLinesList' orig = do
114 res <- headerLines True src'
117consumeLen :: Int -> Source -> IO S8.ByteString
122 | len <= 0 = return $ S.concat $ front []
128 let (x, _) = S.splitAt len bs
129 loop (front . (x:)) (len - S.length x)
131overLargeHeader :: Selector InvalidRequest
132overLargeHeader e = e == OverLargeHeader
134mkSourceFunc :: [S8.ByteString] -> IO (IO S8.ByteString)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list