@@ -35,31 +35,41 @@ module Network.Wai
36 -- $show_read
36 -- $show_read
37 -- ** Request method
37 -- ** Request method
38− Method (..)
38+ Method
39− , methodFromBS
39+ , methodOPTIONS
40− , methodToBS
40+ , methodGET
41− -- ** URL scheme (http versus https)
41+ , methodHEAD
42− , UrlScheme (..)
42+ , methodPOST
43 -- ** HTTP protocol versions
47 -- ** HTTP protocol versions
44− , HttpVersion (..)
48+ , HttpVersion
45− , httpVersionFromBS
49+ , http09
46− , httpVersionToBS
50+ , http10
52+ -- ** Case-insensitive byte strings
47 -- ** Request header names
55 -- ** Request header names
48− , RequestHeader (..)
56+ , RequestHeader
50− , requestHeaderFromBS
52− , requestHeaderToLower
53 -- ** Response header names
57 -- ** Response header names
54− , ResponseHeader (..)
58+ , ResponseHeader
56− , responseHeaderFromBS
58− , responseHeaderToLower
59 -- ** Response status code
59 -- ** Response status code
60 , Status (..)
60 , Status (..)
61− , statusCode
61+ , status200
62− , statusMessage
62+ , status301
63 -- ** Source
73 -- ** Source
64 , Source (..)
74 , Source (..)
65 -- * Enumerator
75 -- * Enumerator
@@ -73,7 +83,9 @@ module Network.Wai
74import qualified Data.ByteString as B
84import qualified Data.ByteString as B
75import qualified Data.ByteString.Char8 as B8
85import qualified Data.ByteString.Char8 as B8
86+import qualified Data.ByteString.Lazy as L
76import Data.Char (toLower)
87import Data.Char (toLower)
88+import Data.String (IsString (..))
78-- $show_read
90-- $show_read
@@ -85,82 +97,62 @@ import Data.Char (toLower)
85-- | HTTP request method. This data type is extensible via the Method
97-- | HTTP request method. This data type is extensible via the Method
86-- constructor. Request methods are case-sensitive, and comparison is achieved
98-- constructor. Request methods are case-sensitive, and comparison is achieved
87-- by converting to a 'B.ByteString' via 'methodToBS'.
99-- by converting to a 'B.ByteString' via 'methodToBS'.
97− | Method B.ByteString
100+type Method = B.ByteString
98− deriving (Show, Read)
101+
99−
102+methodOPTIONS :: Method
100−instance Eq Method where
103+methodOPTIONS = B8.pack "OPTIONS"
101− x == y = methodToBS x == methodToBS y
104+
102−
105+methodGET :: Method
103−methodFromBS :: B.ByteString -> Method
106+methodGET = B8.pack "GET"
105− | B.length bs <= 7 = case B8.unpack bs of
108+methodHEAD :: Method
106− "OPTIONS" -> OPTIONS
113− "CONNECT" -> CONNECT
115− | otherwise = Method bs
117−methodToBS :: Method -> B.ByteString
118−methodToBS OPTIONS = B8.pack "OPTIONS"
119−methodToBS GET = B8.pack "GET"
120−methodToBS HEAD = B8.pack "HEAD"
109+methodHEAD = B8.pack "HEAD"
121−methodToBS POST = B8.pack "POST"
112+methodPOST = B8.pack "POST"
122−methodToBS PUT = B8.pack "PUT"
115+methodPUT = B8.pack "PUT"
117+methodDELETE :: Method
123−methodToBS DELETE = B8.pack "DELETE"
118+methodDELETE = B8.pack "DELETE"
120+methodTRACE :: Method
124−methodToBS TRACE = B8.pack "TRACE"
121+methodTRACE = B8.pack "TRACE"
123+methodCONNECT :: Method
125−methodToBS CONNECT = B8.pack "CONNECT"
124+methodCONNECT = B8.pack "CONNECT"
126−methodToBS (Method bs) = bs
128−data UrlScheme = HTTP | HTTPS
131-- | Version of HTTP protocol used in current request. This data type is
126-- | Version of HTTP protocol used in current request. This data type is
132-- extensible via the HttpVersion constructor. Comparison is achieved by
127-- extensible via the HttpVersion constructor. Comparison is achieved by
133-- converting to a 'B.ByteString' via 'httpVersionToBS'.
128-- converting to a 'B.ByteString' via 'httpVersionToBS'.
134−data HttpVersion =
129+type HttpVersion = B.ByteString
138− | HttpVersion B.ByteString
139− deriving (Show, Read)
141−instance Eq HttpVersion where
131+http09 :: HttpVersion
142− x == y = httpVersionToBS x == httpVersionToBS y
132+http09 = B8.pack "0.9"
144−-- | This function takes the information after \"HTTP\/\". For example:
134+http10 :: HttpVersion
145−--
135+http10 = B8.pack "1.0"
146−-- @ 'httpVersionFromBS' ('B8.pack' \"1.0\") == 'Http10' @
136+
147−httpVersionFromBS :: B.ByteString -> HttpVersion
137+http11 :: HttpVersion
148−httpVersionFromBS bs
138+http11 = B8.pack "1.1"
149− | B.length bs == 3 = case B8.unpack bs of
139+
150− "0.9" -> Http09
140+data CIByteString = CIByteString
151− "1.0" -> Http10
141+ { ciOriginal :: !B.ByteString
152− "1.1" -> Http11
142+ , ciLowerCase :: !B.ByteString
153− _ -> HttpVersion bs
143+ }
154− | otherwise = HttpVersion bs
144+
155−
145+mkCIByteString :: B.ByteString -> CIByteString
156−-- | Returns the version number, for example:
146+mkCIByteString bs = CIByteString bs $ B8.map toLower bs
158−-- @ 'B8.unpack' ('httpVersionToBS' 'Http10') == \"1.0\" @
148+instance Show CIByteString where
159−httpVersionToBS :: HttpVersion -> B.ByteString
149+ show = show . ciOriginal
160−httpVersionToBS Http09 = B8.pack "0.9"
150+instance Eq CIByteString where
161−httpVersionToBS Http10 = B8.pack "1.0"
151+ x == y = ciLowerCase x == ciLowerCase y
162−httpVersionToBS Http11 = B8.pack "1.1"
152+instance Ord CIByteString where
163−httpVersionToBS (HttpVersion bs) = bs
153+ x <= y = ciLowerCase x <= ciLowerCase y
154+instance IsString CIByteString where
155+ fromString = mkCIByteString . fromString
165-- | Headers sent from the client to the server. Clearly, this is not a
157-- | Headers sent from the client to the server. Clearly, this is not a
166-- complete list of all possible headers, but rather a selection of common
158-- complete list of all possible headers, but rather a selection of common
@@ -172,68 +164,7 @@ httpVersionToBS (HttpVersion bs) = bs
173-- Equality determined by conversion via 'requestHeaderToLower'. Request
165-- Equality determined by conversion via 'requestHeaderToLower'. Request
174-- headers are *not* case sensitive (a change from version 0.0 of WAI).
166-- headers are *not* case sensitive (a change from version 0.0 of WAI).
175−data RequestHeader =
167+type RequestHeader = CIByteString
186− | RequestHeader B.ByteString B.ByteString
187− deriving (Show, Read)
189−lowerBS :: B.ByteString -> B.ByteString
190−lowerBS = B8.map toLower
192−requestHeader :: B.ByteString -> RequestHeader
193−requestHeader x = RequestHeader x $ lowerBS x
195−instance Eq RequestHeader where
196− x == y = requestHeaderToLower x == requestHeaderToLower y
198−requestHeaderFromBS :: B.ByteString -> RequestHeader
199−requestHeaderFromBS bs = case B8.unpack bs of
201− "Accept-Charset" -> AcceptCharset
202− "Accept-Encoding" -> AcceptEncoding
203− "Accept-Language" -> AcceptLanguage
204− "Authorization" -> Authorization
206− "Content-Length" -> ReqContentLength
207− "Content-Type" -> ReqContentType
209− "Referer" -> Referer
210− _ -> requestHeader bs
212−requestHeaderToBS :: RequestHeader -> B.ByteString
213−requestHeaderToBS Accept = B8.pack "Accept"
214−requestHeaderToBS AcceptCharset = B8.pack "Accept-Charset"
215−requestHeaderToBS AcceptEncoding = B8.pack "Accept-Encoding"
216−requestHeaderToBS AcceptLanguage = B8.pack "Accept-Language"
217−requestHeaderToBS Authorization = B8.pack "Authorization"
218−requestHeaderToBS Cookie = B8.pack "Cookie"
219−requestHeaderToBS ReqContentLength = B8.pack "Content-Length"
220−requestHeaderToBS ReqContentType = B8.pack "Content-Type"
221−requestHeaderToBS Host = B8.pack "Host"
222−requestHeaderToBS Referer = B8.pack "Referer"
223−requestHeaderToBS (RequestHeader bs _) = bs
225−requestHeaderToLower :: RequestHeader -> B.ByteString
226−requestHeaderToLower Accept = B8.pack "accept"
227−requestHeaderToLower AcceptCharset = B8.pack "accept-charset"
228−requestHeaderToLower AcceptEncoding = B8.pack "accept-encoding"
229−requestHeaderToLower AcceptLanguage = B8.pack "accept-language"
230−requestHeaderToLower Authorization = B8.pack "authorization"
231−requestHeaderToLower Cookie = B8.pack "cookie"
232−requestHeaderToLower ReqContentLength = B8.pack "content-Length"
233−requestHeaderToLower ReqContentType = B8.pack "content-Type"
234−requestHeaderToLower Host = B8.pack "host"
235−requestHeaderToLower Referer = B8.pack "referer"
236−requestHeaderToLower (RequestHeader _ bs) = bs
238-- | Headers sent from the server to the client. Clearly, this is not a
169-- | Headers sent from the server to the client. Clearly, this is not a
239-- complete list of all possible headers, but rather a selection of common
170-- complete list of all possible headers, but rather a selection of common
@@ -244,61 +175,7 @@ requestHeaderToLower (RequestHeader _ bs) = bs
245-- Equality determined by conversion via 'responseHeaderToLower'. Response
176-- Equality determined by conversion via 'responseHeaderToLower'. Response
246-- headers are *not* case sensitive (a change from version 0.0 of WAI).
177-- headers are *not* case sensitive (a change from version 0.0 of WAI).
247−data ResponseHeader =
251− | ContentDisposition
257− | ResponseHeader B.ByteString B.ByteString
260−instance Eq ResponseHeader where
261− x == y = responseHeaderToBS x == responseHeaderToBS y
263−responseHeader :: B.ByteString -> ResponseHeader
264−responseHeader x = ResponseHeader x $ lowerBS x
266−responseHeaderFromBS :: B.ByteString -> ResponseHeader
267−responseHeaderFromBS bs = case B8.unpack bs of
268− "Content-Encoding" -> ContentEncoding
269− "Content-Language" -> ContentLanguage
270− "Content-Length" -> ContentLength
271− "Content-Disposition" -> ContentDisposition
272− "Content-Type" -> ContentType
273− "Expires" -> Expires
274− "Location" -> Location
276− "Set-Cookie" -> SetCookie
277− _ -> responseHeader bs
279−responseHeaderToBS :: ResponseHeader -> B.ByteString
280−responseHeaderToBS ContentEncoding = B8.pack "Content-Encoding"
281−responseHeaderToBS ContentLanguage = B8.pack "Content-Language"
282−responseHeaderToBS ContentLength = B8.pack "Content-Length"
283−responseHeaderToBS ContentDisposition = B8.pack "Content-Disposition"
284−responseHeaderToBS ContentType = B8.pack "Content-Type"
285−responseHeaderToBS Expires = B8.pack "Expires"
286−responseHeaderToBS Location = B8.pack "Location"
287−responseHeaderToBS Server = B8.pack "Server"
288−responseHeaderToBS SetCookie = B8.pack "Set-Cookie"
289−responseHeaderToBS (ResponseHeader bs _) = bs
291−responseHeaderToLower :: ResponseHeader -> B.ByteString
292−responseHeaderToLower ContentEncoding = B8.pack "content-encoding"
293−responseHeaderToLower ContentLanguage = B8.pack "content-language"
294−responseHeaderToLower ContentLength = B8.pack "content-length"
295−responseHeaderToLower ContentDisposition = B8.pack "content-disposition"
296−responseHeaderToLower ContentType = B8.pack "content-type"
297−responseHeaderToLower Expires = B8.pack "expires"
298−responseHeaderToLower Location = B8.pack "location"
299−responseHeaderToLower Server = B8.pack "server"
300−responseHeaderToLower SetCookie = B8.pack "set-cookie"
301−responseHeaderToLower (ResponseHeader _ bs) = bs
178+type ResponseHeader = CIByteString
303-- | This attempts to provide the most common HTTP status codes, not all of
180-- | This attempts to provide the most common HTTP status codes, not all of
304-- them. Use the Status constructor when you want to create a status code not
181-- them. Use the Status constructor when you want to create a status code not
@@ -306,48 +183,41 @@ responseHeaderToLower (ResponseHeader _ bs) = bs
307-- The 'Eq' instance tests equality based only on the numeric status code
184-- The 'Eq' instance tests equality based only on the numeric status code
308-- value. See 'statusCode'.
185-- value. See 'statusCode'.
309−data Status =
186+data Status = Status { statusCode :: Int, statusMessage :: B.ByteString }
320− | Status Int B.ByteString
321 deriving Show
187 deriving Show
323instance Eq Status where
189instance Eq Status where
324 x == y = statusCode x == statusCode y
190 x == y = statusCode x == statusCode y
326−statusCode :: Status -> Int
192+status200 :: Status
327−statusCode Status200 = 200
193+status200 = Status 200 $ B8.pack "OK"
328−statusCode Status301 = 301
194+
329−statusCode Status302 = 302
195+status301 :: Status
330−statusCode Status303 = 303
331−statusCode Status400 = 400
332−statusCode Status401 = 401
333−statusCode Status403 = 403
334−statusCode Status404 = 404
335−statusCode Status405 = 405
336−statusCode Status500 = 500
337−statusCode (Status i _) = i
339−statusMessage :: Status -> B.ByteString
340−statusMessage Status200 = B8.pack "OK"
341−statusMessage Status301 = B8.pack "Moved Permanently"
196+status301 = Status 301 $ B8.pack "Moved Permanently"
342−statusMessage Status302 = B8.pack "Found"
197+
199+status302 = Status 302 $ B8.pack "Found"
343−statusMessage Status303 = B8.pack "See Other"
202+status303 = Status 303 $ B8.pack "See Other"
344−statusMessage Status400 = B8.pack "Bad Request"
205+status400 = Status 400 $ B8.pack "Bad Request"
345−statusMessage Status401 = B8.pack "Unauthorized"
208+status401 = Status 401 $ B8.pack "Unauthorized"
346−statusMessage Status403 = B8.pack "Forbidden"
211+status403 = Status 403 $ B8.pack "Forbidden"
347−statusMessage Status404 = B8.pack "Not Found"
214+status404 = Status 404 $ B8.pack "Not Found"
348−statusMessage Status405 = B8.pack "Method Not Allowed"
217+status405 = Status 405 $ B8.pack "Method Not Allowed"
349−statusMessage Status500 = B8.pack "Internal Server Error"
220+status500 = Status 500 $ B8.pack "Internal Server Error"
350−statusMessage (Status _ m) = m
352-- | This is a source for 'B.ByteString's. It is a function (wrapped in a
222-- | This is a source for 'B.ByteString's. It is a function (wrapped in a
353-- newtype) that will return Nothing if the data has been completely consumed,
223-- newtype) that will return Nothing if the data has been completely consumed,
@@ -408,13 +278,17 @@ data Request = Request
408 , serverName :: B.ByteString
278 , serverName :: B.ByteString
409 , serverPort :: Int
279 , serverPort :: Int
410 , requestHeaders :: [(RequestHeader, B.ByteString)]
280 , requestHeaders :: [(RequestHeader, B.ByteString)]
411− , urlScheme :: UrlScheme
281+ , isSecure :: Bool
412 , requestBody :: Source
282 , requestBody :: Source
413 , errorHandler :: String -> IO ()
283 , errorHandler :: String -> IO ()
414 -- | The client\'s host information.
284 -- | The client\'s host information.
415 , remoteHost :: B.ByteString
285 , remoteHost :: B.ByteString
288+data ResponseBody = ResponseFile FilePath
289+ | ResponseEnumerator Enumerator
290+ | ResponseLBS L.ByteString
418data Response = Response
292data Response = Response
419 { status :: Status
293 { status :: Status
420 , responseHeaders :: [(ResponseHeader, B.ByteString)]
294 , responseHeaders :: [(ResponseHeader, B.ByteString)]
@@ -422,7 +296,7 @@ data Response = Response
422 -- files from the disk. This datatype facilitates this optimization; if
296 -- files from the disk. This datatype facilitates this optimization; if
423 -- 'Left' is returned, the server will send the file from the disk by
297 -- 'Left' is returned, the server will send the file from the disk by
424 -- whatever means it wishes. If 'Right', it will call the 'Enumerator'.
298 -- whatever means it wishes. If 'Right', it will call the 'Enumerator'.
425− , responseBody :: Either FilePath Enumerator
299+ , responseBody :: ResponseBody
428type Application = Request -> IO Response
302type Application = Request -> IO Response