@@ -1,6 +1,4 @@
11{-# LANGUAGE Rank2Types #-}
2−{-# LANGUAGE ExistentialQuantification #-}
3−{-# LANGUAGE DeriveDataTypeable #-}
42{-|
53
64This module defines a generic web application interface. It is a common
@@ -37,108 +35,57 @@ include:
3735-}
3836module Network.Wai
3937 ( -- * WAI interface
40− Request (..)
41− , Response (..)
38+ -- ** Request
39+ Request
40+ , requestMethod
41+ , httpVersion
42+ , rawPathInfo
43+ , rawQueryString
44+ , requestHeaders
45+ , isSecure
46+ , remoteHost
47+ , pathInfo
48+ , queryString
49+ , requestBody
50+ , vault
51+ , requestBodyLength
52+ , resourceInternalState
53+ -- ** Response
54+ , Response
55+ , responseFile
56+ , responseBuilder
4257 , responseSource
58+ , responseLBS
59+ -- ** Other types
4360 , Application
4461 , Middleware
4562 , FilePart (..)
4663 , RequestBodyLength (..)
47− -- * Response body smart constructors
48− , responseLBS
64+ -- ** Helper functions
65+ , responseToSource
4966 , responseStatus
5067 ) where
5168
52−import qualified Data.ByteString as B
53−import qualified Data.ByteString.Lazy as L
54−import Data.Typeable (Typeable)
55−import qualified Data.Conduit as C
56−import qualified Data.Conduit.List as CL
57−import qualified Data.Conduit.Binary as CB
58−import Blaze.ByteString.Builder (Builder, fromLazyByteString)
59−import Network.Socket (SockAddr)
60−import qualified Network.HTTP.Types as H
61−import Data.Text (Text)
62−import Data.ByteString.Lazy.Char8 () -- makes it easier to use responseLBS
63−import Blaze.ByteString.Builder (fromByteString)
64−import Data.Vault (Vault)
65−import Data.Word (Word64)
69+import Blaze.ByteString.Builder (Builder, fromLazyByteString)
70+import Blaze.ByteString.Builder (fromByteString)
6671import qualified Control.Monad.Trans.Resource as Res
72+import qualified Data.ByteString as B
73+import qualified Data.ByteString.Lazy as L
74+import Data.ByteString.Lazy.Char8 ()
75+import qualified Data.Conduit as C
76+import qualified Data.Conduit.Binary as CB
77+import qualified Data.Conduit.List as CL
78+import qualified Network.HTTP.Types as H
79+import Network.Wai.Internal
6780
68−-- | Information on the request sent by the client. This abstracts away the
69−-- details of the underlying implementation.
70−data Request = Request
71− { requestMethod :: H.Method
72− , httpVersion :: H.HttpVersion
73− -- | Extra path information sent by the client. The meaning varies slightly
74− -- depending on backend; in a standalone server setting, this is most likely
75− -- all information after the domain name. In a CGI application, this would be
76− -- the information following the path to the CGI executable itself.
77− -- Do not modify this raw value- modify pathInfo instead.
78− , rawPathInfo :: B.ByteString
79− -- | If no query string was specified, this should be empty. This value
80− -- /will/ include the leading question mark.
81− -- Do not modify this raw value- modify queryString instead.
82− , rawQueryString :: B.ByteString
83− , requestHeaders :: H.RequestHeaders
84− -- | Was this request made over an SSL connection?
85− --
86− -- Note that this value will /not/ tell you if the client originally made
87− -- this request over SSL, but rather whether the current connection is SSL.
88− -- The distinction lies with reverse proxies. In many cases, the client will
89− -- connect to a load balancer over SSL, but connect to the WAI handler
90− -- without SSL. In such a case, @isSecure@ will be @False@, but from a user
91− -- perspective, there is a secure connection.
92− , isSecure :: Bool
93− -- | The client\'s host information.
94− , remoteHost :: SockAddr
95− -- | Path info in individual pieces- the url without a hostname/port and without a query string, split on forward slashes,
96− , pathInfo :: [Text]
97− -- | Parsed query string information
98− , queryString :: H.Query
99− , requestBody :: C.Source IO B.ByteString
100− -- | A location for arbitrary data to be shared by applications and middleware.
101− , vault :: Vault
102− -- | The size of the request body. In the case of a chunked request body, this may be unknown.
103− --
104− -- Since 1.4.0
105− , requestBodyLength :: RequestBodyLength
106− -- | The internal @ResourceT@ state, used for allocating scarce resources
107− -- will in an application.
108− --
109− -- Since 1.5.0
110− , resourceInternalState :: Res.InternalState
111− }
112− deriving (Typeable)
113−
114−-- |
115−--
116−-- Some questions and answers about the usage of 'Builder' here:
117−--
118−-- Q1. Shouldn't it be at the user's discretion to use Builders internally and
119−-- then create a stream of ByteStrings?
120−--
121−-- A1. That would be less efficient, as we wouldn't get cheap concatenation
122−-- with the response headers.
123−--
124−-- Q2. Isn't it really inefficient to convert from ByteString to Builder, and
125−-- then right back to ByteString?
126−--
127−-- A2. No. If the ByteStrings are small, then they will be copied into a larger
128−-- buffer, which should be a performance gain overall (less system calls). If
129−-- they are already large, then blaze-builder uses an InsertByteString
130−-- instruction to avoid copying.
131−--
132−-- Q3. Doesn't this prevent us from creating comet-style servers, since data
133−-- will be cached?
134−--
135−-- A3. You can force blaze-builder to output a ByteString before it is an
136−-- optimal size by sending a flush command.
137−data Response
138− = ResponseFile H.Status H.ResponseHeaders FilePath (Maybe FilePart)
139− | ResponseBuilder H.Status H.ResponseHeaders Builder
140− | ResponseSource H.Status H.ResponseHeaders (C.Source IO (C.Flush Builder))
141− deriving Typeable
81+responseFile :: H.Status -> H.ResponseHeaders -> FilePath -> Maybe FilePart -> Response
82+responseFile = ResponseFile
83+
84+responseBuilder :: H.Status -> H.ResponseHeaders -> Builder -> Response
85+responseBuilder = ResponseBuilder
86+
87+responseSource :: H.Status -> H.ResponseHeaders -> C.Source IO (C.Flush Builder) -> Response
88+responseSource = ResponseSource
14289
14390responseStatus :: Response -> H.Status
14491responseStatus rsp =
@@ -147,24 +94,19 @@ responseStatus rsp =
14794 ResponseBuilder s _ _ -> s
14895 ResponseSource s _ _ -> s
14996
150−data FilePart = FilePart
151− { filePartOffset :: Integer
152− , filePartByteCount :: Integer
153− } deriving Show
154−
155−responseSource :: Request
97+responseToSource :: Request
15698 -> Response
15799 -> (H.Status, H.ResponseHeaders, C.Source IO (C.Flush Builder))
158−responseSource _ (ResponseSource s h b) = (s, h, b)
159−responseSource req (ResponseFile s h fp (Just part)) =
100+responseToSource _ (ResponseSource s h b) = (s, h, b)
101+responseToSource req (ResponseFile s h fp (Just part)) =
160102 (s, h, transRes (sourceFilePart part fp) C.$= CL.map (C.Chunk . fromByteString))
161103 where
162104 transRes = C.transPipe (flip Res.runInternalState (resourceInternalState req))
163−responseSource req (ResponseFile s h fp Nothing) =
105+responseToSource req (ResponseFile s h fp Nothing) =
164106 (s, h, transRes (CB.sourceFile fp) C.$= CL.map (C.Chunk . fromByteString))
165107 where
166108 transRes = C.transPipe (flip Res.runInternalState (resourceInternalState req))
167−responseSource _ (ResponseBuilder s h b) =
109+responseToSource _ (ResponseBuilder s h b) =
168110 (s, h, CL.sourceList [C.Chunk b])
169111
170112sourceFilePart :: C.MonadResource m => FilePart -> FilePath -> C.Source m B.ByteString
@@ -191,9 +133,3 @@ type Application = Request -> IO Response
191133-- Here, instead of taking a standard 'Application' as its first argument, the
192134-- middleware takes a function which consumes the session information as well.
193135type Middleware = Application -> Application
194−
195−-- | The size of the request body. In the case of chunked bodies, the size will
196−-- not be known.
197−--
198−-- Since 1.4.0
199−data RequestBodyLength = ChunkedBody | KnownLength Word64