@@ -43,8 +43,10 @@ module Network.Wai
43 , mkCIByteString
43 , mkCIByteString
44 -- ** Request header names
44 -- ** Request header names
45 , RequestHeader
45 , RequestHeader
46 -- ** Response header names
47 -- ** Response header names
47 , ResponseHeader
48 , ResponseHeader
48 -- ** Response status code
50 -- ** Response status code
49 , Status (..)
51 , Status (..)
50 , status200
52 , status200
@@ -57,11 +59,11 @@ module Network.Wai
57 , status404
59 , status404
58 , status405
60 , status405
59 , status500
61 , status500
62 -- * WAI interface
62 -- * WAI interface
63 , Request (..)
63 , Request (..)
64 , Response (..)
64 , Response (..)
65 , Application
67 , Application
66 , Middleware
68 , Middleware
@@ -72,8 +74,11 @@ import qualified Data.ByteString.Lazy as L
72import Data.Char (toLower)
74import Data.Char (toLower)
73import Data.String (IsString (..))
75import Data.String (IsString (..))
74import Data.Typeable (Typeable)
76import Data.Typeable (Typeable)
75−import Data.Enumerator (Enumerator, Iteratee)
77+import Data.Enumerator (Enumerator, Iteratee, ($$), joinI, enumList, run_)
78+import qualified Data.Enumerator as E
79+import Data.Enumerator.IO (enumFile)
76−import Blaze.ByteString.Builder (Builder)
80+import Blaze.ByteString.Builder (Builder, fromByteString, fromLazyByteString)
81+import Data.Data (Data)
78-- | HTTP request method. Since the HTTP protocol allows arbitrary request
83-- | HTTP request method. Since the HTTP protocol allows arbitrary request
79-- methods, we leave this open as a 'B.ByteString'. Please note the request
84-- methods, we leave this open as a 'B.ByteString'. Please note the request
@@ -109,6 +114,7 @@ data CIByteString = CIByteString
109 { ciOriginal :: !B.ByteString
114 { ciOriginal :: !B.ByteString
110 , ciLowerCase :: !B.ByteString
115 , ciLowerCase :: !B.ByteString
117+ deriving (Data, Typeable)
113-- | Convert a regular bytestring to a case-insensitive bytestring.
119-- | Convert a regular bytestring to a case-insensitive bytestring.
114mkCIByteString :: B.ByteString -> CIByteString
120mkCIByteString :: B.ByteString -> CIByteString
@@ -116,6 +122,8 @@ mkCIByteString bs = CIByteString bs $ B8.map toLower bs
117instance Show CIByteString where
123instance Show CIByteString where
118 show = show . ciOriginal
124 show = show . ciOriginal
125+instance Read CIByteString where
126+ readsPrec i = map (\(x, y) -> (mkCIByteString x, y)) . readsPrec i
119instance Eq CIByteString where
127instance Eq CIByteString where
120 x == y = ciLowerCase x == ciLowerCase y
128 x == y = ciLowerCase x == ciLowerCase y
121instance Ord CIByteString where
129instance Ord CIByteString where
@@ -126,10 +134,12 @@ instance IsString CIByteString where
126-- | Headers sent from the client to the server. Note that this is a
134-- | Headers sent from the client to the server. Note that this is a
127-- case-insensitive string, as the HTTP spec specifies.
135-- case-insensitive string, as the HTTP spec specifies.
128type RequestHeader = CIByteString
136type RequestHeader = CIByteString
137+type RequestHeaders = [(RequestHeader, B.ByteString)]
130-- | Headers sent from the server to the client. Note that this is a
139-- | Headers sent from the server to the client. Note that this is a
131-- case-insensitive string, as the HTTP spec specifies.
140-- case-insensitive string, as the HTTP spec specifies.
132type ResponseHeader = CIByteString
141type ResponseHeader = CIByteString
142+type ResponseHeaders = [(ResponseHeader, B.ByteString)]
134-- | HTTP status code; a combination of the integral code and a status message.
144-- | HTTP status code; a combination of the integral code and a status message.
135-- Equality is determined solely on the basis of the integral code.
145-- Equality is determined solely on the basis of the integral code.
@@ -205,35 +215,20 @@ data Request = Request
206 deriving Typeable
216 deriving Typeable
208−-- | The response body returned to the server from the application. We provide
218+data Response
209−-- three separate constructors as optimizations:
211−-- * 'ResponseEnumerator' is the most general type, allowing constant-memory
212−-- production of a response, even in the presence of interleaved I\/O actions.
214−-- * 'ResponseFile' serves a static file from the filesystem. Many servers use
215−-- a sendfile system call to optimize this type of serving, making this a huge
218−-- * 'ResponseLBS'. Often times, we wish to return a response that includes no
219−-- interleaved I\/O. In this case, we can use Haskell's natural laziness to our
220−-- advantage, and represent the response as a lazy bytestring.
222− = ResponseFile FilePath
219+ = ResponseFile Status ResponseHeaders FilePath
223− | ResponseEnumerator (Iteratee Builder IO () -> IO ())
220+ | ResponseLBS Status ResponseHeaders L.ByteString
224− | ResponseLBS L.ByteString
221+ | ResponseEnumerator (forall a. ResponseEnumerator a)
227−data Response = Response
223+type ResponseEnumerator a =
228− { status :: Status
224+ (Status -> ResponseHeaders -> Iteratee Builder IO a) -> IO a
229− , responseHeaders :: [(ResponseHeader, B.ByteString)]
225+
230− -- | A common optimization is to use the sendfile system call when sending
226+responseEnumerator :: Response -> ResponseEnumerator a
231− -- files from the disk. This datatype facilitates this optimization; if
227+responseEnumerator (ResponseEnumerator e) f = e f
232− -- 'Left' is returned, the server will send the file from the disk by
228+responseEnumerator (ResponseFile s h fp) f =
233− -- whatever means it wishes. If 'Right', it will call the 'Enumerator'.
229+ run_ $ enumFile fp $$ joinI $ E.map fromByteString $$ f s h
234− , responseBody :: ResponseBody
230+responseEnumerator (ResponseLBS s h lbs) f =
235− }
231+ run_ $ enumList 1 [fromLazyByteString lbs] $$ f s h
238type Application = Request -> IO Response
233type Application = Request -> IO Response