snap-core-0.2.16: Snap: A Haskell Web Framework (Core)ContentsIndex
Snap.Types
Contents
The Snap Monad
Functions for control flow and early termination
Routing
Access to state
Logging
Grabbing/transforming request bodies
HTTP Datatypes and Functions
Headers
Requests
Responses
Response I/O
Iteratee
HTTP utilities
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.
Synopsis
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
= GET
| HEAD
| POST
| PUT
| DELETE
| TRACE
| OPTIONS
| CONNECT
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:

1. stateful access to fetch or modify an HTTP Request

2. stateful access to fetch or modify an HTTP Response

3. failure / Alternative / MonadPlus semantics: a Snap handler can choose not to handle a given request, using empty or its synonym pass, 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

4. convenience functions (writeBS, writeLBS, writeText, writeLazyText, addToOutput) for writing output to the Response:

 a :: (forall a . Enumerator a) -> Snap ()
 a someEnumerator = do
     writeBS "I'm a strict bytestring"
     writeLBS "I'm a lazy bytestring"
     addToOutput someEnumerator

5. 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.

6. access to the IO monad through a MonadIO instance:

 a :: Snap ()
 a = liftIO fireTheMissiles
show/hide Instances
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
show/hide Instances
Functions for control flow and early termination
finishWith :: Response -> Snap a
Short-circuits a Snap monad action early, storing the given Response value in its state.
pass :: 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.
path
:: ByteStringpath to match against
-> Snap ahandler 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.
dir
:: ByteStringpath component to match
-> Snap ahandler 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.

ifTop :: Snap a -> Snap a
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
getRequest :: Snap Request
Grabs the Request object out of the Snap monad.
getResponse :: Snap Response
Grabs the Response object out of the Snap monad.
putRequest :: Request -> Snap ()
Puts a new Request object into the Snap monad.
putResponse :: Response -> Snap ()
Puts a new Response object into the Snap monad.
modifyRequest :: (Request -> Request) -> Snap ()
Modifies the Request object stored in a Snap monad.
modifyResponse :: (Response -> Response) -> Snap ()
Modifes the Response object stored in a Snap monad.
localRequest :: (Request -> Request) -> Snap a -> Snap a
Runs a Snap action with a locally-modified Request state object. The Request object in the Snap monad state after the call to localRequest will be unchanged.
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.
transformRequestBody
:: (forall a. Enumerator a)the output Iteratee is passed to this Enumerator, and then the resulting Iteratee is fed the request body stream. Your Enumerator is responsible for transforming the input.
-> 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
HTTP-related datatypes: Request, Response, Cookie, etc.
data Request
Contains all of the information about an incoming HTTP request.
show/hide Instances
data Response
Represents an HTTP response.
show/hide Instances
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.
headers :: a -> Headers
Retrieve the headers from a datatype that has headers.
show/hide 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&param=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).
Constructors
GET
HEAD
POST
PUT
DELETE
TRACE
OPTIONS
CONNECT
show/hide Instances
data Cookie
A datatype representing an HTTP cookie.
Constructors
Cookie
cookieName :: !ByteStringThe name of the cookie.
cookieValue :: !ByteStringThe cookie's string value.
cookieExpires :: !(Maybe UTCTime)The cookie's expiration value, if it has one.
cookieDomain :: !(Maybe ByteString)The cookie's "domain" value, if it has one.
cookiePath :: !(Maybe ByteString)The cookie path.
show/hide Instances
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.
rqMethod :: Request -> Method
Returns the HTTP request method.
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.
rqParams :: Request -> Params
Returns the Params mapping for this Request. "Parameters" are automatically decoded from the query string and POST body and entered into this mapping.
rqParam
:: ByteStringparameter name to look up
-> RequestHTTP 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.
getParam
:: ByteStringparameter 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.
rqSetParam
:: ByteStringparameter name
-> [ByteString]parameter values
-> Requestrequest
-> Request
Writes a key-value pair to the parameters mapping within the given request.
Responses
emptyResponse :: Response
An empty Response.
setResponseCode
:: IntHTTP response integer code
-> ResponseResponse to be modified
-> Response
Sets the HTTP response code.
setResponseStatus
:: IntHTTP response integer code
-> ByteStringHTTP response explanation
-> ResponseResponse to be modified
-> Response
Sets the HTTP response status. Note: normally you would use setResponseCode unless you needed a custom response explanation.
rspStatus :: Response -> Int
Returns the HTTP status code.
rspStatusReason :: Response -> ByteString
Returns the HTTP status explanation string.
setContentType :: ByteString -> Response -> Response
Sets the Content-Type in the Response headers.
addCookie
:: Cookiecookie value
-> Responseresponse to modify
-> Response
Adds an HTTP Cookie to 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 ()
Performs a redirect by setting the Location header to the given target URL/path and the status code to 302 in the Response object stored in a Snap monad. Note that the target URL is not validated in any way. Consider using 'redirect\'' instead, which allows you to choose the correct status code.
redirect' :: ByteString -> Int -> Snap ()
Performs a redirect by setting the Location header to the given target URL/path and the status code (should be one of 301, 302, 303 or 307) in the Response object stored in a Snap monad. Note that the target URL is not validated in any way.
Response I/O
setResponseBody
:: (forall a. Enumerator a)new response body enumerator
-> Responseresponse 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.
addToOutput
:: (forall a. Enumerator a)output to add
-> Snap ()
Adds the output from the given enumerator to the Response stored in the Snap monad state.
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.

writeText :: Text -> Snap ()

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)
Produced by Haddock version 2.7.2