@@ -43,8 +43,10 @@ module Network.Wai
4343 , mkCIByteString
4444 -- ** Request header names
4545 , RequestHeader
46+ , RequestHeaders
4647 -- ** Response header names
4748 , ResponseHeader
49+ , ResponseHeaders
4850 -- ** Response status code
4951 , Status (..)
5052 , status200
@@ -57,11 +59,11 @@ module Network.Wai
5759 , status404
5860 , status405
5961 , status500
60− -- ** Response body
61− , ResponseBody (..)
6262 -- * WAI interface
6363 , Request (..)
6464 , Response (..)
65+ , ResponseEnumerator
66+ , responseEnumerator
6567 , Application
6668 , Middleware
6769 ) where
@@ -72,8 +74,11 @@ import qualified Data.ByteString.Lazy as L
7274import Data.Char (toLower)
7375import Data.String (IsString (..))
7476import Data.Typeable (Typeable)
75−import Data.Enumerator (Enumerator, Iteratee)
76−import Blaze.ByteString.Builder (Builder)
77+import Data.Enumerator (Enumerator, Iteratee, ($$), joinI, enumList, run_)
78+import qualified Data.Enumerator as E
79+import Data.Enumerator.IO (enumFile)
80+import Blaze.ByteString.Builder (Builder, fromByteString, fromLazyByteString)
81+import Data.Data (Data)
7782
7883-- | HTTP request method. Since the HTTP protocol allows arbitrary request
7984-- methods, we leave this open as a 'B.ByteString'. Please note the request
@@ -109,6 +114,7 @@ data CIByteString = CIByteString
109114 { ciOriginal :: !B.ByteString
110115 , ciLowerCase :: !B.ByteString
111116 }
117+ deriving (Data, Typeable)
112118
113119-- | Convert a regular bytestring to a case-insensitive bytestring.
114120mkCIByteString :: B.ByteString -> CIByteString
@@ -116,6 +122,8 @@ mkCIByteString bs = CIByteString bs $ B8.map toLower bs
116122
117123instance Show CIByteString where
118124 show = show . ciOriginal
125+instance Read CIByteString where
126+ readsPrec i = map (\(x, y) -> (mkCIByteString x, y)) . readsPrec i
119127instance Eq CIByteString where
120128 x == y = ciLowerCase x == ciLowerCase y
121129instance Ord CIByteString where
@@ -126,10 +134,12 @@ instance IsString CIByteString where
126134-- | Headers sent from the client to the server. Note that this is a
127135-- case-insensitive string, as the HTTP spec specifies.
128136type RequestHeader = CIByteString
137+type RequestHeaders = [(RequestHeader, B.ByteString)]
129138
130139-- | Headers sent from the server to the client. Note that this is a
131140-- case-insensitive string, as the HTTP spec specifies.
132141type ResponseHeader = CIByteString
142+type ResponseHeaders = [(ResponseHeader, B.ByteString)]
133143
134144-- | HTTP status code; a combination of the integral code and a status message.
135145-- Equality is determined solely on the basis of the integral code.
@@ -205,35 +215,20 @@ data Request = Request
205215 }
206216 deriving Typeable
207217
208−-- | The response body returned to the server from the application. We provide
209−-- three separate constructors as optimizations:
210−--
211−-- * 'ResponseEnumerator' is the most general type, allowing constant-memory
212−-- production of a response, even in the presence of interleaved I\/O actions.
213−--
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
216−-- performance gain.
217−--
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.
221−data ResponseBody
222− = ResponseFile FilePath
223− | ResponseEnumerator (Iteratee Builder IO () -> IO ())
224− | ResponseLBS L.ByteString
225− deriving Typeable
218+data Response
219+ = ResponseFile Status ResponseHeaders FilePath
220+ | ResponseLBS Status ResponseHeaders L.ByteString
221+ | ResponseEnumerator (forall a. ResponseEnumerator a)
226222
227−data Response = Response
228− { status :: Status
229− , responseHeaders :: [(ResponseHeader, B.ByteString)]
230− -- | A common optimization is to use the sendfile system call when sending
231− -- files from the disk. This datatype facilitates this optimization; if
232− -- 'Left' is returned, the server will send the file from the disk by
233− -- whatever means it wishes. If 'Right', it will call the 'Enumerator'.
234− , responseBody :: ResponseBody
235− }
236− deriving Typeable
223+type ResponseEnumerator a =
224+ (Status -> ResponseHeaders -> Iteratee Builder IO a) -> IO a
225+
226+responseEnumerator :: Response -> ResponseEnumerator a
227+responseEnumerator (ResponseEnumerator e) f = e f
228+responseEnumerator (ResponseFile s h fp) f =
229+ run_ $ enumFile fp $$ joinI $ E.map fromByteString $$ f s h
230+responseEnumerator (ResponseLBS s h lbs) f =
231+ run_ $ enumList 1 [fromLazyByteString lbs] $$ f s h
237232
238233type Application = Request -> IO Response
239234