on master help sign in
Documenation cleanup
56333a4Michael Snoyman
Network/Wai.hs+65−47
@@ -5,10 +5,10 @@
5This module defines a generic web application interface. It is a common
5This module defines a generic web application interface. It is a common
6protocol between web servers and web applications.
6protocol between web servers and web applications.
7
7
8−The overriding design principles here are performance, generality and type
8+The overriding design principles here are performance and generality . To
9−safety. To address performance, this library is built on 'Source' for the
9+address performance, this library is built on 'Source' for the request body and
10−request body and 'Enumerator' for the response bodies. The advantages of this
10+'Enumerator' for the response bodies. The advantages of this approach over lazy
11−approach over lazy IO have been debated elsewhere.
11+IO have been debated elsewhere.
12
12
13Nonetheless, many people find these data structures difficult to work with. For
13Nonetheless, many people find these data structures difficult to work with. For
14that reason, this library includes the "Network.Wai.Enumerator" module to
14that reason, this library includes the "Network.Wai.Enumerator" module to
@@ -18,11 +18,8 @@ Generality is achieved by removing many variables commonly found in similar
18projects that are not universal to all servers. The goal is that the 'Request'
18projects that are not universal to all servers. The goal is that the 'Request'
19object contains only data which is meaningful in all circumstances.
19object contains only data which is meaningful in all circumstances.
20
20
21−Unlike other approaches, this package declares many data types to assist in
22−type safety. This feels more inline with the general Haskell spirit.
23−
24A final note: please remember when using this package that, while your
21A final note: please remember when using this package that, while your
25−application my compile without a hitch against many different servers, there
22+application may compile without a hitch against many different servers, there
26are other considerations to be taken when moving to a new backend. For example,
23are other considerations to be taken when moving to a new backend. For example,
27if you transfer from a CGI application to a FastCGI one, you might suddenly
24if you transfer from a CGI application to a FastCGI one, you might suddenly
28find you have a memory leak. Conversely, a FastCGI application would be
25find you have a memory leak. Conversely, a FastCGI application would be
@@ -33,7 +30,6 @@ would kill the performance of a CGI application.
33module Network.Wai
30module Network.Wai
34 ( -- * Data types
31 ( -- * Data types
35
32
36− -- $show_read
37 -- ** Request method
33 -- ** Request method
38 Method
34 Method
39 -- ** HTTP protocol versions
35 -- ** HTTP protocol versions
@@ -79,37 +75,42 @@ import qualified Data.ByteString.Lazy as L
79import Data.Char (toLower)
75import Data.Char (toLower)
80import Data.String (IsString (..))
76import Data.String (IsString (..))
81
77
82−-- $show_read
78+-- | HTTP request method. Since the HTTP protocol allows arbitrary request
83−--
79+-- methods, we leave this open as a 'B.ByteString'. Please note the request
84−-- For the data types below, you should only use the 'Show' and 'Read'
85−-- instances for debugging purposes. Each datatype (excepting 'UrlScheme') has
86−-- associated functions for converting to and from strict 'B.ByteString's;
87−-- these are approrpiate for generating content.
88−
89−-- | HTTP request method. This data type is extensible via the Method
90−-- constructor. Request methods are case-sensitive, and comparison is achieved
80+-- methods are case-sensitive.
91−-- by converting to a 'B.ByteString' via 'methodToBS'.
92type Method = B.ByteString
81type Method = B.ByteString
93
82
94−-- | Version of HTTP protocol used in current request. This data type is
83+-- | Version of HTTP protocol used in current request. The value given here
95−-- extensible via the HttpVersion constructor. Comparison is achieved by
84+-- should be everything following the \"HTTP/\" line in a request. In other
96−-- converting to a 'B.ByteString' via 'httpVersionToBS'.
85+-- words, HTTP\/1.1 -> \"1.1\", HTTP\/1.0 -> \"1.0\".
97type HttpVersion = B.ByteString
86type HttpVersion = B.ByteString
98
87
88+-- | HTTP/0.9
99http09 :: HttpVersion
89http09 :: HttpVersion
100http09 = B8.pack "0.9"
90http09 = B8.pack "0.9"
101
91
92+-- | HTTP/1.0
102http10 :: HttpVersion
93http10 :: HttpVersion
103http10 = B8.pack "1.0"
94http10 = B8.pack "1.0"
104
95
96+-- | HTTP/1.1
105http11 :: HttpVersion
97http11 :: HttpVersion
106http11 = B8.pack "1.1"
98http11 = B8.pack "1.1"
107
99
100+-- | A case insensitive bytestring, where the 'Eq' and 'Ord' instances do
101+-- comparisons based on the lower-cased version of this string. For efficiency,
102+-- this datatype contains both the original and lower-case version of the
103+-- string; this means there is no need to lower-case the bytestring for every
104+-- comparison.
105+--
106+-- Please note that this datatype has an 'IsString' instance, which can allow
107+-- for very concise code when using the OverloadedStrings language extension.
108data CIByteString = CIByteString
108data CIByteString = CIByteString
109 { ciOriginal :: !B.ByteString
109 { ciOriginal :: !B.ByteString
110 , ciLowerCase :: !B.ByteString
110 , ciLowerCase :: !B.ByteString
111 }
111 }
112
112
113+-- | Convert a regular bytestring to a case-insensitive bytestring.
113mkCIByteString :: B.ByteString -> CIByteString
114mkCIByteString :: B.ByteString -> CIByteString
114mkCIByteString bs = CIByteString bs $ B8.map toLower bs
115mkCIByteString bs = CIByteString bs $ B8.map toLower bs
115
116
@@ -122,68 +123,59 @@ instance Ord CIByteString where
122instance IsString CIByteString where
123instance IsString CIByteString where
123 fromString = mkCIByteString . fromString
124 fromString = mkCIByteString . fromString
124
125
125−-- | Headers sent from the client to the server. Clearly, this is not a
126+-- | Headers sent from the client to the server. Note that this is a
126−-- complete list of all possible headers, but rather a selection of common
127+-- case-insensitive string, as the HTTP spec specifies.
127−-- ones. If other headers are required, they can be created with the
128−-- RequestHeader constructor.
129−--
130−-- The naming rules are simple: removing any hyphens from the actual name, and
131−-- if there is a naming conflict with a 'ResponseHeader', prefix with Req.
132−--
133−-- Equality determined by conversion via 'requestHeaderToLower'. Request
134−-- headers are *not* case sensitive (a change from version 0.0 of WAI).
135type RequestHeader = CIByteString
128type RequestHeader = CIByteString
136
129
137−-- | Headers sent from the server to the client. Clearly, this is not a
130+-- | Headers sent from the server to the client. Note that this is a
138−-- complete list of all possible headers, but rather a selection of common
131+-- case-insensitive string, as the HTTP spec specifies.
139−-- ones. If other headers are required, they can be created with the
140−-- ResponseHeader constructor.
141−--
142−-- if there is a naming conflict with a 'ResponseHeader', prefix with Req.
143−--
144−-- Equality determined by conversion via 'responseHeaderToLower'. Response
145−-- headers are *not* case sensitive (a change from version 0.0 of WAI).
146type ResponseHeader = CIByteString
132type ResponseHeader = CIByteString
147
133
148−-- | This attempts to provide the most common HTTP status codes, not all of
134+-- | HTTP status code; a combination of the integral code and a status message.
149−-- them. Use the Status constructor when you want to create a status code not
135+-- Equality is determined solely on the basis of the integral code.
150−-- provided.
151−--
152−-- The 'Eq' instance tests equality based only on the numeric status code
153−-- value. See 'statusCode'.
154data Status = Status { statusCode :: Int, statusMessage :: B.ByteString }
136data Status = Status { statusCode :: Int, statusMessage :: B.ByteString }
155 deriving Show
137 deriving Show
156
138
157instance Eq Status where
139instance Eq Status where
158 x == y = statusCode x == statusCode y
140 x == y = statusCode x == statusCode y
159
141
142+-- | OK
160status200 :: Status
143status200 :: Status
161status200 = Status 200 $ B8.pack "OK"
144status200 = Status 200 $ B8.pack "OK"
162
145
146+-- | Moved Permanently
163status301 :: Status
147status301 :: Status
164status301 = Status 301 $ B8.pack "Moved Permanently"
148status301 = Status 301 $ B8.pack "Moved Permanently"
165
149
150+-- | Found
166status302 :: Status
151status302 :: Status
167status302 = Status 302 $ B8.pack "Found"
152status302 = Status 302 $ B8.pack "Found"
168
153
154+-- | See Other
169status303 :: Status
155status303 :: Status
170status303 = Status 303 $ B8.pack "See Other"
156status303 = Status 303 $ B8.pack "See Other"
171
157
158+-- | Bad Request
172status400 :: Status
159status400 :: Status
173status400 = Status 400 $ B8.pack "Bad Request"
160status400 = Status 400 $ B8.pack "Bad Request"
174
161
162+-- | Unauthorized
175status401 :: Status
163status401 :: Status
176status401 = Status 401 $ B8.pack "Unauthorized"
164status401 = Status 401 $ B8.pack "Unauthorized"
177
165
166+-- | Forbidden
178status403 :: Status
167status403 :: Status
179status403 = Status 403 $ B8.pack "Forbidden"
168status403 = Status 403 $ B8.pack "Forbidden"
180
169
170+-- | Not Found
181status404 :: Status
171status404 :: Status
182status404 = Status 404 $ B8.pack "Not Found"
172status404 = Status 404 $ B8.pack "Not Found"
183
173
174+-- | Method Not Allowed
184status405 :: Status
175status405 :: Status
185status405 = Status 405 $ B8.pack "Method Not Allowed"
176status405 = Status 405 $ B8.pack "Method Not Allowed"
186
177
178+-- | Internal Server Error
187status500 :: Status
179status500 :: Status
188status500 = Status 500 $ B8.pack "Internal Server Error"
180status500 = Status 500 $ B8.pack "Internal Server Error"
189
181
@@ -194,6 +186,12 @@ status500 = Status 500 $ B8.pack "Internal Server Error"
194--
186--
195-- Be certain not to reuse a 'Source'! It might work fine with some
187-- Be certain not to reuse a 'Source'! It might work fine with some
196-- implementations of 'Source', while causing bugs with others.
188-- implementations of 'Source', while causing bugs with others.
189+--
190+-- This datatype is used by WAI to represent a request body. We choose this
191+-- over an enumerator in that it gives the application power over control flow.
192+-- This not only makes it easier to use in many situations, but also allows
193+-- implementation of some features such as a backtracking parser which doesn't
194+-- read the entire body into memory.
197newtype Source = Source { runSource :: IO (Maybe (B.ByteString, Source)) }
195newtype Source = Source { runSource :: IO (Maybe (B.ByteString, Source)) }
198
196
199-- | An enumerator is a data producer. It takes two arguments: a function to
197-- | An enumerator is a data producer. It takes two arguments: a function to
@@ -225,6 +223,10 @@ newtype Source = Source { runSource :: IO (Maybe (B.ByteString, Source)) }
225-- 'Enumerator' may only be called once. While this requirement puts a bit of a
223-- 'Enumerator' may only be called once. While this requirement puts a bit of a
226-- strain on the caller in some situations, it saves a large amount of
224-- strain on the caller in some situations, it saves a large amount of
227-- complication- and thus performance- on the producer.
225-- complication- and thus performance- on the producer.
226+--
227+-- In WAI, an Enumerator is used to represent the response body. We have
228+-- specifically chosen one of the simplest representations of an enumerator to
229+-- avoid coding complication and performance overhead.
228newtype Enumerator = Enumerator { runEnumerator :: forall a.
230newtype Enumerator = Enumerator { runEnumerator :: forall a.
229 (a -> B.ByteString -> IO (Either a a))
231 (a -> B.ByteString -> IO (Either a a))
230 -> a
232 -> a
@@ -246,13 +248,29 @@ data Request = Request
246 , serverName :: B.ByteString
248 , serverName :: B.ByteString
247 , serverPort :: Int
249 , serverPort :: Int
248 , requestHeaders :: [(RequestHeader, B.ByteString)]
250 , requestHeaders :: [(RequestHeader, B.ByteString)]
251+ -- ^ Was this request made over an SSL connection?
249 , isSecure :: Bool
252 , isSecure :: Bool
250 , requestBody :: Source
253 , requestBody :: Source
254+ -- ^ Log the given line in some method; how this is accomplished is
255+ -- server-dependant.
251 , errorHandler :: String -> IO ()
256 , errorHandler :: String -> IO ()
252 -- | The client\'s host information.
257 -- | The client\'s host information.
253 , remoteHost :: B.ByteString
258 , remoteHost :: B.ByteString
254 }
259 }
255
260
261+-- | The response body returned to the server from the application. We provide
262+-- three separate constructors as optimizations:
263+--
264+-- * 'ResponseEnumerator' is the most general type, allowing constant-memory
265+-- production of a response, even in the presence of interleaved I\/O actions.
266+--
267+-- * 'ResponseFile' serves a static file from the filesystem. Many servers use
268+-- a sendfile system call to optimize this type of serving, making this a huge
269+-- performance gain.
270+--
271+-- * 'ResponseLBS'. Often times, we wish to return a response that includes no
272+-- interleaved I\/O. In this case, we can use Haskell's natural laziness to our
273+-- advantage, and represent the response as a lazy bytestring.
256data ResponseBody = ResponseFile FilePath
274data ResponseBody = ResponseFile FilePath
257 | ResponseEnumerator Enumerator
275 | ResponseEnumerator Enumerator
258 | ResponseLBS L.ByteString
276 | ResponseLBS L.ByteString