File: FileSpec.hs

package info (click to toggle)
haskell-warp 3.4.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 456 kB
  • sloc: haskell: 4,873; makefile: 10
file content (132 lines) | stat: -rw-r--r-- 4,512 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
{-# LANGUAGE OverloadedStrings #-}

module FileSpec (main, spec) where

import Data.ByteString
import Data.String (fromString)
import Network.HTTP.Types
import Network.Wai.Handler.Warp.File
import Network.Wai.Handler.Warp.FileInfoCache
import Network.Wai.Handler.Warp.Header
import System.IO.Unsafe (unsafePerformIO)

import Test.Hspec

main :: IO ()
main = hspec spec

changeHeaders
    :: (ResponseHeaders -> ResponseHeaders) -> RspFileInfo -> RspFileInfo
changeHeaders f rfi =
    case rfi of
        WithBody s hs off len -> WithBody s (f hs) off len
        other -> other

getHeaders :: RspFileInfo -> ResponseHeaders
getHeaders rfi =
    case rfi of
        WithBody _ hs _ _ -> hs
        _ -> []

testFileRange
    :: String
    -> RequestHeaders
    -> RspFileInfo
    -> Spec
testFileRange desc reqhs ans = it desc $ do
    finfo <- getInfo "attic/hex"
    let f = (:) ("Last-Modified", fileInfoDate finfo)
        hs = getHeaders ans
        ans' = changeHeaders f ans
    conditionalRequest
        finfo
        []
        methodGet
        (indexResponseHeader hs)
        (indexRequestHeader reqhs)
        `shouldBe` ans'

farPast, farFuture :: ByteString
farPast = "Thu, 01 Jan 1970 00:00:00 GMT"
farFuture = "Sun, 05 Oct 3000 00:00:00 GMT"

regularBody :: RspFileInfo
regularBody = WithBody ok200 [("Content-Length", "16"), ("Accept-Ranges", "bytes")] 0 16

make206Body :: Integer -> Integer -> RspFileInfo
make206Body start len =
    WithBody status206 [crHeader, lenHeader, ("Accept-Ranges", "bytes")] start len
  where
    lenHeader = ("Content-Length", fromString $ show len)
    crHeader =
        ( "Content-Range"
        , fromString $ "bytes " <> show start <> "-" <> show (start + len - 1) <> "/16"
        )

spec :: Spec
spec = do
    describe "conditionalRequest" $ do
        testFileRange
            "gets a file size from file system"
            []
            regularBody
        testFileRange
            "gets a file size from file system and handles Range and returns Partical Content"
            [("Range", "bytes=2-14")]
            $ make206Body 2 13
        testFileRange
            "truncates end point of range to file size"
            [("Range", "bytes=10-20")]
            $ make206Body 10 6
        testFileRange
            "gets a file size from file system and handles Range and returns OK if Range means the entire"
            [("Range:", "bytes=0-15")]
            regularBody
        testFileRange
            "returns a 412 if the file has been changed in the meantime"
            [("If-Unmodified-Since", farPast)]
            $ WithoutBody status412
        testFileRange
            "gets a file if the file has not been changed in the meantime"
            [("If-Unmodified-Since", farFuture)]
            regularBody
        testFileRange
            "ignores the If-Unmodified-Since header if an If-Match header is also present"
            [("If-Match", "SomeETag"), ("If-Unmodified-Since", farPast)]
            regularBody
        testFileRange
            "still gives only a range, even after conditionals"
            [ ("If-Match", "SomeETag")
            , ("If-Unmodified-Since", farPast)
            , ("Range", "bytes=10-20")
            ]
            $ make206Body 10 6
        testFileRange
            "gets a file if the file has been changed in the meantime"
            [("If-Modified-Since", farPast)]
            regularBody
        testFileRange
            "returns a 304 if the file has not been changed in the meantime"
            [("If-Modified-Since", farFuture)]
            $ WithoutBody status304
        testFileRange
            "ignores the If-Modified-Since header if an If-None-Match header is also present"
            [("If-None-Match", "SomeETag"), ("If-Modified-Since", farFuture)]
            regularBody
        testFileRange
            "still gives only a range, even after conditionals"
            [ ("If-None-Match", "SomeETag")
            , ("If-Modified-Since", farFuture)
            , ("Range", "bytes=10-13")
            ]
            $ make206Body 10 4
        testFileRange
            "gives the a range, if the condition is met"
            [ ("If-Range", fileInfoDate (unsafePerformIO $ getInfo "attic/hex"))
            , ("Range", "bytes=2-7")
            ]
            $ make206Body 2 6
        testFileRange
            "gives the entire body and ignores the Range header if the condition isn't met"
            [("If-Range", farPast), ("Range", "bytes=2-7")]
            regularBody