Snap.Types
Contents
Description
This module contains the core type definitions, class instances, and functions
for HTTP as well as the Snap
monad, which is used for web handlers.
- data Snap a
- runSnap :: Snap a -> (ByteString -> IO ()) -> Request -> Iteratee IO (Request, Response)
- data NoHandlerException = NoHandlerException
- finishWith :: Response -> Snap a
- pass :: Snap a
- method :: Method -> Snap a -> Snap a
- path :: ByteString -> Snap a -> Snap a
- dir :: ByteString -> Snap a -> Snap a
- ifTop :: Snap a -> Snap a
- route :: [(ByteString, Snap a)] -> Snap a
- routeLocal :: [(ByteString, Snap a)] -> Snap a
- getRequest :: Snap Request
- getResponse :: Snap Response
- putRequest :: Request -> Snap ()
- putResponse :: Response -> Snap ()
- modifyRequest :: (Request -> Request) -> Snap ()
- modifyResponse :: (Response -> Response) -> Snap ()
- localRequest :: (Request -> Request) -> Snap a -> Snap a
- withRequest :: (Request -> Snap a) -> Snap a
- withResponse :: (Response -> Snap a) -> Snap a
- logError :: ByteString -> Snap ()
- runRequestBody :: Iteratee IO a -> Snap a
- getRequestBody :: Snap ByteString
- transformRequestBody :: (forall a. Enumerator a) -> Snap ()
- data Request
- data Response
- type Headers = Map CIByteString [ByteString]
- class HasHeaders a where
- updateHeaders :: (Headers -> Headers) -> a -> a
- headers :: a -> Headers
- type Params = Map ByteString [ByteString]
- data Method
- data Cookie = Cookie {
- cookieName :: !ByteString
- cookieValue :: !ByteString
- cookieExpires :: !(Maybe UTCTime)
- cookieDomain :: !(Maybe ByteString)
- cookiePath :: !(Maybe ByteString)
- type HttpVersion = (Int, Int)
- addHeader :: HasHeaders a => CIByteString -> ByteString -> a -> a
- setHeader :: HasHeaders a => CIByteString -> ByteString -> a -> a
- getHeader :: HasHeaders a => CIByteString -> a -> Maybe ByteString
- deleteHeader :: HasHeaders a => CIByteString -> a -> a
- ipHeaderFilter :: Snap ()
- ipHeaderFilter' :: CIByteString -> Snap ()
- rqServerName :: Request -> ByteString
- rqServerPort :: Request -> Int
- rqRemoteAddr :: Request -> ByteString
- rqRemotePort :: Request -> Int
- rqLocalAddr :: Request -> ByteString
- rqLocalHostname :: Request -> ByteString
- rqIsSecure :: Request -> Bool
- rqContentLength :: Request -> Maybe Int
- rqMethod :: Request -> Method
- rqVersion :: Request -> HttpVersion
- rqCookies :: Request -> [Cookie]
- rqPathInfo :: Request -> ByteString
- rqContextPath :: Request -> ByteString
- rqURI :: Request -> ByteString
- rqQueryString :: Request -> ByteString
- rqParams :: Request -> Params
- rqParam :: ByteString -> Request -> Maybe [ByteString]
- getParam :: ByteString -> Snap (Maybe ByteString)
- rqModifyParams :: (Params -> Params) -> Request -> Request
- rqSetParam :: ByteString -> [ByteString] -> Request -> Request
- emptyResponse :: Response
- setResponseCode :: Int -> Response -> Response
- setResponseStatus :: Int -> ByteString -> Response -> Response
- rspStatus :: Response -> Int
- rspStatusReason :: Response -> ByteString
- setContentType :: ByteString -> Response -> Response
- addCookie :: Cookie -> Response -> Response
- setContentLength :: Int64 -> Response -> Response
- clearContentLength :: Response -> Response
- redirect :: ByteString -> Snap ()
- redirect' :: ByteString -> Int -> Snap ()
- setResponseBody :: (forall a. Enumerator a) -> Response -> Response
- modifyResponseBody :: (forall a. Enumerator a -> Enumerator a) -> Response -> Response
- addToOutput :: (forall a. Enumerator a) -> Snap ()
- writeBS :: ByteString -> Snap ()
- writeLazyText :: Text -> Snap ()
- writeText :: Text -> Snap ()
- writeLBS :: ByteString -> Snap ()
- sendFile :: FilePath -> Snap ()
- sendFilePartial :: FilePath -> (Int64, Int64) -> Snap ()
- type Enumerator a = Enumerator IO a
- data SomeEnumerator = SomeEnumerator (forall a. Enumerator a)
- formatHttpTime :: CTime -> IO ByteString
- parseHttpTime :: ByteString -> IO CTime
- urlEncode :: ByteString -> ByteString
- urlDecode :: ByteString -> Maybe ByteString
The Snap Monad
data Snap a
Snap
is the Monad
that user web handlers run in. Snap
gives you:
- stateful access to fetch or modify an HTTP
Request
- stateful access to fetch or modify an HTTP
Response
- failure /
Alternative
/MonadPlus
semantics: aSnap
handler can choose not to handle a given request, usingempty
or its synonympass
, and you can try alternative handlers with the<|>
operator:
a :: Snap String a = pass b :: Snap String b = return "foo" c :: Snap String c = a <|> b -- try running a, if it fails then try b
- convenience functions (
writeBS
,writeLBS
,writeText
,writeLazyText
,addToOutput
) for writing output to theResponse
:
a :: (forall a . Enumerator a) -> Snap () a someEnumerator = do writeBS "I'm a strict bytestring" writeLBS "I'm a lazy bytestring" addToOutput someEnumerator
- early termination: if you call
finishWith
:
a :: Snap () a = do modifyResponse $ setResponseStatus 500 "Internal Server Error" writeBS "500 error" r <- getResponse finishWith r
then any subsequent processing will be skipped and supplied Response
value
will be returned from runSnap
as-is.
a :: Snap () a = liftIO fireTheMissiles
runSnap :: Snap a -> (ByteString -> IO ()) -> Request -> Iteratee IO (Request, Response)
Runs a Snap
monad action in the 'Iteratee IO' monad.
data NoHandlerException
This exception is thrown if the handler you supply to runSnap
fails.
Constructors
NoHandlerException |
Functions for control flow and early termination
finishWith :: Response -> Snap a
Fails out of a Snap
monad action. This is used to indicate
that you choose not to handle the given request within the given
handler.
Routing
method :: Method -> Snap a -> Snap a
Runs a Snap
monad action only if the request's HTTP method matches
the given method.
Arguments
:: ByteString | path to match against |
-> Snap a | handler to run |
-> Snap a |
Runs a Snap
monad action only for requests where rqPathInfo
is exactly
equal to the given string. If the path matches, locally sets rqContextPath
to the old value of rqPathInfo
, sets rqPathInfo
="", and runs the given
handler.
Arguments
:: ByteString | path component to match |
-> Snap a | handler to run |
-> Snap a |
Runs a Snap
monad action only when the rqPathInfo
of the request
starts with the given path. For example,
dir "foo" handler
Will fail if rqPathInfo
is not "/foo
" or "/foo/...
", and will
add "foo/"
to the handler's local rqContextPath
.
Runs a Snap
monad action only when rqPathInfo
is empty.
route :: [(ByteString, Snap a)] -> Snap a
A web handler which, given a mapping from URL entry points to web handlers, efficiently routes requests to the correct handler.
The URL entry points are given as relative paths, for example:
route [ ("foo/bar/quux", fooBarQuux) ]
If the URI of the incoming request is
/foo/bar/quux
or
/foo/bar/quux/...anything...
then the request will be routed to "fooBarQuux
", with rqContextPath
set to "/foo/bar/quux/
" and rqPathInfo
set to
"...anything...
".
A path component within an URL entry point beginning with a colon (":
")
is treated as a variable capture; the corresponding path component within
the request URI will be entered into the rqParams
parameters mapping with
the given name. For instance, if the routes were:
route [ ("foo/:bar/baz", fooBazHandler) ]
Then a request for "/foo/saskatchewan/baz
" would be routed to
fooBazHandler
with a mapping for:
"bar" => "saskatchewan"
in its parameters table.
Longer paths are matched first, and specific routes are matched before captures. That is, if given routes:
[ ("a", h1), ("a/b", h2), ("a/:x", h3) ]
a request for "/a/b
" will go to h2
, "/a/s
" for any s will go
to h3
, and "/a
" will go to h1
.
The following example matches "/article
" to an article index,
"/login
" to a login, and "/article/...
" to an article renderer.
route [ ("article", renderIndex) , ("article/:id", renderArticle) , ("login", method POST doLogin) ]
routeLocal :: [(ByteString, Snap a)] -> Snap a
The routeLocal
function is the same as route'
, except it doesn't change
the request's context path. This is useful if you want to route to a
particular handler but you want that handler to receive the rqPathInfo
as
it is.
Access to state
modifyResponse :: (Response -> Response) -> Snap ()
localRequest :: (Request -> Request) -> Snap a -> Snap a
withRequest :: (Request -> Snap a) -> Snap a
Fetches the Request
from state and hands it to the given action.
withResponse :: (Response -> Snap a) -> Snap a
Fetches the Response
from state and hands it to the given action.
Logging
logError :: ByteString -> Snap ()
Log an error message in the Snap
monad
Grabbing/transforming request bodies
runRequestBody :: Iteratee IO a -> Snap a
Sends the request body through an iteratee (data consumer) and returns the result.
getRequestBody :: Snap ByteString
Returns the request body as a bytestring.
Arguments
:: (forall a. Enumerator a) | the output |
-> Snap () |
Normally Snap is careful to ensure that the request body is fully consumed
after your web handler runs, but before the Response
enumerator is
streamed out the socket. If you want to transform the request body into some
output in O(1) space, you should use this function.
Note that upon calling this function, response processing finishes early as
if you called finishWith
. Make sure you set any content types, headers,
cookies, etc. before you call this function.
HTTP Datatypes and Functions
type Headers = Map CIByteString [ByteString]
A type alias for a case-insensitive key-value mapping.
class HasHeaders a where
A typeclass for datatypes which contain HTTP headers.
Methods
updateHeaders :: (Headers -> Headers) -> a -> a
Modify the datatype's headers.
Retrieve the headers from a datatype that has headers.
Instances
type Params = Map ByteString [ByteString]
A type alias for the HTTP parameters mapping. Each parameter
key maps to a list of ByteString values; if a parameter is specified
multiple times (e.g.: "GET /foo?param=bar1¶m=bar2
"), looking up
"param
" in the mapping will give you ["bar1", "bar2"]
.
data Method
Enumerates the HTTP method values (see http://tools.ietf.org/html/rfc2068.html#section-5.1.1).
data Cookie
A datatype representing an HTTP cookie.
Constructors
Cookie | |
Fields
|
type HttpVersion = (Int, Int)
Headers
addHeader :: HasHeaders a => CIByteString -> ByteString -> a -> a
Adds a header key-value-pair to the HasHeaders
datatype. If a header with
the same name already exists, the new value is appended to the headers list.
setHeader :: HasHeaders a => CIByteString -> ByteString -> a -> a
Sets a header key-value-pair in a HasHeaders
datatype. If a header with
the same name already exists, it is overwritten with the new value.
getHeader :: HasHeaders a => CIByteString -> a -> Maybe ByteString
Gets a header value out of a HasHeaders
datatype. If many headers came
in with the same name, they will be catenated together.
deleteHeader :: HasHeaders a => CIByteString -> a -> a
Clears a header value from a HasHeaders
datatype.
ipHeaderFilter :: Snap ()
Modifies the Request
in the state to set the rqRemoteAddr
field to the value in the X-Forwarded-For header. If the header is
not present, this action has no effect.
This action should be used only when working behind a reverse http proxy that sets the X-Forwarded-For header. This is the only way to ensure the value in the X-Forwarded-For header can be trusted.
This is provided as a filter so actions that require the remote address can get it in a uniform manner. It has specifically limited functionality to ensure that its transformation can be trusted, when used correctly.
ipHeaderFilter' :: CIByteString -> Snap ()
Modifies the Request
in the state to set the rqRemoteAddr
field to the value from the header specified. If the header
specified is not present, this action has no effect.
This action should be used only when working behind a reverse http proxy that sets the header being looked at. This is the only way to ensure the value in the header can be trusted.
This is provided as a filter so actions that require the remote address can get it in a uniform manner. It has specifically limited functionality to ensure that its transformation can be trusted, when used correctly.
Requests
rqServerName :: Request -> ByteString
The server name of the request, as it came in from the request's
Host:
header.
rqServerPort :: Request -> Int
Returns the port number the HTTP server is listening on.
rqRemoteAddr :: Request -> ByteString
The remote IP address.
rqRemotePort :: Request -> Int
The remote TCP port number.
rqLocalAddr :: Request -> ByteString
The local IP address for this request.
rqLocalHostname :: Request -> ByteString
Returns the HTTP server's idea of its local hostname.
rqIsSecure :: Request -> Bool
Returns True
if this is an HTTPS
session (currently always
False
).
rqContentLength :: Request -> Maybe Int
Returns the Content-Length
of the HTTP request body.
rqVersion :: Request -> HttpVersion
Returns the HTTP version used by the client.
rqCookies :: Request -> [Cookie]
Returns a list of the cookies that came in from the HTTP request headers.
rqPathInfo :: Request -> ByteString
Handlers can (will be; --ed) be hung on a URI
"entry point";
this is called the "context path". If a handler is hung on the
context path "/foo/"
, and you request "/foo/bar"
, the value
of rqPathInfo
will be "bar"
.
rqContextPath :: Request -> ByteString
The "context path" of the request; catenating rqContextPath
, and
rqPathInfo
should get you back to the original rqURI
. The
rqContextPath
always begins and ends with a slash ("/"
)
character, and represents the path (relative to your
component/snaplet) you took to get to your handler.
rqURI :: Request -> ByteString
Returns the URI
requested by the client.
rqQueryString :: Request -> ByteString
Returns the HTTP query string for this Request
.
Arguments
:: ByteString | parameter name to look up |
-> Request | HTTP request |
-> Maybe [ByteString] |
Looks up the value(s) for the given named parameter. Parameters initially
come from the request's query string and any decoded POST body (if the
request's Content-Type
is application/x-www-form-urlencoded
). Parameter
values can be modified within handlers using rqModifyParams.
Arguments
:: ByteString | parameter name to look up |
-> Snap (Maybe ByteString) |
See rqParam
. Looks up a value for the given named parameter in the
Request
. If more than one value was entered for the given parameter name,
getParam
gloms the values together with:
intercalate
" "
rqModifyParams :: (Params -> Params) -> Request -> Request
Modifies the parameters mapping (which is a Map ByteString ByteString
) in
a Request
using the given function.
Arguments
:: ByteString | parameter name |
-> [ByteString] | parameter values |
-> Request | request |
-> Request |
Writes a key-value pair to the parameters mapping within the given request.
Responses
An empty Response
.
Sets the HTTP response code.
Arguments
:: Int | HTTP response integer code |
-> ByteString | HTTP response explanation |
-> Response | Response to be modified |
-> Response |
Sets the HTTP response status. Note: normally you would use
setResponseCode
unless you needed a custom response explanation.
rspStatusReason :: Response -> ByteString
Returns the HTTP status explanation string.
setContentType :: ByteString -> Response -> Response
Sets the Content-Type
in the Response
headers.
setContentLength :: Int64 -> Response -> Response
A note here: if you want to set the Content-Length
for the response,
Snap forces you to do it with this function rather than by setting it in the
headers; the Content-Length
in the headers will be ignored.
The reason for this is that Snap needs to look up the value of
Content-Length
for each request, and looking the string value up in the
headers and parsing the number out of the text will be too expensive.
If you don't set a content length in your response, HTTP keep-alive will be
disabled for HTTP/1.0 clients, forcing a Connection: close
. For HTTP/1.1
clients, Snap will switch to the chunked transfer encoding if
Content-Length
is not specified.
clearContentLength :: Response -> Response
Removes any Content-Length
set in the Response
.
redirect :: ByteString -> Snap ()
redirect' :: ByteString -> Int -> Snap ()
Response I/O
Arguments
:: (forall a. Enumerator a) | new response body enumerator |
-> Response | response to modify |
-> Response |
Sets an HTTP response body to the given Enumerator
value.
modifyResponseBody :: (forall a. Enumerator a -> Enumerator a) -> Response -> Response
Modifies a response body.
Arguments
:: (forall a. Enumerator a) | output to add |
-> Snap () |
writeBS :: ByteString -> Snap ()
Adds the given strict ByteString
to the body of the Response
stored in
the Snap
monad state.
Warning: This function is intentionally non-strict. If any pure
exceptions are raised by the expression creating the ByteString
,
the exception won't actually be raised within the Snap handler.
writeLazyText :: Text -> Snap ()
Adds the given lazy Text
to the body of the Response
stored in the
Snap
monad state.
Warning: This function is intentionally non-strict. If any pure
exceptions are raised by the expression creating the ByteString
,
the exception won't actually be raised within the Snap handler.
Adds the given strict Text
to the body of the Response
stored in the
Snap
monad state.
Warning: This function is intentionally non-strict. If any pure
exceptions are raised by the expression creating the ByteString
,
the exception won't actually be raised within the Snap handler.
writeLBS :: ByteString -> Snap ()
Adds the given lazy ByteString
to the body of the Response
stored in
the Snap
monad state.
Warning: This function is intentionally non-strict. If any pure
exceptions are raised by the expression creating the ByteString
,
the exception won't actually be raised within the Snap handler.
sendFile :: FilePath -> Snap ()
Sets the output to be the contents of the specified file.
Calling sendFile
will overwrite any output queued to be sent in the
Response
. If the response body is not modified after the call to
sendFile
, Snap will use the efficient sendfile()
system call on
platforms that support it.
If the response body is modified (using modifyResponseBody
), the file will
be read using mmap()
.
sendFilePartial :: FilePath -> (Int64, Int64) -> Snap ()
Sets the output to be the contents of the specified file, within the given (start,end) range.
Calling sendFilePartial
will overwrite any output queued to be sent in the
Response
. If the response body is not modified after the call to
sendFilePartial
, Snap will use the efficient sendfile()
system call on
platforms that support it.
If the response body is modified (using modifyResponseBody
), the file will
be read using mmap()
.
Iteratee
type Enumerator a = Enumerator IO a
data SomeEnumerator
An existential wrapper for the Enumerator
type
Constructors
SomeEnumerator (forall a. Enumerator a) |
HTTP utilities
formatHttpTime :: CTime -> IO ByteString
Converts a CTime
into an HTTP timestamp.
parseHttpTime :: ByteString -> IO CTime
Converts an HTTP timestamp into a CTime
.
urlEncode :: ByteString -> ByteString
URL-escapes a string (see http://tools.ietf.org/html/rfc2396.html#section-2.4)
urlDecode :: ByteString -> Maybe ByteString
Decodes an URL-escaped string (see http://tools.ietf.org/html/rfc2396.html#section-2.4)