-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/

-- | Snap: A Haskell Web Framework (core interfaces and types)
--   
--   Snap is a simple and fast web development framework and server written
--   in Haskell. For more information or to download the latest version,
--   you can visit the Snap project website at
--   http://snapframework.com/.
--   
--   This library contains the core definitions and types for the Snap
--   framework, including:
--   
--   
--   
- Primitive types and functions for HTTP (requests, responses,
--   cookies, post/query parameters, etc)
--   
- A monad for programming web handlers called "Snap", which
--   allows:
--   
--   
--   
--   
- Stateful access to the HTTP request and response objects
--   
- Monadic failure (i.e. MonadPlus/Alternative instances) for
--   declining to handle requests and chaining handlers together
--   
- Early termination of the computation if you know early what you
--   want to return and want to prevent further monadic processing
--   
--   
--   Quick start: The Snap monad and HTTP definitions are in
--   Snap.Core.
@package snap-core
@version 1.0.5.1

-- | An internal Snap module for (optionally) printing debugging messages.
--   To enable debug output, compile the library with the debug
--   flag (off by default) and set the environment variable DEBUG
--   to 1. We use unsafePerformIO to make sure that the
--   call to getEnv is only made once.
--   
--   N.B. this is an internal interface, please don't write external
--   code that depends on it.
module Snap.Internal.Debug

-- | Print out the provided debug message prefixed by the thread ID.
--   
--   Example:
--   
--   
--   ghci> debug "Some debug message"
--   [     225] Some debug message
--   
debug :: MonadIO m => String -> m ()

-- | Print out the error message corresponding to the Errno value
--   returned by getErrno together with any additional information
--   provided by the user (usually the location where the error occurred).
--   
--   Example:
--   
--   
--   ghci> debugErrno "pathtoSource.hs:34"
--   [     323] pathtoSource.hs:34: failed (Success)
--   
debugErrno :: MonadIO m => String -> m ()

-- | An opaque data type for HTTP headers. Intended to be imported
--   qualified, i.e:
--   
--   
--   import           Snap.Types.Headers (Headers)
--   import qualified Snap.Types.Headers as H
--   
--   foo :: Headers
--   foo = H.empty
--   
module Snap.Types.Headers

-- | A key-value map that represents a collection of HTTP header fields.
--   Keys are case-insensitive.
data Headers

-- | An empty collection of HTTP header fields.
--   
--   Example:
--   
--   
--   ghci> H.empty
--   H {unH = []}
--   
empty :: Headers

-- | Is a given collection of HTTP header fields empty?
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> H.null H.empty
--   True
--   ghci> H.null $ H.fromList [("Host", "localhost")]
--   False
--   
null :: Headers -> Bool

-- | Does this collection of HTTP header fields contain a given field?
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> H.member "host" $ H.fromList [("Host", "localhost")]
--   True
--   ghci> H.member "Accept" $ H.fromList [("Host", "localhost")]
--   False
--   
member :: CI ByteString -> Headers -> Bool

-- | Look up the value of a given HTTP header field.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> H.lookup "host" $ H.fromList [("Host", "localhost")]
--   Just "localhost"
--   ghci> H.lookup "Accept" $ H.fromList [("Host", "localhost")]
--   Nothing
--   
lookup :: CI ByteString -> Headers -> Maybe ByteString

-- | Look up the value of a given HTTP header field or return the provided
--   default value when that header field is not present.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let hdrs = H.fromList [("Host", "localhost")]
--   ghci> H.lookupWithDefault "host" "127.0.0.1" $ hdrs
--   "localhost"
--   ghci> H.lookupWithDefault "Accept" "text/plain" $ hdrs
--   "text/plain"
--   
lookupWithDefault :: ByteString -> CI ByteString -> Headers -> ByteString

-- | Insert a key-value pair into the headers map. If the key already
--   exists in the map, the values are catenated with ", ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let hdrs = H.insert "Accept" "text/plain" $ H.empty
--   ghci> hdrs
--   H {unH = [("accept","text/plain")]}
--   ghci> H.insert "Accept" "text/html" $ hdrs
--   H {unH = [("accept","text/plain,text/html")]}
--   
insert :: CI ByteString -> ByteString -> Headers -> Headers

-- | Insert a key-value pair into the headers map, without checking whether
--   the header already exists. The key must be already case-folded,
--   or none of the lookups will work!
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let hdrs = H.unsafeInsert "accept" "text/plain" $ H.empty
--   ghci> hdrs
--   H {unH = [("accept","text/plain")]}
--   ghci> let hdrs' = H.unsafeInsert "accept" "text/html" $ hdrs
--   ghci> hdrs'
--   H {unH = [("accept","text/html"), ("accept","text/plain")]}
--   ghci> H.lookup "accept" hdrs'
--   Just "text/html"
--   
unsafeInsert :: ByteString -> ByteString -> Headers -> Headers

-- | Set the value of a HTTP header field to a given value, replacing the
--   old value.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> H.set "accept" "text/plain" $ H.empty
--   H {unH = [("accept","text/plain")]}
--   ghci> H.set "accept" "text/html" $ H.fromList [("Accept", "text/plain")]
--   H {unH = [("accept","text/html")]}
--   
set :: CI ByteString -> ByteString -> Headers -> Headers

-- | Delete all key-value pairs associated with the given key from the
--   headers map.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> H.delete "accept" $ H.fromList [("Accept", "text/plain")]
--   H {unH = []}
--   
delete :: CI ByteString -> Headers -> Headers

-- | Strict left fold over all key-value pairs in the headers map.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import Data.Monoid
--   ghci> let hdrs = H.fromList [("Accept", "text/plain"), ("Accept", "text/html")]
--   ghci> let f (cntr, acc) _ val = (cntr+1, val <> ";" <> acc)
--   ghci> H.foldl' f (0, "") hdrs
--   (2,"text/html;text/plain;")
--   
foldl' :: (a -> CI ByteString -> ByteString -> a) -> a -> Headers -> a

-- | Right fold over all key-value pairs in the headers map.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import Data.Monoid
--   ghci> let hdrs = H.fromList [("Accept", "text/plain"), ("Accept", "text/html")]
--   ghci> let f _ val (cntr, acc) = (cntr+1, val <> ";" <> acc)
--   ghci> H.foldr f (0, "") hdrs
--   (2,"text/plain;text/html;")
--   
foldr :: (CI ByteString -> ByteString -> a -> a) -> a -> Headers -> a

-- | Same as foldl', but the key parameter is of type
--   ByteString instead of CI ByteString. The key is
--   case-folded (lowercase).
foldedFoldl' :: (a -> ByteString -> ByteString -> a) -> a -> Headers -> a

-- | Same as foldr, but the key parameter is of type
--   ByteString instead of CI ByteString. The key is
--   case-folded (lowercase).
foldedFoldr :: (ByteString -> ByteString -> a -> a) -> a -> Headers -> a

-- | Convert a Headers value to a list of key-value pairs.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let l = [("Accept", "text/plain"), ("Accept", "text/html")]
--   ghci> H.toList . H.fromList $ l
--   [("accept","text/plain"),("accept","text/html")]
--   
toList :: Headers -> [(CI ByteString, ByteString)]

-- | Build a Headers value from a list of key-value pairs.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> H.fromList [("Accept", "text/plain"), ("Accept", "text/html")]
--   H {unH = [("accept","text/plain"),("accept","text/html")]}
--   
fromList :: [(CI ByteString, ByteString)] -> Headers

-- | Like fromList, but the keys are assumed to be already
--   case-folded (in lowercase).
unsafeFromCaseFoldedList :: [(ByteString, ByteString)] -> Headers

-- | Like toList, but does not convert the keys to CI
--   ByteString, so key comparisons will be case-sensitive.
unsafeToCaseFoldedList :: Headers -> [(ByteString, ByteString)]
instance GHC.Internal.Show.Show Snap.Types.Headers.Headers

-- | An internal Snap module containing HTTP types.
--   
--   N.B. this is an internal interface, please don't write user
--   code that depends on it. Most of these declarations (except for the
--   unsafe/encapsulation-breaking ones) are re-exported from
--   Snap.Core.
module Snap.Internal.Http.Types
set_c_locale :: IO ()
c_parse_http_time :: CString -> IO CTime
c_format_http_time :: CTime -> CString -> IO ()
c_format_log_time :: CTime -> CString -> IO ()

-- | A typeclass for datatypes which contain HTTP headers.
class HasHeaders a

-- | Modify the datatype's headers.
updateHeaders :: HasHeaders a => (Headers -> Headers) -> a -> a

-- | Retrieve the headers from a datatype that has headers.
headers :: HasHeaders a => a -> Headers

-- | 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.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> addHeader "Host" "localhost" H.empty
--   H {unH = [("host","localhost")]}
--   ghci> addHeader "Host" "127.0.0.1" it
--   H {unH = [("host","localhost,127.0.0.1")]}
--   
addHeader :: HasHeaders a => CI ByteString -> 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.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> setHeader "Host" "localhost" H.empty
--   H {unH = [("host","localhost")]}
--   ghci> setHeader "Host" "127.0.0.1" it
--   H {unH = [("host","127.0.0.1")]}
--   
setHeader :: HasHeaders a => CI ByteString -> ByteString -> a -> a

-- | Gets a header value out of a HasHeaders datatype.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> getHeader "Host" $ setHeader "Host" "localhost" H.empty
--   Just "localhost"
--   
getHeader :: HasHeaders a => CI ByteString -> a -> Maybe ByteString

-- | Lists all the headers out of a HasHeaders datatype. If many
--   headers came in with the same name, they will be catenated together.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> listHeaders $ setHeader "Host" "localhost" H.empty
--   [("host","localhost")]
--   
listHeaders :: HasHeaders a => a -> [(CI ByteString, ByteString)]

-- | Clears a header value from a HasHeaders datatype.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> deleteHeader "Host" $ setHeader "Host" "localhost" H.empty
--   H {unH = []}
--   
deleteHeader :: HasHeaders a => CI ByteString -> a -> a

-- | Enumerates the HTTP method values (see
--   http://tools.ietf.org/html/rfc2068.html#section-5.1.1).
data Method
GET :: Method
HEAD :: Method
POST :: Method
PUT :: Method
DELETE :: Method
TRACE :: Method
OPTIONS :: Method
CONNECT :: Method
PATCH :: Method
Method :: ByteString -> Method

-- | Equate the special case constructors with their corresponding
--   Method name variant.
normalizeMethod :: Method -> Method

-- | Represents a (major, minor) version of the HTTP protocol.
type HttpVersion = (Int, Int)

-- | A datatype representing an HTTP cookie.
data Cookie
Cookie :: !ByteString -> !ByteString -> !Maybe UTCTime -> !Maybe ByteString -> !Maybe ByteString -> !Bool -> !Bool -> Cookie

-- | The name of the cookie.
[cookieName] :: Cookie -> !ByteString

-- | The cookie's string value.
[cookieValue] :: Cookie -> !ByteString

-- | The cookie's expiration value, if it has one.
[cookieExpires] :: Cookie -> !Maybe UTCTime

-- | The cookie's "domain" value, if it has one.
[cookieDomain] :: Cookie -> !Maybe ByteString

-- | The cookie path.
[cookiePath] :: Cookie -> !Maybe ByteString

-- | Tag as secure cookie?
[cookieSecure] :: Cookie -> !Bool

-- | HTTP only?
[cookieHttpOnly] :: Cookie -> !Bool

-- | 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"].
type Params = Map ByteString [ByteString]

-- | Contains all of the information about an incoming HTTP request.
data Request
Request :: ByteString -> ByteString -> {-# UNPACK #-} !Int -> ByteString -> {-# UNPACK #-} !Int -> ByteString -> !Bool -> Headers -> InputStream ByteString -> !Maybe Word64 -> !Method -> {-# UNPACK #-} !HttpVersion -> [Cookie] -> ByteString -> ByteString -> ByteString -> ByteString -> Params -> Params -> Params -> Request

-- | The server name of the request, as it came in from the request's
--   Host: header.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.get "/foo/bar" M.empty
--   ghci|         T.setHeader "host" "example.com"
--   ghci| :}
--   ghci> rqHostName rq
--   "example.com"
--   
[rqHostName] :: Request -> ByteString

-- | The remote IP address.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqClientAddr `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "127.0.0.1"
--   
[rqClientAddr] :: Request -> ByteString

-- | The remote TCP port number.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqClientPort `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "60000"
--   
[rqClientPort] :: Request -> {-# UNPACK #-} !Int

-- | The local IP address for this request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqServerAddr `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "127.0.0.1"
--   
[rqServerAddr] :: Request -> ByteString

-- | Returns the port number the HTTP server is listening on. This may be
--   useless from the perspective of external requests, e.g. if the server
--   is running behind a proxy.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqServerPort `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   8080
--   
[rqServerPort] :: Request -> {-# UNPACK #-} !Int

-- | Returns the HTTP server's idea of its local hostname, including port.
--   This is as configured with the Config object at startup.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqLocalHostname `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "localhost"
--   
[rqLocalHostname] :: Request -> ByteString

-- | Returns True if this is an HTTPS session.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqIsSecure `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   False
--   
[rqIsSecure] :: Request -> !Bool

-- | Contains all HTTP Headers associated with this request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqHeaders `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   H {unH = [("host","localhost")]}
--   
[rqHeaders] :: Request -> Headers

-- | Actual body of the request.
[rqBody] :: Request -> InputStream ByteString

-- | Returns the Content-Length of the HTTP request body.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqContentLength `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   Nothing
--   
[rqContentLength] :: Request -> !Maybe Word64

-- | Returns the HTTP request method.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqMethod `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   GET
--   
[rqMethod] :: Request -> !Method

-- | Returns the HTTP version used by the client.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqVersion `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   (1,1)
--   
[rqVersion] :: Request -> {-# UNPACK #-} !HttpVersion

-- | Returns a list of the cookies that came in from the HTTP request
--   headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqCookies `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   []
--   
[rqCookies] :: Request -> [Cookie]

-- | Handlers can 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".
--   
--   The following identity holds:
--   
--   
--   rqURI r == S.concat [ rqContextPath r
--                       , rqPathInfo r
--                       , let q = rqQueryString r
--                         in if S.null q
--                              then ""
--                              else S.append "?" q
--                       ]
--   
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqPathInfo `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "foo/bar"
--   
[rqPathInfo] :: Request -> ByteString

-- | The "context path" of the request; catenating rqContextPath,
--   and rqPathInfo should get you back to the original rqURI
--   (ignoring query strings). 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqContextPath `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "/"
--   
[rqContextPath] :: Request -> ByteString

-- | Returns the URI requested by the client.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqURI `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "foo/bar"
--   
[rqURI] :: Request -> ByteString

-- | Returns the HTTP query string for this Request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rq <- T.buildRequest (T.get "/foo/bar" (M.fromList [("name", ["value"])]))
--   ghci> rqQueryString rq
--   "name=value"
--   
[rqQueryString] :: Request -> ByteString

-- | Returns the parameters mapping for this Request. "Parameters"
--   are automatically decoded from the URI's query string and
--   POST body and entered into this mapping. The rqParams
--   value is thus a union of rqQueryParams and rqPostParams.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   
[rqParams] :: Request -> Params

-- | The parameter mapping decoded from the URI's query string.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqQueryParams rq
--   fromList [("baz",["quux"])]
--   
[rqQueryParams] :: Request -> Params

-- | The parameter mapping decoded from the POST body. Note that Snap only
--   auto-decodes POST request bodies when the request's
--   Content-Type is application/x-www-form-urlencoded.
--   For multipart/form-data use handleFileUploads to
--   decode the POST request and fill this mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqPostParams rq
--   fromList [("baz",["qux"])]
--   
[rqPostParams] :: Request -> Params
type StreamProc = OutputStream Builder -> IO OutputStream Builder
data ResponseBody

-- | output body is a function that writes to a Builder stream
Stream :: StreamProc -> ResponseBody

-- | output body is sendfile(), optional second argument is a byte range to
--   send
SendFile :: FilePath -> Maybe (Word64, Word64) -> ResponseBody
rspBodyMap :: (StreamProc -> StreamProc) -> ResponseBody -> ResponseBody
rspBodyToEnum :: ResponseBody -> StreamProc

-- | Represents an HTTP response.
data Response
Response :: Headers -> Map ByteString Cookie -> !Maybe Word64 -> ResponseBody -> !Int -> !ByteString -> !Bool -> Response
[rspHeaders] :: Response -> Headers
[rspCookies] :: Response -> Map ByteString Cookie

-- | We will need to inspect the content length no matter what, and looking
--   up "content-length" in the headers and parsing the number out of the
--   text will be too expensive.
[rspContentLength] :: Response -> !Maybe Word64
[rspBody] :: Response -> ResponseBody

-- | Returns the HTTP status code.
--   
--   Example:
--   
--   
--   ghci> rspStatus emptyResponse
--   200
--   
[rspStatus] :: Response -> !Int

-- | Returns the HTTP status explanation string.
--   
--   Example:
--   
--   
--   ghci> rspStatusReason emptyResponse
--   OK
--   
[rspStatusReason] :: Response -> !ByteString

-- | If true, we are transforming the request body with
--   transformRequestBody
[rspTransformingRqBody] :: Response -> !Bool

-- | 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".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParam "baz" rq
--   Just ["qux","quux"]
--   
rqParam :: ByteString -> Request -> Maybe [ByteString]

-- | Looks up the value(s) for the given named parameter in the POST
--   parameters mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqPostParam "baz" rq
--   Just ["qux"]
--   
rqPostParam :: ByteString -> Request -> Maybe [ByteString]

-- | Looks up the value(s) for the given named parameter in the query
--   parameters mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqQueryParam "baz" rq
--   Just ["quux"]
--   
rqQueryParam :: ByteString -> Request -> Maybe [ByteString]

-- | Modifies the parameters mapping (which is a Map ByteString
--   ByteString) in a Request using the given function.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   ghci> rqParams $ rqModifyParams (M.delete "baz") rq
--   fromList []
--   
rqModifyParams :: (Params -> Params) -> Request -> Request

-- | Writes a key-value pair to the parameters mapping within the given
--   request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   ghci> rqParams $ rqSetParam "baz" ["corge"] rq
--   fromList [("baz", ["corge"])]
--   
rqSetParam :: ByteString -> [ByteString] -> Request -> Request

-- | An empty Response.
--   
--   Example:
--   
--   
--   ghci> emptyResponse
--   HTTP/1.1 200 OK
--   
emptyResponse :: Response

-- | Sets an HTTP response body to the given stream procedure.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> r
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   
setResponseBody :: (OutputStream Builder -> IO (OutputStream Builder)) -> Response -> Response

-- | Sets the HTTP response status. Note: normally you would use
--   setResponseCode unless you needed a custom response
--   explanation.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> setResponseStatus 500 "Internal Server Error" emptyResponse
--   HTTP/1.1 500 Internal Server Error
--   
setResponseStatus :: Int -> ByteString -> Response -> Response

-- | Sets the HTTP response code.
--   
--   Example:
--   
--   
--   ghci> setResponseCode 404 emptyResponse
--   HTTP/1.1 404 Not Found
--   
setResponseCode :: Int -> Response -> Response

-- | Modifies a response body.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> r
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   ghci> :{
--   ghci| let r' = modifyResponseBody
--   ghci|          (f out -> do
--   ghci|              out' <- f out
--   ghci|              Streams.write (Just $ Builder.byteString "\nBye, world!") out'
--   ghci|              return out') r
--   ghci| :}
--   ghci> r'
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   Bye, world!
--   
modifyResponseBody :: ((OutputStream Builder -> IO (OutputStream Builder)) -> OutputStream Builder -> IO (OutputStream Builder)) -> Response -> Response

-- | Sets the Content-Type in the Response headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> setContentType "text/html" emptyResponse
--   HTTP/1.1 200 OK
--   content-type: text/html
--   
setContentType :: ByteString -> Response -> Response

-- | Convert Cookie into ByteString for output.
--   
--   TODO: Remove duplication. This function is copied from
--   snap-server/Snap.Internal.Http.Server.Session.
cookieToBS :: Cookie -> ByteString

-- | Render cookies from a given Response to Headers.
--   
--   TODO: Remove duplication. This function is copied from
--   snap-server/Snap.Internal.Http.Server.Session.
renderCookies :: Response -> Headers -> Headers

-- | Adds an HTTP Cookie to Response headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> getResponseCookie "name" $ addResponseCookie cookie emptyResponse
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   
addResponseCookie :: Cookie -> Response -> Response

-- | Gets an HTTP Cookie with the given name from Response
--   headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> getResponseCookie "cookie-name" emptyResponse
--   Nothing
--   
getResponseCookie :: ByteString -> Response -> Maybe Cookie

-- | Returns a list of Cookies present in Response
--   
--   Example:
--   
--   
--   ghci> getResponseCookies emptyResponse
--   []
--   
getResponseCookies :: Response -> [Cookie]

-- | Deletes an HTTP Cookie from the Response headers. Please
--   note this does not necessarily erase the cookie from the client
--   browser.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let rsp    = addResponseCookie cookie emptyResponse
--   ghci> getResponseCookie "name" rsp
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   ghci> getResponseCookie "name" $ deleteResponseCookie "name" rsp
--   Nothing
--   
deleteResponseCookie :: ByteString -> Response -> Response

-- | Modifies an HTTP Cookie with given name in Response
--   headers. Nothing will happen if a matching Cookie can not be
--   found in Response.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import Data.Monoid
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let rsp    = addResponseCookie cookie emptyResponse
--   ghci> getResponseCookie "name" rsp
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   ghci> let f ck@(Cookie { cookieName = name }) = ck { cookieName = name <> "'"}
--   ghci> let rsp' = modifyResponseCookie "name" f rsp
--   ghci> getResponseCookie "name'" rsp'
--   Just (Cookie {cookieName = "name'", ...})
--   ghci> getResponseCookie "name" rsp'
--   Just (Cookie {cookieName = "name", ...})
--   
modifyResponseCookie :: ByteString -> (Cookie -> Cookie) -> 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.
--   
--   Example:
--   
--   
--   ghci> setContentLength 400 emptyResponse
--   HTTP/1.1 200 OK
--   Content-Length: 400
--   
setContentLength :: Word64 -> Response -> Response

-- | Removes any Content-Length set in the Response.
--   
--   Example:
--   
--   
--   ghci> clearContentLength $ setContentLength 400 emptyResponse
--   HTTP/1.1 200 OK
--   
clearContentLength :: Response -> Response

-- | Convert a CTime into common log entry format.
formatLogTime :: CTime -> IO ByteString

-- | Convert a CTime into an HTTP timestamp.
--   
--   Example:
--   
--   
--   ghci> formatHttpTime . fromIntegral $ 10
--   "Thu, 01 Jan 1970 00:00:10 GMT"
--   
formatHttpTime :: CTime -> IO ByteString

-- | Converts an HTTP timestamp into a CTime.
--   
--   If the given time string is unparseable, this function will return 0.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> parseHttpTime "Thu, 01 Jan 1970 00:00:10 GMT"
--   10
--   
parseHttpTime :: ByteString -> IO CTime

-- | Adapted from:
--   
--   
--   https://www.iana.org/assignments/http-status-codes/http-status-codes.txt
statusReasonMap :: IntMap ByteString

-- | See rqClientAddr.

-- | Deprecated: (snap-core >= 1.0.0.0) please use
--   rqClientAddr, this will be removed in 1.1.*
rqRemoteAddr :: Request -> ByteString

-- | See rqClientPort.

-- | Deprecated: (snap-core >= 1.0.0.0) please use
--   rqClientPort, this will be removed in 1.1.*
rqRemotePort :: Request -> Int
instance GHC.Classes.Eq Snap.Internal.Http.Types.Cookie
instance GHC.Classes.Eq Snap.Internal.Http.Types.Method
instance Snap.Internal.Http.Types.HasHeaders Snap.Types.Headers.Headers
instance Snap.Internal.Http.Types.HasHeaders Snap.Internal.Http.Types.Request
instance Snap.Internal.Http.Types.HasHeaders Snap.Internal.Http.Types.Response
instance GHC.Classes.Ord Snap.Internal.Http.Types.Method
instance GHC.Internal.Read.Read Snap.Internal.Http.Types.Method
instance GHC.Internal.Show.Show Snap.Internal.Http.Types.Cookie
instance GHC.Internal.Show.Show Snap.Internal.Http.Types.Method
instance GHC.Internal.Show.Show Snap.Internal.Http.Types.Request
instance GHC.Internal.Show.Show Snap.Internal.Http.Types.Response

module Snap.Internal.Parsing
fullyParse :: ByteString -> Parser a -> Either String a
(<?>) :: Parser a -> String -> Parser a
infix 0 <?>
fullyParse' :: (Parser a -> ByteString -> Result a) -> (Result a -> ByteString -> Result a) -> ByteString -> Parser a -> Either String a
parseNum :: Parser Int64
untilEOL :: Parser ByteString
crlf :: Parser ByteString
toTableList :: (Char -> Bool) -> [Char]
toTable :: (Char -> Bool) -> Char -> Bool
skipFieldChars :: Parser ()
isFieldChar :: Char -> Bool

-- | Parser for request headers.
pHeaders :: Parser [(ByteString, ByteString)]
pWord :: Parser ByteString
pWord' :: (Char -> Bool) -> Parser ByteString
pQuotedString :: Parser ByteString
pQuotedString' :: (Char -> Bool) -> Parser ByteString
isRFCText :: Char -> Bool
matchAll :: [Char -> Bool] -> Char -> Bool
pAvPairs :: Parser [(ByteString, ByteString)]
pAvPair :: Parser (ByteString, ByteString)
pParameter :: Parser (ByteString, ByteString)
pParameter' :: (Char -> Bool) -> Parser (ByteString, ByteString)
trim :: ByteString -> ByteString
pValueWithParameters :: Parser (ByteString, [(CI ByteString, ByteString)])
pValueWithParameters' :: (Char -> Bool) -> Parser (ByteString, [(CI ByteString, ByteString)])
pContentTypeWithParameters :: Parser (ByteString, [(CI ByteString, ByteString)])
pToken :: Parser ByteString
isToken :: Char -> Bool

-- | Used for "#field-name", and field-name = token, so "#token":
--   comma-separated tokens/field-names, like a header field list.
pTokens :: Parser [ByteString]
parseToCompletion :: Parser a -> ByteString -> Maybe a
type DList a = [a] -> [a]
pUrlEscaped :: Parser ByteString

-- | Decode an URL-escaped string (see
--   http://tools.ietf.org/html/rfc2396.html#section-2.4)
--   
--   Example:
--   
--   
--   ghci> urlDecode "1+attoparsec+%7e%3d+3+*+10%5e-2+meters"
--   Just "1 attoparsec ~= 3 * 10^-2 meters"
--   
urlDecode :: ByteString -> Maybe ByteString

-- | URL-escape a string (see
--   http://tools.ietf.org/html/rfc2396.html#section-2.4)
--   
--   Example:
--   
--   
--   ghci> urlEncode "1 attoparsec ~= 3 * 10^-2 meters"
--   "1+attoparsec+%7e%3d+3+*+10%5e-2+meters"
--   
urlEncode :: ByteString -> ByteString

-- | URL-escape a string (see
--   http://tools.ietf.org/html/rfc2396.html#section-2.4) into a
--   Builder.
--   
--   Example:
--   
--   
--   ghci> import Data.ByteString.Builder
--   ghci> toLazyByteString . urlEncodeBuilder $ "1 attoparsec ~= 3 * 10^-2 meters"
--   "1+attoparsec+%7e%3d+3+*+10%5e-2+meters"
--   
urlEncodeBuilder :: ByteString -> Builder
urlEncodeClean :: Char -> Bool
hexd :: Char -> Builder
finish :: Result a -> Result a

-- | Parse a string encoded in application/x-www-form-urlencoded
--   format.
--   
--   Example:
--   
--   
--   ghci> parseUrlEncoded "Name=John+Doe&Name=Jane+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21"
--   fromList [(Age,["23"]),(Formula,["a + b == 13%!"]),(Name,["John Doe","Jane Doe"])]
--   
parseUrlEncoded :: ByteString -> Map ByteString [ByteString]

-- | Like printUrlEncoded, but produces a Builder instead of
--   a ByteString. Useful for constructing a large string
--   efficiently in a single step.
--   
--   Example:
--   
--   
--   ghci> import Data.Map
--   ghci> import Data.Monoid
--   ghci> import Data.ByteString.Builder
--   ghci> let bldr = buildUrlEncoded (fromList [(Name, ["John Doe"]), (Age, ["23"])])
--   ghci> toLazyByteString $ byteString "http://example.com/script?" <> bldr
--   "http://example.com/script?Age=23&Name=John+Doe"
--   
buildUrlEncoded :: Map ByteString [ByteString] -> Builder

-- | Given a collection of key-value pairs with possibly duplicate keys
--   (represented as a Map), construct a string in
--   application/x-www-form-urlencoded format.
--   
--   Example:
--   
--   
--   ghci> printUrlEncoded (fromList [(Name, ["John Doe"]), (Age, ["23"])])
--   "Age=23&Name=John+Doe"
--   
printUrlEncoded :: Map ByteString [ByteString] -> ByteString
pCookies :: Parser [Cookie]
parseCookie :: ByteString -> Maybe [Cookie]
unsafeFromHex :: (Enum a, Num a, Bits a) => ByteString -> a
unsafeFromNat :: (Enum a, Num a, Bits a) => ByteString -> a

module Snap.Internal.Core

-- | MonadSnap is a type class, analogous to MonadIO for
--   IO, that makes it easy to wrap Snap inside monad
--   transformers.
class (Monad m, MonadIO m, MonadBaseControl IO m, MonadPlus m, Functor m, Applicative m, Alternative m) => MonadSnap (m :: Type -> Type)

-- | Lift a computation from the Snap monad.
liftSnap :: MonadSnap m => Snap a -> m a
data SnapResult a
SnapValue :: a -> SnapResult a
Zero :: Zero -> SnapResult a

-- | Type of external handler passed to escapeHttp.
type EscapeHttpHandler = Int -> Int -> IO () -> InputStream ByteString -> OutputStream Builder -> IO ()

-- | Used internally to implement escapeHttp.
data EscapeSnap
TerminateConnection :: SomeException -> EscapeSnap
EscapeHttp :: EscapeHttpHandler -> EscapeSnap
data Zero
PassOnProcessing :: Zero
EarlyTermination :: Response -> Zero
EscapeSnap :: EscapeSnap -> Zero

-- | Snap is the Monad that user web handlers run in.
--   Snap gives you:
--   
--   
--   
- Stateful access to fetch or modify an HTTP
--   Request.
printRqContextPath :: Snap () printRqContextPath =
--   writeBS . rqContextPath =<< getRequest
--   

--   
- Stateful access to fetch or modify an HTTP
--   Response.
printRspStatusReason :: Snap ()
--   printRspStatusReason = writeBS . rspStatusReason
--   =<< getResponse 

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

--   
- Convenience functions (writeBS, writeLBS,
--   writeText, writeLazyText, addToOutput) for
--   queueing output to be written to the Response, or for streaming
--   to the response using io-streams:
example ::
--   (OutputStream Builder -> IO (OutputStream
--   Builder)) -> Snap () example streamProc = do writeBS
--   "I'm a strict bytestring" writeLBS "I'm a lazy bytestring"
--   writeText "I'm strict text" addToOutput streamProc
--   

--   
- 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 the supplied Response value will be returned from
--   runSnap as-is.
--   
- Access to the IO monad through a MonadIO
--   instance:
a :: Snap () a = liftIO fireTheMissiles
--   

--   
- The ability to set or extend a timeout which will kill the handler
--   thread after N seconds of inactivity (the default is 20
--   seconds):
a :: Snap () a = setTimeout 30 

--   
- Throw and catch exceptions using a MonadBaseControl
--   instance:
import Control.Exception.Lifted
--   (SomeException, throwIO, catch) foo :: Snap ()
--   foo = bar `catch` (e::SomeException) -> baz where bar =
--   throwIO FooException 

--   
- Log a message to the error log:
foo :: Snap () foo =
--   logError "grumble." 

--   
--   
--   You may notice that most of the type signatures in this module contain
--   a (MonadSnap m) => ... typeclass constraint.
--   MonadSnap is a typeclass which, in essence, says "you can get
--   back to the Snap monad from here". Using MonadSnap you
--   can extend the Snap monad with additional functionality and
--   still have access to most of the Snap functions without writing
--   lift everywhere. Instances are already provided for most of the
--   common monad transformers (ReaderT, WriterT,
--   StateT, etc.).
newtype Snap a
Snap :: (forall r. () => (a -> SnapState -> IO r) -> (Zero -> SnapState -> IO r) -> SnapState -> IO r) -> Snap a
[unSnap] :: Snap a -> forall r. () => (a -> SnapState -> IO r) -> (Zero -> SnapState -> IO r) -> SnapState -> IO r
data SnapState
SnapState :: Request -> Response -> (ByteString -> IO ()) -> ((Int -> Int) -> IO ()) -> SnapState
[_snapRequest] :: SnapState -> Request
[_snapResponse] :: SnapState -> Response
[_snapLogError] :: SnapState -> ByteString -> IO ()
[_snapModifyTimeout] :: SnapState -> (Int -> Int) -> IO ()

-- | Pass the request body stream to a consuming procedure, returning the
--   result.
--   
--   If the consuming procedure you pass in here throws an exception, Snap
--   will attempt to clear the rest of the unread request body (using
--   skipToEof) before rethrowing the exception. If you used
--   terminateConnection, however, Snap will give up and immediately
--   close the socket.
--   
--   To prevent slowloris attacks, the connection will be also terminated
--   if the input socket produces data too slowly (500 bytes per second is
--   the default limit).
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import qualified Data.ByteString.Lazy as L
--   ghci> import Data.Char (toUpper)
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> let r = T.put "/foo" "text/plain" "some text"
--   ghci> :{
--   ghci| let f s = do u <- Streams.map (B8.map toUpper) s
--   ghci|              l <- Streams.toList u
--   ghci|              return $ L.fromChunks l
--   ghci| :}
--   ghci> T.runHandler r (runRequestBody f >>= writeLBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 20:48:40 GMT
--   
--   SOME TEXT
--   
runRequestBody :: MonadSnap m => (InputStream ByteString -> IO a) -> m a

-- | Returns the request body as a lazy bytestring. /Note that the request
--   is not actually provided lazily!/
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.put "/foo" "text/plain" "some text"
--   ghci> T.runHandler r (readRequestBody 2048 >>= writeLBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 20:08:44 GMT
--   
--   some text
--   
--   
--   Since: 0.6
readRequestBody :: MonadSnap m => Word64 -> m ByteString

-- | Normally Snap is careful to ensure that the request body is fully
--   consumed after your web handler runs, but before the Response
--   body 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.
--   
--   Take care: in order for this to work, the HTTP client must be written
--   with input-to-output streaming in mind.
--   
--   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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import Data.Char (toUpper)
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> let r = T.put "/foo" "text/plain" "some text"
--   ghci> let f = Streams.map (B8.map toUpper)
--   ghci> T.runHandler r (transformRequestBody f >> readRequestBody 2048 >>= writeLBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 20:30:15 GMT
--   
--   SOME TEXT
--   
transformRequestBody :: (InputStream ByteString -> IO (InputStream ByteString)) -> Snap ()

-- | Short-circuits a Snap monad action early, storing the given
--   Response value in its state.
--   
--   IMPORTANT: Be vary careful when using this with things like a DB
--   library's withTransaction function or any other kind of
--   setup/teardown block, as it can prevent the cleanup from being called
--   and result in resource leaks.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import Control.Applicative
--   ghci> let r = T.get "/" M.empty
--   ghci> T.runHandler r ((ifTop $ writeBS "TOP") <|> finishWith emptyResponse)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 16:58:57 GMT
--   
--   TOP
--   ghci> let r' = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r' ((ifTop $ writeBS "TOP") <|> finishWith emptyResponse)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 17:50:50 GMT
--   
finishWith :: MonadSnap m => Response -> m a

-- | Capture the flow of control in case a handler calls finishWith.
--   
--   WARNING: in the event of a call to transformRequestBody
--   it is possible to violate HTTP protocol safety when using this
--   function. If you call catchFinishWith it is suggested that you
--   do not modify the body of the Response which was passed to the
--   finishWith call.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import Control.Applicative
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> let h = (ifTop $ writeBS "TOP") <|> finishWith emptyResponse
--   ghci> T.runHandler r (catchFinishWith h >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 18:35:42 GMT
--   
--   Left HTTP/1.1 200 OK
--   
catchFinishWith :: Snap a -> Snap (Either Response 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r pass
--   HTTP/1.1 404 Not Found
--   server: Snap/test
--   date: Thu, 07 Aug 2014 13:35:42 GMT
--   
--   <!DOCTYPE html>
--   <html>
--   <head>
--   <title>Not found</title>
--   </head>
--   <body>
--   <code>No handler accepted "/foo/bar"/code
--   </body></html>
--   
pass :: MonadSnap m => m a

-- | Runs a Snap monad action only if the request's HTTP method
--   matches the given method.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (method GET $ writeBS "OK")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 13:38:48 GMT
--   
--   OK
--   ghci> T.runHandler r (method POST $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
method :: MonadSnap m => Method -> m a -> m a

-- | Runs a Snap monad action only if the request's HTTP method
--   matches one of the given methods.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (methods [GET, POST] $ writeBS "OK")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 13:38:48 GMT
--   
--   OK
--   ghci> T.runHandler r (methods [POST] $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
methods :: MonadSnap m => [Method] -> m a -> m a
updateContextPath :: Int -> Request -> Request
pathWith :: MonadSnap m => (ByteString -> ByteString -> Bool) -> ByteString -> m a -> m 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (dir "foo" $ writeBS "OK")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:52:24 GMT
--   
--   OK
--   ghci> T.runHandler r (dir "baz" $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
dir :: MonadSnap m => ByteString -> m a -> m 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> T.runHandler (T.get "/foo" M.empty) (path "foo" $ writeBS "bar")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:15:42 GMT
--   
--   bar
--   ghci> T.runHandler (T.get "/foo" M.empty) (path "bar" $ writeBS "baz")
--   HTTP/1.1 404 Not Found
--   ...
--   
path :: MonadSnap m => ByteString -> m a -> m a

-- | Runs a Snap monad action only when the first path component is
--   successfully parsed as the argument to the supplied handler function.
--   
--   Note that the path segment is url-decoded prior to being passed to
--   fromBS; this is new as of snap-core 0.10.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/11/foo/bar" M.empty
--   ghci> let f = (\i -> if i == 11 then writeBS "11" else writeBS "???")
--   ghci> T.runHandler r (pathArg f)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:27:10 GMT
--   
--   11
--   ghci> let r' = T.get "/foo/11/bar" M.empty
--   ghci> T.runHandler r' (pathArg f)
--   HTTP/1.1 404 Not Found
--   ...
--   
pathArg :: (Readable a, MonadSnap m) => (a -> m b) -> m b

-- | Runs a Snap monad action only when rqPathInfo is empty.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/" M.empty
--   ghci> T.runHandler r (ifTop $ writeBS OK)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:56:39 GMT
--   
--   OK
--   ghci> let r' = T.get "/foo" M.empty
--   ghci> T.runHandler r' (ifTop $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
ifTop :: MonadSnap m => m a -> m a

-- | Local Snap version of get.
sget :: Snap SnapState

-- | Local Snap monad version of modify.
smodify :: (SnapState -> SnapState) -> Snap ()

-- | Grabs the Request object out of the Snap monad.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS . rqURI =<< getRequest)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 07:51:54 GMT
--   
--   /foo/bar
--   
getRequest :: MonadSnap m => m Request

-- | Grabs the Response object out of the Snap monad.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS . rspStatusReason =<< getResponse)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 15:06:00 GMT
--   
--   OK
--   
getResponse :: MonadSnap m => m Response

-- | Grabs something out of the Request object, using the given
--   projection function. See gets.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS =<< getsRequest rqURI)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 07:51:54 GMT
--   
--   /foo/bar
--   
getsRequest :: MonadSnap m => (Request -> a) -> m a

-- | Grabs something out of the Response object, using the given
--   projection function. See gets.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS =<< getsResponse rspStatusReason)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 13:35:45 GMT
--   
--   OK
--   
getsResponse :: MonadSnap m => (Response -> a) -> m a

-- | Puts a new Request object into the Snap monad. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> :{
--   ghci| let hndlr = do rq <- T.buildRequest (T.get "/bar/foo" M.empty)
--   ghci|                putRequest rq
--   ghci|                uri' <- getsRequest rqURI
--   ghci|                writeBS uri'
--   ghci| :}
--   ghci> T.runHandler (T.get "/foo/bar" M.empty) hndlr
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:13:46 GMT
--   
--   /bar/foo
--   
putRequest :: MonadSnap m => Request -> m ()

-- | Puts a new Response object into the Snap monad.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let rsp = setResponseCode 404 emptyResponse
--   ghci> let req = T.get "/foo/bar" M.empty
--   ghci> T.runHandler req (putResponse rsp)
--   HTTP/1.1 404 Not Found
--   server: Snap/test
--   date: Wed, 06 Aug 2014 13:59:58 GMT
--   
putResponse :: MonadSnap m => Response -> m ()

-- | Modifies the Request object stored in a Snap monad.
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> r' <- T.buildRequest $ T.get "/bar/foo" M.empty
--   ghci> T.runHandler r (modifyRequest (const r') >> getsRequest rqURI >>= writeBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:24:25 GMT
--   
--   /bar/foo
--   
modifyRequest :: MonadSnap m => (Request -> Request) -> m ()

-- | Modifes the Response object stored in a Snap monad.
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (modifyResponse $ setResponseCode 404)
--   HTTP/1.1 404 Not Found
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:27:11 GMT
--   
modifyResponse :: MonadSnap m => (Response -> Response) -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (redirect "http://snapframework.com")
--   HTTP/1.1 302 Found
--   content-length: 0
--   location: http://snapframework.com
--   server: Snap/test
--   date: Thu, 07 Aug 2014 08:52:11 GMT
--   Content-Length: 0
--   
redirect :: MonadSnap m => ByteString -> m a

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (redirect' "http://snapframework.com" 301)
--   HTTP/1.1 307 Temporary Redirect
--   content-length: 0
--   location: http://snapframework.com
--   server: Snap/test
--   date: Thu, 07 Aug 2014 08:55:51 GMT
--   Content-Length: 0
--   
redirect' :: MonadSnap m => ByteString -> Int -> m a

-- | Log an error message in the Snap monad.
--   
--   Example:
--   
--   
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> runSnap (logError "fatal error!") (error . B8.unpack) undefined undefined
--   *** Exception: fatal error!
--   
logError :: MonadSnap m => ByteString -> m ()

-- | Run the given stream procedure, adding its output to the
--   Response stored in the Snap monad state.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Builder as B
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> :{
--   ghci| let f str = do {
--   ghci|   Streams.write (Just $ B.byteString "Hello, streams world") str;
--   ghci|   return str }
--   ghci| :}
--   ghci> T.runHandler r (addToOutput f)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:55:47 GMT
--   
--   Hello, streams world
--   
addToOutput :: MonadSnap m => (OutputStream Builder -> IO (OutputStream Builder)) -> m ()

-- | Adds the given Builder to the body of the Response
--   stored in the | Snap monad state.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Builder as B
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBuilder $ B.byteString "Hello, world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:33:33 GMT
--   
--   Hello, world
--   
writeBuilder :: MonadSnap m => Builder -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS "Hello, bytestring world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:34:27 GMT
--   
--   Hello, bytestring world
--   
writeBS :: MonadSnap m => ByteString -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeLBS "Hello, lazy bytestring world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:35:15 GMT
--   
--   Hello, lazy bytestring world
--   
writeLBS :: MonadSnap m => ByteString -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeText "Hello, text world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:36:38 GMT
--   
--   Hello, text world
--   
writeText :: MonadSnap m => Text -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeLazyText "Hello, lazy text world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:37:41 GMT
--   
--   Hello, lazy text world
--   
writeLazyText :: MonadSnap m => Text -> m ()

-- | 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().
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> writeFile "/tmp/snap-file" "Hello, sendFile world"
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (sendFile "/tmp/snap-file")
--   HTTP/1.1 200 OK
--   content-length: 21
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:45:10 GMT
--   Content-Length: 21
--   
--   Hello, sendFile world
--   
sendFile :: MonadSnap m => FilePath -> m ()

-- | 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().
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> writeFile "/tmp/snap-file" "Hello, sendFilePartial world"
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (sendFilePartial "/tmp/snap-file" (7, 28))
--   HTTP/1.1 200 OK
--   content-length: 21
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:47:20 GMT
--   Content-Length: 21
--   
--   sendFilePartial world
--   
sendFilePartial :: MonadSnap m => FilePath -> (Word64, Word64) -> m ()

-- | 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. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> r' <- T.buildRequest $ T.get "/bar/foo" M.empty
--   ghci> let printRqURI = getsRequest rqURI >>= writeBS >> writeBS "\n"
--   ghci> T.runHandler r (printRqURI >> localRequest (const r') printRqURI)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:34:12 GMT
--   
--   /foo/bar
--   /bar/foo
--   
localRequest :: MonadSnap m => (Request -> Request) -> m a -> m a

-- | Fetches the Request from state and hands it to the given
--   action. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import Control.Monad.IO.Class
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> let h = withRequest (\rq -> liftIO (T.requestToString rq) >>= writeBS)
--   ghci> T.runHandler r h
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:44:24 GMT
--   
--   GET /foo/bar HTTP/1.1
--   host: localhost
--   
withRequest :: MonadSnap m => (Request -> m a) -> m a

-- | Fetches the Response from state and hands it to the given
--   action. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (withResponse $ writeBS . rspStatusReason)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:48:45 GMT
--   
--   OK
--   
withResponse :: MonadSnap m => (Response -> m a) -> m a

-- | 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 :: MonadSnap m => m ()

-- | 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.
ipHeaderFilter' :: MonadSnap m => CI ByteString -> m ()

-- | This function brackets a Snap action in resource acquisition and
--   release. This is provided because MonadCatchIO's bracket
--   function doesn't work properly in the case of a short-circuit return
--   from the action being bracketed.
--   
--   In order to prevent confusion regarding the effects of the aquisition
--   and release actions on the Snap state, this function doesn't accept
--   Snap actions for the acquire or release actions.
--   
--   This function will run the release action in all cases where the
--   acquire action succeeded. This includes the following behaviors from
--   the bracketed Snap action.
--   
--   
--   
- Normal completion
--   
- Short-circuit completion, either from calling fail or
--   finishWith
--   
- An exception being thrown.
--   
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let br = bracketSnap (putStrLn "before") (const $ putStrLn "after")
--   ghci> T.runHandler (T.get "/" M.empty) (br $ const $ writeBS "OK")
--   before
--   after
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 18:41:50 GMT
--   
--   OK
--   
bracketSnap :: IO a -> (a -> IO b) -> (a -> Snap c) -> Snap c

-- | This exception is thrown if the handler you supply to runSnap
--   fails.
data NoHandlerException
NoHandlerException :: String -> NoHandlerException

-- | Terminate the HTTP session with the given exception.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Control.Exception as E
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (terminateConnection $ E.AssertionFailed "Assertion failed!")
--   *** Exception: <terminated: Assertion failed!>
--   
terminateConnection :: (Exception e, MonadSnap m) => e -> m a

-- | Terminate the HTTP session and hand control to some external handler,
--   escaping all further HTTP traffic.
--   
--   The external handler takes three arguments: a function to modify the
--   thread's timeout, and a read and a write ends to the socket.
escapeHttp :: MonadSnap m => EscapeHttpHandler -> m ()

-- | Runs a Snap monad action.
--   
--   This function is mostly intended for library writers; instead of
--   invoking runSnap directly, use httpServe or
--   runHandler (for testing).
runSnap :: Snap a -> (ByteString -> IO ()) -> ((Int -> Int) -> IO ()) -> Request -> IO (Request, Response)

-- | Post-process a finalized HTTP response:
--   
--   
--   
- fixup content-length header
--   
- properly handle 204/304 responses
--   
- if request was HEAD, remove response body
--   
--   
--   Note that we do NOT deal with transfer-encoding: chunked or
--   "connection: close" here.
fixupResponse :: Request -> Response -> IO Response

-- | Evaluates a Snap monad action.
--   
--   Unlike runSnap, evalSnap evaluates to the value, not the
--   Response. Like runSnap, evalSnap is intended for
--   library writers. Note that there is no meaningful way of evaluating a
--   Snap monad action that contains pass without alternative
--   (i.e. failure), finishWith (i.e. early termination), or
--   escapeHttp (i.e. escaping Snap). In all of those three cases
--   evalSnap throws an IO exception.
evalSnap :: Snap a -> (ByteString -> IO ()) -> ((Int -> Int) -> IO ()) -> Request -> IO a
getParamFrom :: MonadSnap m => (ByteString -> Request -> Maybe [ByteString]) -> ByteString -> m (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 " ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.get "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getParam "foo" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 12:57:20 GMT
--   
--   Just "bar"
--   
getParam :: MonadSnap m => ByteString -> m (Maybe ByteString)

-- | See rqPostParam. Looks up a value for the given named parameter
--   in the POST form parameters mapping in Request. If more than
--   one value was entered for the given parameter name,
--   getPostParam gloms the values together with:
--   intercalate " ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getPostParam "foo" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:01:04 GMT
--   
--   Just "bar"
--   
getPostParam :: MonadSnap m => ByteString -> m (Maybe ByteString)

-- | See rqQueryParam. Looks up a value for the given named
--   parameter in the query string parameters mapping in Request. If
--   more than one value was entered for the given parameter name,
--   getQueryParam gloms the values together with
--   intercalate " ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" M.empty >> T.setQueryStringRaw "foo=bar&foo=baz"
--   ghci> T.runHandler r (getQueryParam "foo" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:06:50 GMT
--   
--   Just "bar baz"
--   
getQueryParam :: MonadSnap m => ByteString -> m (Maybe ByteString)

-- | See rqParams. Convenience function to return Params from
--   the Request inside of a MonadSnap instance.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.get "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getParams >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:02:54 GMT
--   
--   fromList [("foo",["bar"])]
--   
getParams :: MonadSnap m => m Params

-- | See rqParams. Convenience function to return Params from
--   the Request inside of a MonadSnap instance.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getPostParams >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:04:34 GMT
--   
--   fromList [("foo",["bar"])]
--   
getPostParams :: MonadSnap m => m Params

-- | See rqParams. Convenience function to return Params from
--   the Request inside of a MonadSnap instance.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" M.empty >> T.setQueryStringRaw "foo=bar&foo=baz"
--   ghci> T.runHandler r (getQueryParams >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:10:17 GMT
--   
--   fromList [("foo",["bar","baz"])]
--   
getQueryParams :: MonadSnap m => m Params

-- | Gets the HTTP Cookie with the specified name.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let r = T.get "/foo/bar" M.empty >> T.addCookies [cookie]
--   ghci> T.runHandler r (getCookie "name" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 12:16:58 GMT
--   
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   
getCookie :: MonadSnap m => ByteString -> m (Maybe Cookie)

-- | Gets the HTTP Cookie with the specified name and decodes it. If
--   the decoding fails, the handler calls pass.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let r = T.get "/foo/bar" M.empty >> T.addCookies [cookie]
--   ghci> T.runHandler r (readCookie "name" >>= writeBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 12:20:09 GMT
--   
--   value
--   
readCookie :: (MonadSnap m, Readable a) => ByteString -> m a

-- | Expire given Cookie in client's browser.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> let cookie = Cookie "name" "" Nothing (Just "/subsite") Nothing True False
--   ghci> T.runHandler r (expireCookie cookie)
--   HTTP/1.1 200 OK
--   set-cookie: name=; path=/subsite; expires=Sat, 24 Dec 1994 06:28:16 GMT; Secure
--   server: Snap/test
--   
--   date: Thu, 07 Aug 2014 12:21:27 GMT
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let r2 = T.get "/foo/bar" M.empty >> T.addCookies [cookie]
--   ghci> T.runHandler r (getCookie "name" >>= maybe (return ()) expireCookie)
--   HTTP/1.1 200 OK
--   set-cookie: name=; expires=Sat, 24 Dec 1994 06:28:16 GMT
--   server: Snap/test
--   
expireCookie :: MonadSnap m => Cookie -> m ()

-- | Causes the handler thread to be killed n seconds from now.
setTimeout :: MonadSnap m => Int -> m ()

-- | Causes the handler thread to be killed at least n seconds
--   from now.
extendTimeout :: MonadSnap m => Int -> m ()

-- | Modifies the amount of time remaining before the request times out.
modifyTimeout :: MonadSnap m => (Int -> Int) -> m ()

-- | Returns an IO action which you can use to modify the timeout
--   value.
getTimeoutModifier :: MonadSnap m => m ((Int -> Int) -> IO ())
data ResponseBody

-- | output body is a function that writes to a Builder stream
Stream :: StreamProc -> ResponseBody

-- | output body is sendfile(), optional second argument is a byte range to
--   send
SendFile :: FilePath -> Maybe (Word64, Word64) -> ResponseBody

-- | Contains all of the information about an incoming HTTP request.
data Request
Request :: ByteString -> ByteString -> {-# UNPACK #-} !Int -> ByteString -> {-# UNPACK #-} !Int -> ByteString -> !Bool -> Headers -> InputStream ByteString -> !Maybe Word64 -> !Method -> {-# UNPACK #-} !HttpVersion -> [Cookie] -> ByteString -> ByteString -> ByteString -> ByteString -> Params -> Params -> Params -> Request

-- | The server name of the request, as it came in from the request's
--   Host: header.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.get "/foo/bar" M.empty
--   ghci|         T.setHeader "host" "example.com"
--   ghci| :}
--   ghci> rqHostName rq
--   "example.com"
--   
[rqHostName] :: Request -> ByteString

-- | The remote IP address.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqClientAddr `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "127.0.0.1"
--   
[rqClientAddr] :: Request -> ByteString

-- | The remote TCP port number.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqClientPort `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "60000"
--   
[rqClientPort] :: Request -> {-# UNPACK #-} !Int

-- | The local IP address for this request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqServerAddr `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "127.0.0.1"
--   
[rqServerAddr] :: Request -> ByteString

-- | Returns the port number the HTTP server is listening on. This may be
--   useless from the perspective of external requests, e.g. if the server
--   is running behind a proxy.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqServerPort `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   8080
--   
[rqServerPort] :: Request -> {-# UNPACK #-} !Int

-- | Returns the HTTP server's idea of its local hostname, including port.
--   This is as configured with the Config object at startup.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqLocalHostname `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "localhost"
--   
[rqLocalHostname] :: Request -> ByteString

-- | Returns True if this is an HTTPS session.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqIsSecure `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   False
--   
[rqIsSecure] :: Request -> !Bool

-- | Contains all HTTP Headers associated with this request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqHeaders `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   H {unH = [("host","localhost")]}
--   
[rqHeaders] :: Request -> Headers

-- | Actual body of the request.
[rqBody] :: Request -> InputStream ByteString

-- | Returns the Content-Length of the HTTP request body.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqContentLength `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   Nothing
--   
[rqContentLength] :: Request -> !Maybe Word64

-- | Returns the HTTP request method.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqMethod `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   GET
--   
[rqMethod] :: Request -> !Method

-- | Returns the HTTP version used by the client.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqVersion `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   (1,1)
--   
[rqVersion] :: Request -> {-# UNPACK #-} !HttpVersion

-- | Returns a list of the cookies that came in from the HTTP request
--   headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqCookies `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   []
--   
[rqCookies] :: Request -> [Cookie]

-- | Handlers can 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".
--   
--   The following identity holds:
--   
--   
--   rqURI r == S.concat [ rqContextPath r
--                       , rqPathInfo r
--                       , let q = rqQueryString r
--                         in if S.null q
--                              then ""
--                              else S.append "?" q
--                       ]
--   
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqPathInfo `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "foo/bar"
--   
[rqPathInfo] :: Request -> ByteString

-- | The "context path" of the request; catenating rqContextPath,
--   and rqPathInfo should get you back to the original rqURI
--   (ignoring query strings). 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqContextPath `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "/"
--   
[rqContextPath] :: Request -> ByteString

-- | Returns the URI requested by the client.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqURI `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "foo/bar"
--   
[rqURI] :: Request -> ByteString

-- | Returns the HTTP query string for this Request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rq <- T.buildRequest (T.get "/foo/bar" (M.fromList [("name", ["value"])]))
--   ghci> rqQueryString rq
--   "name=value"
--   
[rqQueryString] :: Request -> ByteString

-- | Returns the parameters mapping for this Request. "Parameters"
--   are automatically decoded from the URI's query string and
--   POST body and entered into this mapping. The rqParams
--   value is thus a union of rqQueryParams and rqPostParams.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   
[rqParams] :: Request -> Params

-- | The parameter mapping decoded from the URI's query string.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqQueryParams rq
--   fromList [("baz",["quux"])]
--   
[rqQueryParams] :: Request -> Params

-- | The parameter mapping decoded from the POST body. Note that Snap only
--   auto-decodes POST request bodies when the request's
--   Content-Type is application/x-www-form-urlencoded.
--   For multipart/form-data use handleFileUploads to
--   decode the POST request and fill this mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqPostParams rq
--   fromList [("baz",["qux"])]
--   
[rqPostParams] :: Request -> Params

-- | Represents an HTTP response.
data Response
Response :: Headers -> Map ByteString Cookie -> !Maybe Word64 -> ResponseBody -> !Int -> !ByteString -> !Bool -> Response
[rspHeaders] :: Response -> Headers
[rspCookies] :: Response -> Map ByteString Cookie

-- | We will need to inspect the content length no matter what, and looking
--   up "content-length" in the headers and parsing the number out of the
--   text will be too expensive.
[rspContentLength] :: Response -> !Maybe Word64
[rspBody] :: Response -> ResponseBody

-- | Returns the HTTP status code.
--   
--   Example:
--   
--   
--   ghci> rspStatus emptyResponse
--   200
--   
[rspStatus] :: Response -> !Int

-- | Returns the HTTP status explanation string.
--   
--   Example:
--   
--   
--   ghci> rspStatusReason emptyResponse
--   OK
--   
[rspStatusReason] :: Response -> !ByteString

-- | If true, we are transforming the request body with
--   transformRequestBody
[rspTransformingRqBody] :: Response -> !Bool

-- | A typeclass for datatypes which contain HTTP headers.
class HasHeaders a

-- | Modify the datatype's headers.
updateHeaders :: HasHeaders a => (Headers -> Headers) -> a -> a

-- | Retrieve the headers from a datatype that has headers.
headers :: HasHeaders a => a -> Headers

-- | 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"].
type Params = Map ByteString [ByteString]

-- | Enumerates the HTTP method values (see
--   http://tools.ietf.org/html/rfc2068.html#section-5.1.1).
data Method
GET :: Method
HEAD :: Method
POST :: Method
PUT :: Method
DELETE :: Method
TRACE :: Method
OPTIONS :: Method
CONNECT :: Method
PATCH :: Method
Method :: ByteString -> Method

-- | A datatype representing an HTTP cookie.
data Cookie
Cookie :: !ByteString -> !ByteString -> !Maybe UTCTime -> !Maybe ByteString -> !Maybe ByteString -> !Bool -> !Bool -> Cookie

-- | The name of the cookie.
[cookieName] :: Cookie -> !ByteString

-- | The cookie's string value.
[cookieValue] :: Cookie -> !ByteString

-- | The cookie's expiration value, if it has one.
[cookieExpires] :: Cookie -> !Maybe UTCTime

-- | The cookie's "domain" value, if it has one.
[cookieDomain] :: Cookie -> !Maybe ByteString

-- | The cookie path.
[cookiePath] :: Cookie -> !Maybe ByteString

-- | Tag as secure cookie?
[cookieSecure] :: Cookie -> !Bool

-- | HTTP only?
[cookieHttpOnly] :: Cookie -> !Bool

-- | Represents a (major, minor) version of the HTTP protocol.
type HttpVersion = (Int, Int)

-- | 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.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> addHeader "Host" "localhost" H.empty
--   H {unH = [("host","localhost")]}
--   ghci> addHeader "Host" "127.0.0.1" it
--   H {unH = [("host","localhost,127.0.0.1")]}
--   
addHeader :: HasHeaders a => CI ByteString -> 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.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> setHeader "Host" "localhost" H.empty
--   H {unH = [("host","localhost")]}
--   ghci> setHeader "Host" "127.0.0.1" it
--   H {unH = [("host","127.0.0.1")]}
--   
setHeader :: HasHeaders a => CI ByteString -> ByteString -> a -> a

-- | Gets a header value out of a HasHeaders datatype.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> getHeader "Host" $ setHeader "Host" "localhost" H.empty
--   Just "localhost"
--   
getHeader :: HasHeaders a => CI ByteString -> a -> Maybe ByteString

-- | Lists all the headers out of a HasHeaders datatype. If many
--   headers came in with the same name, they will be catenated together.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> listHeaders $ setHeader "Host" "localhost" H.empty
--   [("host","localhost")]
--   
listHeaders :: HasHeaders a => a -> [(CI ByteString, ByteString)]

-- | Clears a header value from a HasHeaders datatype.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> deleteHeader "Host" $ setHeader "Host" "localhost" H.empty
--   H {unH = []}
--   
deleteHeader :: HasHeaders a => CI ByteString -> a -> a

-- | 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".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParam "baz" rq
--   Just ["qux","quux"]
--   
rqParam :: ByteString -> Request -> Maybe [ByteString]

-- | Looks up the value(s) for the given named parameter in the POST
--   parameters mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqPostParam "baz" rq
--   Just ["qux"]
--   
rqPostParam :: ByteString -> Request -> Maybe [ByteString]

-- | Looks up the value(s) for the given named parameter in the query
--   parameters mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqQueryParam "baz" rq
--   Just ["quux"]
--   
rqQueryParam :: ByteString -> Request -> Maybe [ByteString]

-- | Modifies the parameters mapping (which is a Map ByteString
--   ByteString) in a Request using the given function.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   ghci> rqParams $ rqModifyParams (M.delete "baz") rq
--   fromList []
--   
rqModifyParams :: (Params -> Params) -> Request -> Request

-- | Writes a key-value pair to the parameters mapping within the given
--   request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   ghci> rqParams $ rqSetParam "baz" ["corge"] rq
--   fromList [("baz", ["corge"])]
--   
rqSetParam :: ByteString -> [ByteString] -> Request -> Request

-- | An empty Response.
--   
--   Example:
--   
--   
--   ghci> emptyResponse
--   HTTP/1.1 200 OK
--   
emptyResponse :: Response

-- | Sets the HTTP response code.
--   
--   Example:
--   
--   
--   ghci> setResponseCode 404 emptyResponse
--   HTTP/1.1 404 Not Found
--   
setResponseCode :: Int -> Response -> Response

-- | Sets the HTTP response status. Note: normally you would use
--   setResponseCode unless you needed a custom response
--   explanation.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> setResponseStatus 500 "Internal Server Error" emptyResponse
--   HTTP/1.1 500 Internal Server Error
--   
setResponseStatus :: Int -> ByteString -> Response -> Response

-- | Sets the Content-Type in the Response headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> setContentType "text/html" emptyResponse
--   HTTP/1.1 200 OK
--   content-type: text/html
--   
setContentType :: ByteString -> Response -> Response

-- | Adds an HTTP Cookie to Response headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> getResponseCookie "name" $ addResponseCookie cookie emptyResponse
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   
addResponseCookie :: Cookie -> Response -> Response

-- | Gets an HTTP Cookie with the given name from Response
--   headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> getResponseCookie "cookie-name" emptyResponse
--   Nothing
--   
getResponseCookie :: ByteString -> Response -> Maybe Cookie

-- | Returns a list of Cookies present in Response
--   
--   Example:
--   
--   
--   ghci> getResponseCookies emptyResponse
--   []
--   
getResponseCookies :: Response -> [Cookie]

-- | Deletes an HTTP Cookie from the Response headers. Please
--   note this does not necessarily erase the cookie from the client
--   browser.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let rsp    = addResponseCookie cookie emptyResponse
--   ghci> getResponseCookie "name" rsp
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   ghci> getResponseCookie "name" $ deleteResponseCookie "name" rsp
--   Nothing
--   
deleteResponseCookie :: ByteString -> Response -> Response

-- | Modifies an HTTP Cookie with given name in Response
--   headers. Nothing will happen if a matching Cookie can not be
--   found in Response.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import Data.Monoid
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let rsp    = addResponseCookie cookie emptyResponse
--   ghci> getResponseCookie "name" rsp
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   ghci> let f ck@(Cookie { cookieName = name }) = ck { cookieName = name <> "'"}
--   ghci> let rsp' = modifyResponseCookie "name" f rsp
--   ghci> getResponseCookie "name'" rsp'
--   Just (Cookie {cookieName = "name'", ...})
--   ghci> getResponseCookie "name" rsp'
--   Just (Cookie {cookieName = "name", ...})
--   
modifyResponseCookie :: ByteString -> (Cookie -> Cookie) -> 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.
--   
--   Example:
--   
--   
--   ghci> setContentLength 400 emptyResponse
--   HTTP/1.1 200 OK
--   Content-Length: 400
--   
setContentLength :: Word64 -> Response -> Response

-- | Removes any Content-Length set in the Response.
--   
--   Example:
--   
--   
--   ghci> clearContentLength $ setContentLength 400 emptyResponse
--   HTTP/1.1 200 OK
--   
clearContentLength :: Response -> Response

-- | Sets an HTTP response body to the given stream procedure.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> r
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   
setResponseBody :: (OutputStream Builder -> IO (OutputStream Builder)) -> Response -> Response

-- | Modifies a response body.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> r
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   ghci> :{
--   ghci| let r' = modifyResponseBody
--   ghci|          (f out -> do
--   ghci|              out' <- f out
--   ghci|              Streams.write (Just $ Builder.byteString "\nBye, world!") out'
--   ghci|              return out') r
--   ghci| :}
--   ghci> r'
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   Bye, world!
--   
modifyResponseBody :: ((OutputStream Builder -> IO (OutputStream Builder)) -> OutputStream Builder -> IO (OutputStream Builder)) -> Response -> Response

-- | Convert a CTime into an HTTP timestamp.
--   
--   Example:
--   
--   
--   ghci> formatHttpTime . fromIntegral $ 10
--   "Thu, 01 Jan 1970 00:00:10 GMT"
--   
formatHttpTime :: CTime -> IO ByteString

-- | Converts an HTTP timestamp into a CTime.
--   
--   If the given time string is unparseable, this function will return 0.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> parseHttpTime "Thu, 01 Jan 1970 00:00:10 GMT"
--   10
--   
parseHttpTime :: ByteString -> IO CTime
type StreamProc = OutputStream Builder -> IO OutputStream Builder

-- | Convert a CTime into common log entry format.
formatLogTime :: CTime -> IO ByteString

-- | Equate the special case constructors with their corresponding
--   Method name variant.
normalizeMethod :: Method -> Method
rspBodyMap :: (StreamProc -> StreamProc) -> ResponseBody -> ResponseBody
rspBodyToEnum :: ResponseBody -> StreamProc

-- | Adapted from:
--   
--   
--   https://www.iana.org/assignments/http-status-codes/http-status-codes.txt
statusReasonMap :: IntMap ByteString
instance GHC.Internal.Base.Alternative Snap.Internal.Core.Snap
instance GHC.Internal.Base.Applicative Snap.Internal.Core.Snap
instance GHC.Classes.Eq Snap.Internal.Core.NoHandlerException
instance GHC.Internal.Exception.Type.Exception Snap.Internal.Core.EscapeSnap
instance GHC.Internal.Exception.Type.Exception Snap.Internal.Core.NoHandlerException
instance GHC.Internal.Base.Functor Snap.Internal.Core.Snap
instance Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO Snap.Internal.Core.Snap
instance Control.Monad.Base.MonadBase GHC.Types.IO Snap.Internal.Core.Snap
instance GHC.Internal.Control.Monad.Fail.MonadFail Snap.Internal.Core.Snap
instance Control.Monad.IO.Class.MonadIO Snap.Internal.Core.Snap
instance GHC.Internal.Base.MonadPlus Snap.Internal.Core.Snap
instance GHC.Internal.Base.Monad Snap.Internal.Core.Snap
instance Snap.Internal.Core.MonadSnap Snap.Internal.Core.Snap
instance GHC.Internal.Show.Show Snap.Internal.Core.EscapeSnap
instance GHC.Internal.Show.Show Snap.Internal.Core.NoHandlerException

-- | 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.
module Snap.Core

-- | Snap is the Monad that user web handlers run in.
--   Snap gives you:
--   
--   
--   
- Stateful access to fetch or modify an HTTP
--   Request.
printRqContextPath :: Snap () printRqContextPath =
--   writeBS . rqContextPath =<< getRequest
--   

--   
- Stateful access to fetch or modify an HTTP
--   Response.
printRspStatusReason :: Snap ()
--   printRspStatusReason = writeBS . rspStatusReason
--   =<< getResponse 

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

--   
- Convenience functions (writeBS, writeLBS,
--   writeText, writeLazyText, addToOutput) for
--   queueing output to be written to the Response, or for streaming
--   to the response using io-streams:
example ::
--   (OutputStream Builder -> IO (OutputStream
--   Builder)) -> Snap () example streamProc = do writeBS
--   "I'm a strict bytestring" writeLBS "I'm a lazy bytestring"
--   writeText "I'm strict text" addToOutput streamProc
--   

--   
- 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 the supplied Response value will be returned from
--   runSnap as-is.
--   
- Access to the IO monad through a MonadIO
--   instance:
a :: Snap () a = liftIO fireTheMissiles
--   

--   
- The ability to set or extend a timeout which will kill the handler
--   thread after N seconds of inactivity (the default is 20
--   seconds):
a :: Snap () a = setTimeout 30 

--   
- Throw and catch exceptions using a MonadBaseControl
--   instance:
import Control.Exception.Lifted
--   (SomeException, throwIO, catch) foo :: Snap ()
--   foo = bar `catch` (e::SomeException) -> baz where bar =
--   throwIO FooException 

--   
- Log a message to the error log:
foo :: Snap () foo =
--   logError "grumble." 

--   
--   
--   You may notice that most of the type signatures in this module contain
--   a (MonadSnap m) => ... typeclass constraint.
--   MonadSnap is a typeclass which, in essence, says "you can get
--   back to the Snap monad from here". Using MonadSnap you
--   can extend the Snap monad with additional functionality and
--   still have access to most of the Snap functions without writing
--   lift everywhere. Instances are already provided for most of the
--   common monad transformers (ReaderT, WriterT,
--   StateT, etc.).
data Snap a

-- | Runs a Snap monad action.
--   
--   This function is mostly intended for library writers; instead of
--   invoking runSnap directly, use httpServe or
--   runHandler (for testing).
runSnap :: Snap a -> (ByteString -> IO ()) -> ((Int -> Int) -> IO ()) -> Request -> IO (Request, Response)

-- | MonadSnap is a type class, analogous to MonadIO for
--   IO, that makes it easy to wrap Snap inside monad
--   transformers.
class (Monad m, MonadIO m, MonadBaseControl IO m, MonadPlus m, Functor m, Applicative m, Alternative m) => MonadSnap (m :: Type -> Type)

-- | Lift a computation from the Snap monad.
liftSnap :: MonadSnap m => Snap a -> m a

-- | This exception is thrown if the handler you supply to runSnap
--   fails.
data NoHandlerException
NoHandlerException :: String -> NoHandlerException

-- | This function brackets a Snap action in resource acquisition and
--   release. This is provided because MonadCatchIO's bracket
--   function doesn't work properly in the case of a short-circuit return
--   from the action being bracketed.
--   
--   In order to prevent confusion regarding the effects of the aquisition
--   and release actions on the Snap state, this function doesn't accept
--   Snap actions for the acquire or release actions.
--   
--   This function will run the release action in all cases where the
--   acquire action succeeded. This includes the following behaviors from
--   the bracketed Snap action.
--   
--   
--   
- Normal completion
--   
- Short-circuit completion, either from calling fail or
--   finishWith
--   
- An exception being thrown.
--   
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let br = bracketSnap (putStrLn "before") (const $ putStrLn "after")
--   ghci> T.runHandler (T.get "/" M.empty) (br $ const $ writeBS "OK")
--   before
--   after
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 18:41:50 GMT
--   
--   OK
--   
bracketSnap :: IO a -> (a -> IO b) -> (a -> Snap c) -> Snap c

-- | Short-circuits a Snap monad action early, storing the given
--   Response value in its state.
--   
--   IMPORTANT: Be vary careful when using this with things like a DB
--   library's withTransaction function or any other kind of
--   setup/teardown block, as it can prevent the cleanup from being called
--   and result in resource leaks.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import Control.Applicative
--   ghci> let r = T.get "/" M.empty
--   ghci> T.runHandler r ((ifTop $ writeBS "TOP") <|> finishWith emptyResponse)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 16:58:57 GMT
--   
--   TOP
--   ghci> let r' = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r' ((ifTop $ writeBS "TOP") <|> finishWith emptyResponse)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 17:50:50 GMT
--   
finishWith :: MonadSnap m => Response -> m a

-- | Capture the flow of control in case a handler calls finishWith.
--   
--   WARNING: in the event of a call to transformRequestBody
--   it is possible to violate HTTP protocol safety when using this
--   function. If you call catchFinishWith it is suggested that you
--   do not modify the body of the Response which was passed to the
--   finishWith call.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import Control.Applicative
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> let h = (ifTop $ writeBS "TOP") <|> finishWith emptyResponse
--   ghci> T.runHandler r (catchFinishWith h >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 18:35:42 GMT
--   
--   Left HTTP/1.1 200 OK
--   
catchFinishWith :: Snap a -> Snap (Either Response 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r pass
--   HTTP/1.1 404 Not Found
--   server: Snap/test
--   date: Thu, 07 Aug 2014 13:35:42 GMT
--   
--   <!DOCTYPE html>
--   <html>
--   <head>
--   <title>Not found</title>
--   </head>
--   <body>
--   <code>No handler accepted "/foo/bar"/code
--   </body></html>
--   
pass :: MonadSnap m => m a

-- | Type of external handler passed to escapeHttp.
type EscapeHttpHandler = Int -> Int -> IO () -> InputStream ByteString -> OutputStream Builder -> IO ()

-- | Used internally to implement escapeHttp.
data EscapeSnap
TerminateConnection :: SomeException -> EscapeSnap
EscapeHttp :: EscapeHttpHandler -> EscapeSnap

-- | Terminate the HTTP session and hand control to some external handler,
--   escaping all further HTTP traffic.
--   
--   The external handler takes three arguments: a function to modify the
--   thread's timeout, and a read and a write ends to the socket.
escapeHttp :: MonadSnap m => EscapeHttpHandler -> m ()

-- | Terminate the HTTP session with the given exception.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Control.Exception as E
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (terminateConnection $ E.AssertionFailed "Assertion failed!")
--   *** Exception: <terminated: Assertion failed!>
--   
terminateConnection :: (Exception e, MonadSnap m) => e -> m a

-- | Runs a Snap monad action only if the request's HTTP method
--   matches the given method.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (method GET $ writeBS "OK")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 13:38:48 GMT
--   
--   OK
--   ghci> T.runHandler r (method POST $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
method :: MonadSnap m => Method -> m a -> m a

-- | Runs a Snap monad action only if the request's HTTP method
--   matches one of the given methods.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (methods [GET, POST] $ writeBS "OK")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 13:38:48 GMT
--   
--   OK
--   ghci> T.runHandler r (methods [POST] $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
methods :: MonadSnap m => [Method] -> m a -> m 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> T.runHandler (T.get "/foo" M.empty) (path "foo" $ writeBS "bar")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:15:42 GMT
--   
--   bar
--   ghci> T.runHandler (T.get "/foo" M.empty) (path "bar" $ writeBS "baz")
--   HTTP/1.1 404 Not Found
--   ...
--   
path :: MonadSnap m => ByteString -> m a -> m a

-- | Runs a Snap monad action only when the first path component is
--   successfully parsed as the argument to the supplied handler function.
--   
--   Note that the path segment is url-decoded prior to being passed to
--   fromBS; this is new as of snap-core 0.10.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/11/foo/bar" M.empty
--   ghci> let f = (\i -> if i == 11 then writeBS "11" else writeBS "???")
--   ghci> T.runHandler r (pathArg f)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:27:10 GMT
--   
--   11
--   ghci> let r' = T.get "/foo/11/bar" M.empty
--   ghci> T.runHandler r' (pathArg f)
--   HTTP/1.1 404 Not Found
--   ...
--   
pathArg :: (Readable a, MonadSnap m) => (a -> m b) -> m b

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (dir "foo" $ writeBS "OK")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:52:24 GMT
--   
--   OK
--   ghci> T.runHandler r (dir "baz" $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
dir :: MonadSnap m => ByteString -> m a -> m a

-- | Runs a Snap monad action only when rqPathInfo is empty.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/" M.empty
--   ghci> T.runHandler r (ifTop $ writeBS OK)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 14:56:39 GMT
--   
--   OK
--   ghci> let r' = T.get "/foo" M.empty
--   ghci> T.runHandler r' (ifTop $ writeBS "OK")
--   HTTP/1.1 404 Not Found
--   ...
--   
ifTop :: MonadSnap m => m a -> m a

-- | A web handler which, given a mapping from URL entry points to web
--   handlers, efficiently routes requests to the correct handler.
--   
--   Usage
--   
--   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) ]
--   
--   
--   Note: URL decoding
--   
--   A short note about URL decoding: path matching and variable capture
--   are done on decoded URLs, but the contents of
--   rqContextPath and rqPathInfo will contain the original
--   encoded URL, i.e. what the user entered. For example, in the following
--   scenario:
--   
--   
--   route [ ("a b c d/", foo ) ]
--   
--   
--   A request for "/a+b+c+d" will be sent to foo with
--   rqContextPath set to "a+b+c+d".
--   
--   This behaviour changed as of Snap 0.6.1; previous versions had
--   unspecified (and buggy!) semantics here.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as Map
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import Snap.Test
--   ghci> :{
--   ghci| let handler = do r <- getRequest
--   ghci|                  writeBS $ "rqContextPath: " <> rqContextPath r <> "\n"
--   ghci|                  writeBS $ "rqPathInfo: " <> rqPathInfo r <> "\n"
--   ghci|                  writeBS $ "rqParams: " <> (B8.pack . show $ rqParams r)
--   ghci| :}
--   ghci> runHandler (get "/foo/bar" "Map.empty") (route [("foo", handler)])
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 05:16:59 GMT
--   
--   rqContextPath: /foo/
--   rqPathInfo: bar
--   rqParams: fromList []
--   ghci> runHandler (get "/foo/bar" "Map.empty") (route [("foo/:bar", handler)])
--   [...]
--   
--   rqContextPath: /foo/bar/
--   rqPathInfo:
--   rqParams: fromList [("bar",["bar"])]
--   
route :: MonadSnap m => [(ByteString, m a)] -> m 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import Snap.Test
--   ghci> :{
--   ghci| let handler = do r <- getRequest
--   ghci|                  writeBS $ "rqContextPath: " <> rqContextPath r <> "\n"
--   ghci|                  writeBS $ "rqPathInfo: " <> rqPathInfo r <> "\n"
--   ghci|                  writeBS $ "rqParams: " <> (B8.pack . show $ rqParams r)
--   ghci| :}
--   ghci> runHandler (get "/foo/bar" M.empty) (routeLocal [("foo", handler)])
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 05:17:28 GMT
--   
--   rqContextPath: /
--   rqPathInfo: foo/bar
--   ghci> runHandler (get "/foo/bar" M.empty) (routeLocal [("foo/:bar", handler)])
--   [...]
--   
--   rqContextPath: /
--   rqPathInfo: foo/bar
--   rqParams: fromList [("bar",["bar"])]
--   
routeLocal :: MonadSnap m => [(ByteString, m a)] -> m a

-- | Grabs the Request object out of the Snap monad.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS . rqURI =<< getRequest)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 07:51:54 GMT
--   
--   /foo/bar
--   
getRequest :: MonadSnap m => m Request

-- | Grabs something out of the Request object, using the given
--   projection function. See gets.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS =<< getsRequest rqURI)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 07:51:54 GMT
--   
--   /foo/bar
--   
getsRequest :: MonadSnap m => (Request -> a) -> m a

-- | Grabs the Response object out of the Snap monad.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS . rspStatusReason =<< getResponse)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Sat, 02 Aug 2014 15:06:00 GMT
--   
--   OK
--   
getResponse :: MonadSnap m => m Response

-- | Grabs something out of the Response object, using the given
--   projection function. See gets.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS =<< getsResponse rspStatusReason)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 13:35:45 GMT
--   
--   OK
--   
getsResponse :: MonadSnap m => (Response -> a) -> m a

-- | Puts a new Request object into the Snap monad. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> :{
--   ghci| let hndlr = do rq <- T.buildRequest (T.get "/bar/foo" M.empty)
--   ghci|                putRequest rq
--   ghci|                uri' <- getsRequest rqURI
--   ghci|                writeBS uri'
--   ghci| :}
--   ghci> T.runHandler (T.get "/foo/bar" M.empty) hndlr
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:13:46 GMT
--   
--   /bar/foo
--   
putRequest :: MonadSnap m => Request -> m ()

-- | Puts a new Response object into the Snap monad.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let rsp = setResponseCode 404 emptyResponse
--   ghci> let req = T.get "/foo/bar" M.empty
--   ghci> T.runHandler req (putResponse rsp)
--   HTTP/1.1 404 Not Found
--   server: Snap/test
--   date: Wed, 06 Aug 2014 13:59:58 GMT
--   
putResponse :: MonadSnap m => Response -> m ()

-- | Modifies the Request object stored in a Snap monad.
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> r' <- T.buildRequest $ T.get "/bar/foo" M.empty
--   ghci> T.runHandler r (modifyRequest (const r') >> getsRequest rqURI >>= writeBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:24:25 GMT
--   
--   /bar/foo
--   
modifyRequest :: MonadSnap m => (Request -> Request) -> m ()

-- | Modifes the Response object stored in a Snap monad.
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (modifyResponse $ setResponseCode 404)
--   HTTP/1.1 404 Not Found
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:27:11 GMT
--   
modifyResponse :: MonadSnap m => (Response -> Response) -> m ()

-- | 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. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> r' <- T.buildRequest $ T.get "/bar/foo" M.empty
--   ghci> let printRqURI = getsRequest rqURI >>= writeBS >> writeBS "\n"
--   ghci> T.runHandler r (printRqURI >> localRequest (const r') printRqURI)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:34:12 GMT
--   
--   /foo/bar
--   /bar/foo
--   
localRequest :: MonadSnap m => (Request -> Request) -> m a -> m a

-- | Fetches the Request from state and hands it to the given
--   action. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import Control.Monad.IO.Class
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> let h = withRequest (\rq -> liftIO (T.requestToString rq) >>= writeBS)
--   ghci> T.runHandler r h
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:44:24 GMT
--   
--   GET /foo/bar HTTP/1.1
--   host: localhost
--   
withRequest :: MonadSnap m => (Request -> m a) -> m a

-- | Fetches the Response from state and hands it to the given
--   action. Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (withResponse $ writeBS . rspStatusReason)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 15:48:45 GMT
--   
--   OK
--   
withResponse :: MonadSnap m => (Response -> m a) -> m a

-- | Log an error message in the Snap monad.
--   
--   Example:
--   
--   
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> runSnap (logError "fatal error!") (error . B8.unpack) undefined undefined
--   *** Exception: fatal error!
--   
logError :: MonadSnap m => ByteString -> m ()

-- | Pass the request body stream to a consuming procedure, returning the
--   result.
--   
--   If the consuming procedure you pass in here throws an exception, Snap
--   will attempt to clear the rest of the unread request body (using
--   skipToEof) before rethrowing the exception. If you used
--   terminateConnection, however, Snap will give up and immediately
--   close the socket.
--   
--   To prevent slowloris attacks, the connection will be also terminated
--   if the input socket produces data too slowly (500 bytes per second is
--   the default limit).
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import qualified Data.ByteString.Lazy as L
--   ghci> import Data.Char (toUpper)
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> let r = T.put "/foo" "text/plain" "some text"
--   ghci> :{
--   ghci| let f s = do u <- Streams.map (B8.map toUpper) s
--   ghci|              l <- Streams.toList u
--   ghci|              return $ L.fromChunks l
--   ghci| :}
--   ghci> T.runHandler r (runRequestBody f >>= writeLBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 20:48:40 GMT
--   
--   SOME TEXT
--   
runRequestBody :: MonadSnap m => (InputStream ByteString -> IO a) -> m a

-- | Returns the request body as a lazy bytestring. /Note that the request
--   is not actually provided lazily!/
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.put "/foo" "text/plain" "some text"
--   ghci> T.runHandler r (readRequestBody 2048 >>= writeLBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 20:08:44 GMT
--   
--   some text
--   
--   
--   Since: 0.6
readRequestBody :: MonadSnap m => Word64 -> m ByteString

-- | Normally Snap is careful to ensure that the request body is fully
--   consumed after your web handler runs, but before the Response
--   body 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.
--   
--   Take care: in order for this to work, the HTTP client must be written
--   with input-to-output streaming in mind.
--   
--   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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> import Data.Char (toUpper)
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> let r = T.put "/foo" "text/plain" "some text"
--   ghci> let f = Streams.map (B8.map toUpper)
--   ghci> T.runHandler r (transformRequestBody f >> readRequestBody 2048 >>= writeLBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 20:30:15 GMT
--   
--   SOME TEXT
--   
transformRequestBody :: (InputStream ByteString -> IO (InputStream ByteString)) -> Snap ()

-- | Contains all of the information about an incoming HTTP request.
data Request

-- | Represents an HTTP response.
data Response

-- | A key-value map that represents a collection of HTTP header fields.
--   Keys are case-insensitive.
data Headers

-- | A typeclass for datatypes which contain HTTP headers.
class HasHeaders a

-- | Modify the datatype's headers.
updateHeaders :: HasHeaders a => (Headers -> Headers) -> a -> a

-- | Retrieve the headers from a datatype that has headers.
headers :: HasHeaders a => a -> Headers

-- | 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"].
type Params = Map ByteString [ByteString]

-- | Enumerates the HTTP method values (see
--   http://tools.ietf.org/html/rfc2068.html#section-5.1.1).
data Method
GET :: Method
HEAD :: Method
POST :: Method
PUT :: Method
DELETE :: Method
TRACE :: Method
OPTIONS :: Method
CONNECT :: Method
PATCH :: Method
Method :: ByteString -> Method

-- | A datatype representing an HTTP cookie.
data Cookie
Cookie :: !ByteString -> !ByteString -> !Maybe UTCTime -> !Maybe ByteString -> !Maybe ByteString -> !Bool -> !Bool -> Cookie

-- | The name of the cookie.
[cookieName] :: Cookie -> !ByteString

-- | The cookie's string value.
[cookieValue] :: Cookie -> !ByteString

-- | The cookie's expiration value, if it has one.
[cookieExpires] :: Cookie -> !Maybe UTCTime

-- | The cookie's "domain" value, if it has one.
[cookieDomain] :: Cookie -> !Maybe ByteString

-- | The cookie path.
[cookiePath] :: Cookie -> !Maybe ByteString

-- | Tag as secure cookie?
[cookieSecure] :: Cookie -> !Bool

-- | HTTP only?
[cookieHttpOnly] :: Cookie -> !Bool

-- | Represents a (major, minor) version of the HTTP protocol.
type HttpVersion = (Int, Int)

-- | 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.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> addHeader "Host" "localhost" H.empty
--   H {unH = [("host","localhost")]}
--   ghci> addHeader "Host" "127.0.0.1" it
--   H {unH = [("host","localhost,127.0.0.1")]}
--   
addHeader :: HasHeaders a => CI ByteString -> 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.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> setHeader "Host" "localhost" H.empty
--   H {unH = [("host","localhost")]}
--   ghci> setHeader "Host" "127.0.0.1" it
--   H {unH = [("host","127.0.0.1")]}
--   
setHeader :: HasHeaders a => CI ByteString -> ByteString -> a -> a

-- | Gets a header value out of a HasHeaders datatype.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> getHeader "Host" $ setHeader "Host" "localhost" H.empty
--   Just "localhost"
--   
getHeader :: HasHeaders a => CI ByteString -> a -> Maybe ByteString

-- | Lists all the headers out of a HasHeaders datatype. If many
--   headers came in with the same name, they will be catenated together.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> listHeaders $ setHeader "Host" "localhost" H.empty
--   [("host","localhost")]
--   
listHeaders :: HasHeaders a => a -> [(CI ByteString, ByteString)]

-- | Clears a header value from a HasHeaders datatype.
--   
--   Example:
--   
--   
--   ghci> import qualified Snap.Types.Headers as H
--   ghci> deleteHeader "Host" $ setHeader "Host" "localhost" H.empty
--   H {unH = []}
--   
deleteHeader :: HasHeaders a => CI ByteString -> a -> a

-- | 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 :: MonadSnap m => m ()

-- | 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.
ipHeaderFilter' :: MonadSnap m => CI ByteString -> m ()

-- | Contains all HTTP Headers associated with this request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqHeaders `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   H {unH = [("host","localhost")]}
--   
rqHeaders :: Request -> Headers

-- | The server name of the request, as it came in from the request's
--   Host: header.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.get "/foo/bar" M.empty
--   ghci|         T.setHeader "host" "example.com"
--   ghci| :}
--   ghci> rqHostName rq
--   "example.com"
--   
rqHostName :: Request -> ByteString

-- | The remote IP address.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqClientAddr `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "127.0.0.1"
--   
rqClientAddr :: Request -> ByteString

-- | The remote TCP port number.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqClientPort `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "60000"
--   
rqClientPort :: Request -> Int

-- | The local IP address for this request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqServerAddr `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "127.0.0.1"
--   
rqServerAddr :: Request -> ByteString

-- | Returns the port number the HTTP server is listening on. This may be
--   useless from the perspective of external requests, e.g. if the server
--   is running behind a proxy.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqServerPort `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   8080
--   
rqServerPort :: Request -> Int

-- | Returns the HTTP server's idea of its local hostname, including port.
--   This is as configured with the Config object at startup.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqLocalHostname `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "localhost"
--   
rqLocalHostname :: Request -> ByteString

-- | Returns True if this is an HTTPS session.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqIsSecure `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   False
--   
rqIsSecure :: Request -> Bool

-- | Returns the Content-Length of the HTTP request body.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqContentLength `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   Nothing
--   
rqContentLength :: Request -> Maybe Word64

-- | Returns the HTTP request method.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqMethod `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   GET
--   
rqMethod :: Request -> Method

-- | Returns the HTTP version used by the client.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqVersion `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   (1,1)
--   
rqVersion :: Request -> HttpVersion

-- | Returns a list of the cookies that came in from the HTTP request
--   headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqCookies `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   []
--   
rqCookies :: Request -> [Cookie]

-- | Handlers can 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".
--   
--   The following identity holds:
--   
--   
--   rqURI r == S.concat [ rqContextPath r
--                       , rqPathInfo r
--                       , let q = rqQueryString r
--                         in if S.null q
--                              then ""
--                              else S.append "?" q
--                       ]
--   
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqPathInfo `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "foo/bar"
--   
rqPathInfo :: Request -> ByteString

-- | The "context path" of the request; catenating rqContextPath,
--   and rqPathInfo should get you back to the original rqURI
--   (ignoring query strings). 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqContextPath `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "/"
--   
rqContextPath :: Request -> ByteString

-- | Returns the URI requested by the client.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rqURI `fmap` T.buildRequest (T.get "/foo/bar" M.empty)
--   "foo/bar"
--   
rqURI :: Request -> ByteString

-- | Returns the HTTP query string for this Request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> rq <- T.buildRequest (T.get "/foo/bar" (M.fromList [("name", ["value"])]))
--   ghci> rqQueryString rq
--   "name=value"
--   
rqQueryString :: Request -> ByteString

-- | Returns the parameters mapping for this Request. "Parameters"
--   are automatically decoded from the URI's query string and
--   POST body and entered into this mapping. The rqParams
--   value is thus a union of rqQueryParams and rqPostParams.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   
rqParams :: Request -> Params

-- | The parameter mapping decoded from the URI's query string.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqQueryParams rq
--   fromList [("baz",["quux"])]
--   
rqQueryParams :: Request -> Params

-- | The parameter mapping decoded from the POST body. Note that Snap only
--   auto-decodes POST request bodies when the request's
--   Content-Type is application/x-www-form-urlencoded.
--   For multipart/form-data use handleFileUploads to
--   decode the POST request and fill this mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqPostParams rq
--   fromList [("baz",["qux"])]
--   
rqPostParams :: Request -> Params

-- | 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".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParam "baz" rq
--   Just ["qux","quux"]
--   
rqParam :: ByteString -> Request -> Maybe [ByteString]

-- | Looks up the value(s) for the given named parameter in the POST
--   parameters mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqPostParam "baz" rq
--   Just ["qux"]
--   
rqPostParam :: ByteString -> Request -> Maybe [ByteString]

-- | Looks up the value(s) for the given named parameter in the query
--   parameters mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqQueryParam "baz" rq
--   Just ["quux"]
--   
rqQueryParam :: ByteString -> Request -> 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 " ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.get "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getParam "foo" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 12:57:20 GMT
--   
--   Just "bar"
--   
getParam :: MonadSnap m => ByteString -> m (Maybe ByteString)

-- | See rqPostParam. Looks up a value for the given named parameter
--   in the POST form parameters mapping in Request. If more than
--   one value was entered for the given parameter name,
--   getPostParam gloms the values together with:
--   intercalate " ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getPostParam "foo" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:01:04 GMT
--   
--   Just "bar"
--   
getPostParam :: MonadSnap m => ByteString -> m (Maybe ByteString)

-- | See rqQueryParam. Looks up a value for the given named
--   parameter in the query string parameters mapping in Request. If
--   more than one value was entered for the given parameter name,
--   getQueryParam gloms the values together with
--   intercalate " ".
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" M.empty >> T.setQueryStringRaw "foo=bar&foo=baz"
--   ghci> T.runHandler r (getQueryParam "foo" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:06:50 GMT
--   
--   Just "bar baz"
--   
getQueryParam :: MonadSnap m => ByteString -> m (Maybe ByteString)

-- | See rqParams. Convenience function to return Params from
--   the Request inside of a MonadSnap instance.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.get "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getParams >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:02:54 GMT
--   
--   fromList [("foo",["bar"])]
--   
getParams :: MonadSnap m => m Params

-- | See rqParams. Convenience function to return Params from
--   the Request inside of a MonadSnap instance.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" $ M.fromList [("foo", ["bar"])]
--   ghci> T.runHandler r (getPostParams >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:04:34 GMT
--   
--   fromList [("foo",["bar"])]
--   
getPostParams :: MonadSnap m => m Params

-- | See rqParams. Convenience function to return Params from
--   the Request inside of a MonadSnap instance.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let r = T.postUrlEncoded "/foo/bar" M.empty >> T.setQueryStringRaw "foo=bar&foo=baz"
--   ghci> T.runHandler r (getQueryParams >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Mon, 11 Aug 2014 13:10:17 GMT
--   
--   fromList [("foo",["bar","baz"])]
--   
getQueryParams :: MonadSnap m => m Params

-- | Modifies the parameters mapping (which is a Map ByteString
--   ByteString) in a Request using the given function.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   ghci> rqParams $ rqModifyParams (M.delete "baz") rq
--   fromList []
--   
rqModifyParams :: (Params -> Params) -> Request -> Request

-- | Writes a key-value pair to the parameters mapping within the given
--   request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| rq <- T.buildRequest $ do
--   ghci|         T.postUrlEncoded "/foo/bar" $ M.fromList [("baz", ["qux"])]
--   ghci|         T.setQueryStringRaw "baz=quux"
--   ghci| :}
--   ghci> rqParams rq
--   fromList [("baz",["qux","quux"])]
--   ghci> rqParams $ rqSetParam "baz" ["corge"] rq
--   fromList [("baz", ["corge"])]
--   
rqSetParam :: ByteString -> [ByteString] -> Request -> Request

-- | See rqClientAddr.

-- | Deprecated: (snap-core >= 1.0.0.0) please use
--   rqClientAddr, this will be removed in 1.1.*
rqRemoteAddr :: Request -> ByteString

-- | See rqClientPort.

-- | Deprecated: (snap-core >= 1.0.0.0) please use
--   rqClientPort, this will be removed in 1.1.*
rqRemotePort :: Request -> Int

-- | An empty Response.
--   
--   Example:
--   
--   
--   ghci> emptyResponse
--   HTTP/1.1 200 OK
--   
emptyResponse :: Response

-- | Sets the HTTP response code.
--   
--   Example:
--   
--   
--   ghci> setResponseCode 404 emptyResponse
--   HTTP/1.1 404 Not Found
--   
setResponseCode :: Int -> Response -> Response

-- | Sets the HTTP response status. Note: normally you would use
--   setResponseCode unless you needed a custom response
--   explanation.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> setResponseStatus 500 "Internal Server Error" emptyResponse
--   HTTP/1.1 500 Internal Server Error
--   
setResponseStatus :: Int -> ByteString -> Response -> Response

-- | Returns the HTTP status code.
--   
--   Example:
--   
--   
--   ghci> rspStatus emptyResponse
--   200
--   
rspStatus :: Response -> Int

-- | Returns the HTTP status explanation string.
--   
--   Example:
--   
--   
--   ghci> rspStatusReason emptyResponse
--   OK
--   
rspStatusReason :: Response -> ByteString

-- | Sets the Content-Type in the Response headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> setContentType "text/html" emptyResponse
--   HTTP/1.1 200 OK
--   content-type: text/html
--   
setContentType :: ByteString -> Response -> Response

-- | Adds an HTTP Cookie to Response headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> getResponseCookie "name" $ addResponseCookie cookie emptyResponse
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   
addResponseCookie :: Cookie -> Response -> Response

-- | Gets an HTTP Cookie with the given name from Response
--   headers.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> getResponseCookie "cookie-name" emptyResponse
--   Nothing
--   
getResponseCookie :: ByteString -> Response -> Maybe Cookie

-- | Returns a list of Cookies present in Response
--   
--   Example:
--   
--   
--   ghci> getResponseCookies emptyResponse
--   []
--   
getResponseCookies :: Response -> [Cookie]

-- | Deletes an HTTP Cookie from the Response headers. Please
--   note this does not necessarily erase the cookie from the client
--   browser.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let rsp    = addResponseCookie cookie emptyResponse
--   ghci> getResponseCookie "name" rsp
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   ghci> getResponseCookie "name" $ deleteResponseCookie "name" rsp
--   Nothing
--   
deleteResponseCookie :: ByteString -> Response -> Response

-- | Modifies an HTTP Cookie with given name in Response
--   headers. Nothing will happen if a matching Cookie can not be
--   found in Response.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import Data.Monoid
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let rsp    = addResponseCookie cookie emptyResponse
--   ghci> getResponseCookie "name" rsp
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   ghci> let f ck@(Cookie { cookieName = name }) = ck { cookieName = name <> "'"}
--   ghci> let rsp' = modifyResponseCookie "name" f rsp
--   ghci> getResponseCookie "name'" rsp'
--   Just (Cookie {cookieName = "name'", ...})
--   ghci> getResponseCookie "name" rsp'
--   Just (Cookie {cookieName = "name", ...})
--   
modifyResponseCookie :: ByteString -> (Cookie -> Cookie) -> Response -> Response

-- | Expire given Cookie in client's browser.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> let cookie = Cookie "name" "" Nothing (Just "/subsite") Nothing True False
--   ghci> T.runHandler r (expireCookie cookie)
--   HTTP/1.1 200 OK
--   set-cookie: name=; path=/subsite; expires=Sat, 24 Dec 1994 06:28:16 GMT; Secure
--   server: Snap/test
--   
--   date: Thu, 07 Aug 2014 12:21:27 GMT
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let r2 = T.get "/foo/bar" M.empty >> T.addCookies [cookie]
--   ghci> T.runHandler r (getCookie "name" >>= maybe (return ()) expireCookie)
--   HTTP/1.1 200 OK
--   set-cookie: name=; expires=Sat, 24 Dec 1994 06:28:16 GMT
--   server: Snap/test
--   
expireCookie :: MonadSnap m => Cookie -> m ()

-- | Gets the HTTP Cookie with the specified name.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let r = T.get "/foo/bar" M.empty >> T.addCookies [cookie]
--   ghci> T.runHandler r (getCookie "name" >>= writeBS . B8.pack . show)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 12:16:58 GMT
--   
--   Just (Cookie {cookieName = "name", cookieValue = "value", ...})
--   
getCookie :: MonadSnap m => ByteString -> m (Maybe Cookie)

-- | Gets the HTTP Cookie with the specified name and decodes it. If
--   the decoding fails, the handler calls pass.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> let r = T.get "/foo/bar" M.empty >> T.addCookies [cookie]
--   ghci> T.runHandler r (readCookie "name" >>= writeBS)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 07 Aug 2014 12:20:09 GMT
--   
--   value
--   
readCookie :: (MonadSnap m, Readable a) => ByteString -> m a

-- | 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.
--   
--   Example:
--   
--   
--   ghci> setContentLength 400 emptyResponse
--   HTTP/1.1 200 OK
--   Content-Length: 400
--   
setContentLength :: Word64 -> Response -> Response

-- | Removes any Content-Length set in the Response.
--   
--   Example:
--   
--   
--   ghci> clearContentLength $ setContentLength 400 emptyResponse
--   HTTP/1.1 200 OK
--   
clearContentLength :: Response -> Response

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (redirect "http://snapframework.com")
--   HTTP/1.1 302 Found
--   content-length: 0
--   location: http://snapframework.com
--   server: Snap/test
--   date: Thu, 07 Aug 2014 08:52:11 GMT
--   Content-Length: 0
--   
redirect :: MonadSnap m => ByteString -> m a

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (redirect' "http://snapframework.com" 301)
--   HTTP/1.1 307 Temporary Redirect
--   content-length: 0
--   location: http://snapframework.com
--   server: Snap/test
--   date: Thu, 07 Aug 2014 08:55:51 GMT
--   Content-Length: 0
--   
redirect' :: MonadSnap m => ByteString -> Int -> m a

-- | Sets an HTTP response body to the given stream procedure.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> r
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   
setResponseBody :: (OutputStream Builder -> IO (OutputStream Builder)) -> Response -> Response

-- | Modifies a response body.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> r
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   ghci> :{
--   ghci| let r' = modifyResponseBody
--   ghci|          (f out -> do
--   ghci|              out' <- f out
--   ghci|              Streams.write (Just $ Builder.byteString "\nBye, world!") out'
--   ghci|              return out') r
--   ghci| :}
--   ghci> r'
--   HTTP/1.1 200 OK
--   
--   Hello, world!
--   Bye, world!
--   
modifyResponseBody :: ((OutputStream Builder -> IO (OutputStream Builder)) -> OutputStream Builder -> IO (OutputStream Builder)) -> Response -> Response

-- | Run the given stream procedure, adding its output to the
--   Response stored in the Snap monad state.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Builder as B
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> :{
--   ghci| let f str = do {
--   ghci|   Streams.write (Just $ B.byteString "Hello, streams world") str;
--   ghci|   return str }
--   ghci| :}
--   ghci> T.runHandler r (addToOutput f)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:55:47 GMT
--   
--   Hello, streams world
--   
addToOutput :: MonadSnap m => (OutputStream Builder -> IO (OutputStream Builder)) -> m ()

-- | Adds the given Builder to the body of the Response
--   stored in the | Snap monad state.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Builder as B
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBuilder $ B.byteString "Hello, world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:33:33 GMT
--   
--   Hello, world
--   
writeBuilder :: MonadSnap m => Builder -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeBS "Hello, bytestring world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:34:27 GMT
--   
--   Hello, bytestring world
--   
writeBS :: MonadSnap m => ByteString -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeLazyText "Hello, lazy text world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:37:41 GMT
--   
--   Hello, lazy text world
--   
writeLazyText :: MonadSnap m => Text -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeText "Hello, text world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:36:38 GMT
--   
--   Hello, text world
--   
writeText :: MonadSnap m => Text -> m ()

-- | 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.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (writeLBS "Hello, lazy bytestring world")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:35:15 GMT
--   
--   Hello, lazy bytestring world
--   
writeLBS :: MonadSnap m => ByteString -> m ()

-- | 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().
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> writeFile "/tmp/snap-file" "Hello, sendFile world"
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (sendFile "/tmp/snap-file")
--   HTTP/1.1 200 OK
--   content-length: 21
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:45:10 GMT
--   Content-Length: 21
--   
--   Hello, sendFile world
--   
sendFile :: MonadSnap m => FilePath -> m ()

-- | 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().
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> writeFile "/tmp/snap-file" "Hello, sendFilePartial world"
--   ghci> let r = T.get "/foo/bar" M.empty
--   ghci> T.runHandler r (sendFilePartial "/tmp/snap-file" (7, 28))
--   HTTP/1.1 200 OK
--   content-length: 21
--   server: Snap/test
--   date: Wed, 06 Aug 2014 17:47:20 GMT
--   Content-Length: 21
--   
--   sendFilePartial world
--   
sendFilePartial :: MonadSnap m => FilePath -> (Word64, Word64) -> m ()

-- | Causes the handler thread to be killed n seconds from now.
setTimeout :: MonadSnap m => Int -> m ()

-- | Causes the handler thread to be killed at least n seconds
--   from now.
extendTimeout :: MonadSnap m => Int -> m ()

-- | Modifies the amount of time remaining before the request times out.
modifyTimeout :: MonadSnap m => (Int -> Int) -> m ()

-- | Returns an IO action which you can use to modify the timeout
--   value.
getTimeoutModifier :: MonadSnap m => m ((Int -> Int) -> IO ())

-- | Convert a CTime into an HTTP timestamp.
--   
--   Example:
--   
--   
--   ghci> formatHttpTime . fromIntegral $ 10
--   "Thu, 01 Jan 1970 00:00:10 GMT"
--   
formatHttpTime :: CTime -> IO ByteString

-- | Converts an HTTP timestamp into a CTime.
--   
--   If the given time string is unparseable, this function will return 0.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> parseHttpTime "Thu, 01 Jan 1970 00:00:10 GMT"
--   10
--   
parseHttpTime :: ByteString -> IO CTime

-- | Parse a string encoded in application/x-www-form-urlencoded
--   format.
--   
--   Example:
--   
--   
--   ghci> parseUrlEncoded "Name=John+Doe&Name=Jane+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21"
--   fromList [(Age,["23"]),(Formula,["a + b == 13%!"]),(Name,["John Doe","Jane Doe"])]
--   
parseUrlEncoded :: ByteString -> Map ByteString [ByteString]

-- | Like printUrlEncoded, but produces a Builder instead of
--   a ByteString. Useful for constructing a large string
--   efficiently in a single step.
--   
--   Example:
--   
--   
--   ghci> import Data.Map
--   ghci> import Data.Monoid
--   ghci> import Data.ByteString.Builder
--   ghci> let bldr = buildUrlEncoded (fromList [(Name, ["John Doe"]), (Age, ["23"])])
--   ghci> toLazyByteString $ byteString "http://example.com/script?" <> bldr
--   "http://example.com/script?Age=23&Name=John+Doe"
--   
buildUrlEncoded :: Map ByteString [ByteString] -> Builder

-- | Given a collection of key-value pairs with possibly duplicate keys
--   (represented as a Map), construct a string in
--   application/x-www-form-urlencoded format.
--   
--   Example:
--   
--   
--   ghci> printUrlEncoded (fromList [(Name, ["John Doe"]), (Age, ["23"])])
--   "Age=23&Name=John+Doe"
--   
printUrlEncoded :: Map ByteString [ByteString] -> ByteString

-- | URL-escape a string (see
--   http://tools.ietf.org/html/rfc2396.html#section-2.4)
--   
--   Example:
--   
--   
--   ghci> urlEncode "1 attoparsec ~= 3 * 10^-2 meters"
--   "1+attoparsec+%7e%3d+3+*+10%5e-2+meters"
--   
urlEncode :: ByteString -> ByteString

-- | URL-escape a string (see
--   http://tools.ietf.org/html/rfc2396.html#section-2.4) into a
--   Builder.
--   
--   Example:
--   
--   
--   ghci> import Data.ByteString.Builder
--   ghci> toLazyByteString . urlEncodeBuilder $ "1 attoparsec ~= 3 * 10^-2 meters"
--   "1+attoparsec+%7e%3d+3+*+10%5e-2+meters"
--   
urlEncodeBuilder :: ByteString -> Builder

-- | Decode an URL-escaped string (see
--   http://tools.ietf.org/html/rfc2396.html#section-2.4)
--   
--   Example:
--   
--   
--   ghci> urlDecode "1+attoparsec+%7e%3d+3+*+10%5e-2+meters"
--   Just "1 attoparsec ~= 3 * 10^-2 meters"
--   
urlDecode :: ByteString -> Maybe ByteString

-- | Contains web handlers to serve files from a directory.
module Snap.Internal.Util.FileServe

-- | Gets a path from the Request using rqPathInfo and makes
--   sure it is safe to use for opening files. A path is safe if it is a
--   relative path and has no ".." elements to escape the intended
--   directory structure.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> T.runHandler (T.get "/foo/bar" M.empty) (getSafePath >>= writeBS . B8.pack)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Fri, 08 Aug 2014 16:13:20 GMT
--   
--   foo/bar
--   ghci> T.runHandler (T.get "/foo/../bar" M.empty) (getSafePath >>= writeBS . B8.pack)
--   HTTP/1.1 404 Not Found
--   ...
--   
getSafePath :: MonadSnap m => m FilePath

-- | A type alias for MIME type
type MimeMap = HashMap FilePath ByteString

-- | A type alias for dynamic handlers
type HandlerMap (m :: Type -> Type) = HashMap FilePath FilePath -> m ()

-- | A collection of options for serving static files out of a directory.
data DirectoryConfig (m :: Type -> Type)
DirectoryConfig :: [FilePath] -> (FilePath -> m ()) -> HandlerMap m -> MimeMap -> (FilePath -> m ()) -> DirectoryConfig (m :: Type -> Type)

-- | Files to look for when a directory is requested (e.g., index.html)
[indexFiles] :: DirectoryConfig (m :: Type -> Type) -> [FilePath]

-- | Handler to generate a directory listing if there is no index.
[indexGenerator] :: DirectoryConfig (m :: Type -> Type) -> FilePath -> m ()

-- | Map of extensions to pass to dynamic file handlers. This could be
--   used, for example, to implement CGI dispatch, pretty printing of
--   source code, etc.
[dynamicHandlers] :: DirectoryConfig (m :: Type -> Type) -> HandlerMap m

-- | MIME type map to look up content types.
[mimeTypes] :: DirectoryConfig (m :: Type -> Type) -> MimeMap

-- | Handler that is called before a file is served. It will only be called
--   when a file is actually found, not for generated index pages.
[preServeHook] :: DirectoryConfig (m :: Type -> Type) -> FilePath -> m ()

-- | A very simple configuration for directory serving. This configuration
--   uses built-in MIME types from defaultMimeTypes, and has no
--   index files, index generator, dynamic file handlers, or
--   preServeHook.
simpleDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m

-- | A reasonable default configuration for directory serving. This
--   configuration uses built-in MIME types from defaultMimeTypes,
--   serves common index files index.html and index.htm,
--   but does not autogenerate directory indexes, nor have any dynamic file
--   handlers. The preServeHook will not do anything.
defaultDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m

-- | A more elaborate configuration for file serving. This configuration
--   uses built-in MIME types from defaultMimeTypes, serves common
--   index files index.html and index.htm, and
--   autogenerates directory indexes with a Snap-like feel. It still has no
--   dynamic file handlers, nor preServeHook, which should be added
--   as needed.
--   
--   Files recognized as indexes include index.html,
--   index.htm, default.html, default.htm,
--   home.html
--   
--   Example of how the autogenerated directory index looks like:
--   
fancyDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m

-- | An automatic index generator, which is fairly small and does not rely
--   on any external files (which may not be there depending on external
--   request routing).
--   
--   A MimeMap is passed in to display the types of files in the
--   directory listing based on their extension. Preferably, this is the
--   same as the map in the DirectoryConfig
--   
--   The styles parameter allows you to apply styles to the directory
--   listing. The listing itself consists of a table, containing a header
--   row using th elements, and one row per file using td elements, so
--   styles for those pieces may be attached to the appropriate tags.
defaultIndexGenerator :: MonadSnap m => MimeMap -> ByteString -> FilePath -> m ()

-- | The default set of mime type mappings we use when serving files. Its
--   value:
--   
--   
--   Map.fromList [
--     ( ".asc"     , "text/plain"                                             ),
--     ( ".asf"     , "video/x-ms-asf"                                         ),
--     ( ".asx"     , "video/x-ms-asf"                                         ),
--     ( ".au"      , "audio/basic"                                            ),
--     ( ".avi"     , "video/x-msvideo"                                        ),
--     ( ".bmp"     , "image/bmp"                                              ),
--     ( ".bz2"     , "application/x-bzip"                                     ),
--     ( ".c"       , "text/plain"                                             ),
--     ( ".class"   , "application/octet-stream"                               ),
--     ( ".conf"    , "text/plain"                                             ),
--     ( ".cpp"     , "text/plain"                                             ),
--     ( ".css"     , "text/css"                                               ),
--     ( ".csv"     , "text/csv"                                               ),
--     ( ".cxx"     , "text/plain"                                             ),
--     ( ".doc"     , "application/msword"                                     ),
--     ( ".docx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".wordprocessingml.document"                    ),
--     ( ".dotx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".wordprocessingml.template"                    ),
--     ( ".dtd"     , "application/xml-dtd"                                    ),
--     ( ".dvi"     , "application/x-dvi"                                      ),
--     ( ".exe"     , "application/octet-stream"                               ),
--     ( ".flv"     , "video/x-flv"                                            ),
--     ( ".gif"     , "image/gif"                                              ),
--     ( ".gz"      , "application/x-gzip"                                     ),
--     ( ".hs"      , "text/plain"                                             ),
--     ( ".htm"     , "text/html"                                              ),
--     ( ".html"    , "text/html"                                              ),
--     ( ".ico"     , "image/x-icon"                                           ),
--     ( ".jar"     , "application/x-java-archive"                             ),
--     ( ".jpeg"    , "image/jpeg"                                             ),
--     ( ".jpg"     , "image/jpeg"                                             ),
--     ( ".js"      , "text/javascript"                                        ),
--     ( ".json"    , "application/json"                                       ),
--     ( ".log"     , "text/plain"                                             ),
--     ( ".m3u"     , "audio/x-mpegurl"                                        ),
--     ( ".m3u8"    , "application/x-mpegURL"                                  ),
--     ( ".mka"     , "audio/x-matroska"                                       ),
--     ( ".mk3d"    , "video/x-matroska"                                       ),
--     ( ".mkv"     , "video/x-matroska"                                       ),
--     ( ".mov"     , "video/quicktime"                                        ),
--     ( ".mp3"     , "audio/mpeg"                                             ),
--     ( ".mp4"     , "video/mp4"                                              ),
--     ( ".mpeg"    , "video/mpeg"                                             ),
--     ( ".mpg"     , "video/mpeg"                                             ),
--     ( ".ogg"     , "application/ogg"                                        ),
--     ( ".pac"     , "application/x-ns-proxy-autoconfig"                      ),
--     ( ".pdf"     , "application/pdf"                                        ),
--     ( ".png"     , "image/png"                                              ),
--     ( ".potx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.template"                      ),
--     ( ".ppsx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.slideshow"                     ),
--     ( ".ppt"     , "application/vnd.ms-powerpoint"                          ),
--     ( ".pptx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.presentation"                  ),
--     ( ".ps"      , "application/postscript"                                 ),
--     ( ".qt"      , "video/quicktime"                                        ),
--     ( ".rtf"     , "text/rtf"                                               ),
--     ( ".sig"     , "application/pgp-signature"                              ),
--     ( ".sldx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.slide"                         ),
--     ( ".spl"     , "application/futuresplash"                               ),
--     ( ".svg"     , "image/svg+xml"                                          ),
--     ( ".swf"     , "application/x-shockwave-flash"                          ),
--     ( ".tar"     , "application/x-tar"                                      ),
--     ( ".tar.bz2" , "application/x-bzip-compressed-tar"                      ),
--     ( ".tar.gz"  , "application/x-tgz"                                      ),
--     ( ".tbz"     , "application/x-bzip-compressed-tar"                      ),
--     ( ".text"    , "text/plain"                                             ),
--     ( ".tgz"     , "application/x-tgz"                                      ),
--     ( ".tif"     , "image/tiff"                                             ),
--     ( ".tiff"    , "image/tiff"                                             ),
--     ( ".torrent" , "application/x-bittorrent"                               ),
--     ( ".ts"      , "video/mp2t"                                             ),
--     ( ".txt"     , "text/plain"                                             ),
--     ( ".wav"     , "audio/x-wav"                                            ),
--     ( ".wax"     , "audio/x-ms-wax"                                         ),
--     ( ".webm"    , "video/webm"                                             ),
--     ( ".wma"     , "audio/x-ms-wma"                                         ),
--     ( ".wmv"     , "video/x-ms-wmv"                                         ),
--     ( ".xbm"     , "image/x-xbitmap"                                        ),
--     ( ".xlam"    , "application/vnd.ms-excel.addin.macroEnabled.12"         ),
--     ( ".xls"     , "application/vnd.ms-excel"                               ),
--     ( ".xlsb"    , "application/vnd.ms-excel.sheet.binary.macroEnabled.12"  ),
--     ( ".xlsx"    , S.append "application/vnd.openxmlformats-officedocument."
--                             "spreadsheetml.sheet"                           ),
--     ( ".xltx"    , S.append "application/vnd.openxmlformats-officedocument."
--                             "spreadsheetml.template"                        ),
--     ( ".xml"     , "text/xml"                                               ),
--     ( ".xpm"     , "image/x-xpixmap"                                        ),
--     ( ".xwd"     , "image/x-xwindowdump"                                    ),
--     ( ".zip"     , "application/zip"                                        ) ]
--   
defaultMimeTypes :: MimeMap

-- | Determine a given file's MIME type from its filename and the provided
--   MIME map.
fileType :: MimeMap -> FilePath -> ByteString

-- | Serves static files from a directory using the default configuration
--   as given in defaultDirectoryConfig.
serveDirectory :: MonadSnap m => FilePath -> m ()

-- | Serves static files from a directory. Configuration options are passed
--   in a DirectoryConfig that captures various choices about
--   desired behavior. The relative path given in rqPathInfo is
--   searched for a requested file, and the file is served with the
--   appropriate mime type if it is found. Absolute paths and ".."
--   are prohibited to prevent files from being served from outside the
--   sandbox.
serveDirectoryWith :: MonadSnap m => DirectoryConfig m -> FilePath -> m ()

-- | Serves a single file specified by a full or relative path. If the file
--   does not exist, throws an exception (not that it does not pass
--   to the next handler). The path restrictions on serveDirectory
--   don't apply to this function since the path is not being supplied by
--   the user.
serveFile :: MonadSnap m => FilePath -> m ()

-- | Same as serveFile, with control over the MIME mapping used.
serveFileAs :: MonadSnap m => ByteString -> FilePath -> m ()
decodeFilePath :: FilePath -> IO Text
checkRangeReq :: MonadSnap m => Request -> FilePath -> Word64 -> m Bool

-- | The Snap.Test module contains primitives and combinators for testing
--   Snap applications.
module Snap.Test

-- | RequestBuilder is a monad transformer that allows you to conveniently
--   build a snap Request for testing.
data RequestBuilder (m :: Type -> Type) a

-- | A request body of type "multipart/form-data" consists of a
--   set of named form parameters, each of which can by either a list of
--   regular form values or a set of file uploads.
type MultipartParams = [(ByteString, MultipartParam)]

-- | A single "multipart/form-data" form parameter: either a list
--   of regular form values or a set of file uploads.
data MultipartParam

-- | a form variable consisting of the given ByteString values.
FormData :: [ByteString] -> MultipartParam

-- | a file upload consisting of the given FileData values.
Files :: [FileData] -> MultipartParam

-- | Represents a single file upload for the MultipartParam.
data FileData
FileData :: ByteString -> ByteString -> ByteString -> FileData

-- | the file's name
[fdFileName] :: FileData -> ByteString

-- | the file's content-type
[fdContentType] :: FileData -> ByteString

-- | the file contents
[fdContents] :: FileData -> ByteString

-- | The RequestType datatype enumerates the different kinds of HTTP
--   requests you can generate using the testing interface. Most users will
--   prefer to use the get, postUrlEncoded,
--   postMultipart, put, and delete convenience
--   functions.
data RequestType
GetRequest :: RequestType
RequestWithRawBody :: Method -> ByteString -> RequestType
MultipartPostRequest :: MultipartParams -> RequestType
UrlEncodedPostRequest :: Params -> RequestType
DeleteRequest :: RequestType

-- | Runs a RequestBuilder, producing the desired Request.
--   
--   N.B. please don't use the request you get here in a real Snap
--   application; things will probably break. Don't say you weren't warned
--   :-)
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ get "/foo/bar" M.empty
--   GET /foo/bar HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
buildRequest :: MonadIO m => RequestBuilder m () -> m Request

-- | Given a web handler in the Snap monad, and a
--   RequestBuilder defining a test request, runs the handler,
--   producing an HTTP Response.
--   
--   This function will produce almost exactly the same output as running
--   the handler in a real server, except that chunked transfer encoding is
--   not applied, and the "Transfer-Encoding" header is not set (this makes
--   it easier to test response output).
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import Snap.Core
--   ghci> runHandler (get "foo/bar" M.empty) (writeBS "Hello, world!")
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Thu, 17 Jul 2014 21:03:23 GMT
--   
--   Hello, world!
--   
runHandler :: MonadIO m => RequestBuilder m () -> Snap a -> m Response

-- | Given a web handler in some arbitrary MonadSnap monad, a
--   function specifying how to evaluate it within the context of the test
--   monad, and a RequestBuilder defining a test request, runs the
--   handler, producing an HTTP Response.
runHandlerM :: (MonadIO m, MonadSnap n) => (forall a. () => Request -> n a -> m Response) -> RequestBuilder m () -> n b -> m Response

-- | Given a web handler in the Snap monad, and a
--   RequestBuilder defining a test request, runs the handler and
--   returns the monadic value it produces.
--   
--   Throws an exception if the Snap handler early-terminates with
--   finishWith or mzero.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import Control.Monad
--   ghci> import qualified Data.Map as M
--   ghci> import Snap.Core
--   ghci> evalHandler (get "foo/bar" M.empty) (writeBS "Hello, world!" >> return 42)
--   42
--   ghci> evalHandler (get "foo/bar" M.empty) mzero
--   *** Exception: No handler for request: failure was pass
--   
evalHandler :: MonadIO m => RequestBuilder m () -> Snap a -> m a

-- | Given a web handler in some arbitrary MonadSnap monad, a
--   function specifying how to evaluate it within the context of the test
--   monad, and a RequestBuilder defining a test request, runs the
--   handler, returning the monadic value it produces.
--   
--   Throws an exception if the Snap handler early-terminates with
--   finishWith or mzero.
evalHandlerM :: (MonadIO m, MonadSnap n) => (forall a. () => Request -> n a -> m a) -> RequestBuilder m () -> n b -> m b

-- | Builds an HTTP "GET" request with the given query parameters.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ get "/foo/bar" (M.fromList [("param0", ["baz", "quux"])])
--   GET /foo/bar?param0=baz&param0=quux HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   params: param0: ["baz","quux"]
--   
get :: forall (m :: Type -> Type). MonadIO m => ByteString -> Params -> RequestBuilder m ()

-- | <math>. Extract the first element of a list, which must be
--   non-empty.
--   
--   To disable the warning about partiality put {-# OPTIONS_GHC
--   -Wno-x-partial -Wno-unrecognised-warning-flags #-} at the top of
--   the file. To disable it throughout a package put the same options into
--   ghc-options section of Cabal file. To disable it in GHCi put
--   :set -Wno-x-partial -Wno-unrecognised-warning-flags into
--   ~/.ghci config file. See also the migration guide.
--   
--   
Examples
--   
--   
--   >>> head [1, 2, 3]
--   1
--   
--   
--   
--   >>> head [1..]
--   1
--   
--   
--   
--   >>> head []
--   *** Exception: Prelude.head: empty list
--   
head :: HasCallStack => [a] -> a

-- | Builds an HTTP "POST" request with the given form parameters, using
--   the "application/x-www-form-urlencoded" MIME type.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ postUrlEncoded "/foo/bar" (M.fromList [("param0", ["baz", "quux"])])
--   POST /foo/bar HTTP/1.1
--   content-type: application/x-www-form-urlencoded
--   content-length: 22
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=22
--   params: param0: ["baz","quux"]
--   
postUrlEncoded :: forall (m :: Type -> Type). MonadIO m => ByteString -> Params -> RequestBuilder m ()

-- | Builds an HTTP "POST" request with the given form parameters, using
--   the "form-data/multipart" MIME type.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> buildRequest $ postMultipart "/foo/bar" [("param0", FormData ["baz", "quux"])]
--   POST /foo/bar HTTP/1.1
--   content-type: multipart/form-data; boundary=snap-boundary-572334111ec0c05ad4812481e8585dfa
--   content-length: 406
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=406
--   
postMultipart :: forall (m :: Type -> Type). MonadIO m => ByteString -> MultipartParams -> RequestBuilder m ()

-- | Builds an HTTP "PUT" request.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> buildRequest $ put "/foo/bar" "text/plain" "some text"
--   PUT /foo/bar HTTP/1.1
--   content-type: text/plain
--   content-length: 9
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=9
--   
put :: forall (m :: Type -> Type). MonadIO m => ByteString -> ByteString -> ByteString -> RequestBuilder m ()

-- | Builds a "raw" HTTP "POST" request, with the given MIME type and body
--   contents.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> buildRequest $ postRaw "/foo/bar" "text/plain" "some text"
--   POST /foo/bar HTTP/1.1
--   content-type: text/plain
--   content-length: 9
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=9
--   
postRaw :: forall (m :: Type -> Type). MonadIO m => ByteString -> ByteString -> ByteString -> RequestBuilder m ()

-- | Builds an HTTP "DELETE" request with the given query parameters.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ delete "/foo/bar" M.empty
--   DELETE /foo/bar HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
delete :: forall (m :: Type -> Type). MonadIO m => ByteString -> Params -> RequestBuilder m ()

-- | Adds the given header to the request being built.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| buildRequest $ do get "/foo/bar" M.empty
--   ghci|                   addHeader "Accept" "text/html"
--   ghci|                   addHeader "Accept" "text/plain"
--   ghci| :}
--   GET /foo/bar HTTP/1.1
--   accept: text/html,text/plain
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
addHeader :: forall (m :: Type -> Type). Monad m => CI ByteString -> ByteString -> RequestBuilder m ()

-- | Sets the request's content-type to the given MIME type.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ put "/foo/bar" "text/html" "some text" >> setContentType "text/plain"
--   PUT /foo/bar HTTP/1.1
--   content-type: text/plain
--   content-length: 9
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=9
--   
setContentType :: forall (m :: Type -> Type). Monad m => ByteString -> RequestBuilder m ()

-- | Sets the given header in the request being built, overwriting any
--   header with the same name already present.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> :{
--   ghci| buildRequest $ do get "/foo/bar" M.empty
--   ghci|                   setHeader "Accept" "text/html"
--   ghci|                   setHeader "Accept" "text/plain"
--   ghci| :}
--   GET /foo/bar HTTP/1.1
--   accept: text/plain
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
setHeader :: forall (m :: Type -> Type). Monad m => CI ByteString -> ByteString -> RequestBuilder m ()

-- | Adds the given cookies to the request being built.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import Snap.Core
--   ghci> let cookie = Cookie "name" "value" Nothing Nothing Nothing False False
--   ghci> buildRequest $ get "/foo/bar" M.empty >> addCookies [cookie]
--   GET /foo/bar HTTP/1.1
--   cookie: name=value
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   cookies: Cookie {cookieName = "name", cookieValue = "value", ...}
--   
addCookies :: forall (m :: Type -> Type). Monad m => [Cookie] -> RequestBuilder m ()

-- | Sets the test request's http version
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ delete "/foo/bar" M.empty >> setHttpVersion (1,0)
--   DELETE /foo/bar HTTP/1.0
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
setHttpVersion :: forall (m :: Type -> Type). Monad m => (Int, Int) -> RequestBuilder m ()

-- | Escapes the given parameter mapping and sets it as the request's query
--   string.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ get "/foo/bar" M.empty >> setQueryString (M.fromList [("param0", ["baz"]), ("param1", ["qux"])])
--   GET /foo/bar?param0=baz&param1=qux HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   params: param0: ["baz"], param1: ["qux"]
--   
setQueryString :: forall (m :: Type -> Type). Monad m => Params -> RequestBuilder m ()

-- | Sets the request's query string to be the raw bytestring provided,
--   without any escaping or other interpretation. Most users should
--   instead choose the setQueryString function, which takes a
--   parameter mapping.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ get "/foo/bar" M.empty >> setQueryStringRaw "param0=baz&param1=qux"
--   GET /foo/bar?param0=baz&param1=qux HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   params: param0: ["baz"], param1: ["qux"]
--   
setQueryStringRaw :: forall (m :: Type -> Type). Monad m => ByteString -> RequestBuilder m ()

-- | Sets the request's path. The path provided must begin with a
--   "/" and must not contain a query string; if you want
--   to provide a query string in your test request, you must use
--   setQueryString or setQueryStringRaw. Note that
--   rqContextPath is never set by any RequestBuilder
--   function.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ get "/foo/bar" M.empty >> setRequestPath "/bar/foo"
--   GET /bar/foo HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
setRequestPath :: forall (m :: Type -> Type). Monad m => ByteString -> RequestBuilder m ()

-- | Sets the type of the Request being built.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ delete "/foo/bar" M.empty >> setRequestType GetRequest
--   GET /foo/bar HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a
--   
setRequestType :: forall (m :: Type -> Type). MonadIO m => RequestType -> RequestBuilder m ()

-- | Controls whether the test request being generated appears to be an
--   https request or not.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> buildRequest $ delete "/foo/bar" M.empty >> setSecure True
--   DELETE /foo/bar HTTP/1.1
--   host: localhost
--   
--   sn="localhost" c=127.0.0.1:60000 s=127.0.0.1:8080 ctx=/ clen=n/a secure
--   
setSecure :: forall (m :: Type -> Type). Monad m => Bool -> RequestBuilder m ()

-- | Given a Response, assert that its HTTP status code is 200
--   (success).
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Test.HUnit as T
--   ghci> let test = T.runTestTT . T.TestCase
--   ghci> test $ assertSuccess emptyResponse
--   Cases: 1  Tried: 1  Errors: 0  Failures: 0
--   Counts {cases = 1, tried = 1, errors = 0, failures = 0}
--   ghci> test $ assertSuccess (setResponseStatus 500 "Internal Server Error" emptyResponse)
--   ### Failure:
--   Expected success (200) but got (500)
--   expected: 200
--    but got: 500
--   Cases: 1  Tried: 1  Errors: 0  Failures: 1
--   Counts {cases = 1, tried = 1, errors = 0, failures = 1}
--   
assertSuccess :: Response -> Assertion

-- | Given a Response, assert that its HTTP status code is 404 (Not
--   Found).
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> assert404 $ setResponseStatus 404 "Not Found" emptyResponse
--   ghci> assert404 emptyResponse
--   *** Exception: HUnitFailure "Expected Not Found (404) but got (200)\nexpected: 404\n but got: 200"
--   
assert404 :: Response -> Assertion

-- | Given a Response, assert that its HTTP status code is between
--   300 and 399 (a redirect), and that the Location header of the
--   Response points to the specified URI.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> let r' = setResponseStatus 301 "Moved Permanently" emptyResponse
--   ghci> let r  = setHeader "Location" "www.example.com" r'
--   ghci> assertRedirectTo "www.example.com" r
--   ghci> assertRedirectTo "www.example.com" emptyResponse
--   *** Exception: HUnitFailure "Expected redirect but got status code (200)"
--   
assertRedirectTo :: ByteString -> Response -> Assertion

-- | Given a Response, assert that its HTTP status code is between
--   300 and 399 (a redirect).
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> assertRedirect $ setResponseStatus 301 "Moved Permanently" emptyResponse
--   ghci> assertRedirect emptyResponse
--   *** Exception: HUnitFailure "Expected redirect but got status code (200)"
--   
assertRedirect :: Response -> Assertion

-- | Given a Response, assert that its body matches the given
--   regular expression.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified System.IO.Streams as Streams
--   ghci> import qualified Data.ByteString.Builder as Builder
--   ghci> :{
--   ghci| let r = setResponseBody
--   ghci|         (out -> do
--   ghci|             Streams.write (Just $ Builder.byteString "Hello, world!") out
--   ghci|             return out)
--   ghci|         emptyResponse
--   ghci| :}
--   ghci> assertBodyContains "^Hello" r
--   ghci> assertBodyContains "Bye" r
--   *** Exception: HUnitFailure "Expected body to match regexp \"\"Bye\"\", but didn't"
--   
assertBodyContains :: ByteString -> Response -> Assertion

-- | Given a Response, return its body as a ByteString.
--   
--   Example:
--   
--   
--   ghci> getResponseBody emptyResponse
--   ""
--   
getResponseBody :: Response -> IO ByteString

-- | Converts the given Request to a bytestring.
--   
--   Since: 1.0.0.0
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> r <- buildRequest $ get "/foo/bar" M.empty
--   ghci> requestToString r
--   "GET /foo/bar HTTP/1.1\r\nhost: localhost\r\n\r\n"
--   
requestToString :: Request -> IO ByteString

-- | Converts the given Response to a bytestring.
--   
--   Example:
--   
--   
--   ghci> import Snap.Core
--   ghci> responseToString emptyResponse
--   "HTTP/1.1 200 OK\r\n\r\n"
--   
responseToString :: Response -> IO ByteString

-- | Add CORS (cross-origin resource sharing) headers to a Snap
--   application. CORS headers can be added either conditionally or
--   unconditionally to the entire site, or you can apply CORS headers to a
--   single route.
--   
--   To use in a snaplet, simply use wrapSite:
--   
--   
--   wrapSite $ applyCORS defaultOptions
--   
module Snap.Util.CORS

-- | Apply CORS headers to a specific request. This is useful if you only
--   have a single action that needs CORS headers, and you don't want to
--   pay for conditional checks on every request.
--   
--   You should note that applyCORS needs to be used before you add
--   any method combinators. For example, the following won't do
--   what you want:
--   
--   
--   method POST $ applyCORS defaultOptions $ myHandler
--   
--   
--   This fails to work as CORS requires an OPTIONS request in the
--   preflighting stage, but this would get filtered out. Instead, use
--   
--   
--   applyCORS defaultOptions $ method POST $ myHandler
--   
applyCORS :: MonadSnap m => CORSOptions m -> m () -> m ()

-- | Specify the options to use when building CORS headers for a response.
--   Most of these options are Handler actions to allow you to
--   conditionally determine the setting of each header.
data CORSOptions (m :: Type -> Type)
CORSOptions :: m OriginList -> m Bool -> m (HashSet (CI ByteString)) -> m (HashSet HashableMethod) -> (HashSet ByteString -> m (HashSet ByteString)) -> CORSOptions (m :: Type -> Type)

-- | Which origins are allowed to make cross-origin requests.
[corsAllowOrigin] :: CORSOptions (m :: Type -> Type) -> m OriginList

-- | Whether or not to allow exposing the response when the omit
--   credentials flag is unset.
[corsAllowCredentials] :: CORSOptions (m :: Type -> Type) -> m Bool

-- | A list of headers that are exposed to clients. This allows clients to
--   read the values of these headers, if the response includes them.
[corsExposeHeaders] :: CORSOptions (m :: Type -> Type) -> m (HashSet (CI ByteString))

-- | A list of request methods that are allowed.
[corsAllowedMethods] :: CORSOptions (m :: Type -> Type) -> m (HashSet HashableMethod)

-- | An action to determine which of the request headers are allowed. This
--   action is supplied the parsed contents of
--   Access-Control-Request-Headers.
[corsAllowedHeaders] :: CORSOptions (m :: Type -> Type) -> HashSet ByteString -> m (HashSet ByteString)

-- | Liberal default options. Specifies that:
--   
--   
--   
- All origins may make cross-origin requests
--   
- allow-credentials is true.
--   
- No extra headers beyond simple headers are exposed.
--   
- GET, POST, PUT, DELETE and
--   HEAD are all allowed.
--   
- All request headers are allowed.
--   
--   
--   All options are determined unconditionally.
defaultOptions :: forall (m :: Type -> Type). Monad m => CORSOptions m

-- | Used to specify the contents of the
--   Access-Control-Allow-Origin header.
data OriginList

-- | Allow any origin to access this resource. Corresponds to
--   Access-Control-Allow-Origin: *
Everywhere :: OriginList

-- | Do not allow cross-origin requests
Nowhere :: OriginList

-- | Allow cross-origin requests from these origins.
Origins :: OriginSet -> OriginList

-- | A set of origins. RFC 6454 specifies that origins are a scheme, host
--   and port, so the OriginSet wrapper around a HashSet
--   ensures that each URI constists of nothing more than this.
data OriginSet
mkOriginSet :: [URI] -> OriginSet
origins :: OriginSet -> HashSet HashableURI

-- | A newtype over URI with a Hashable instance.
newtype HashableURI
HashableURI :: URI -> HashableURI
newtype HashableMethod
HashableMethod :: Method -> HashableMethod
instance GHC.Classes.Eq Snap.Util.CORS.HashableMethod
instance GHC.Classes.Eq Snap.Util.CORS.HashableURI
instance Data.Hashable.Class.Hashable Snap.Util.CORS.HashableMethod
instance Data.Hashable.Class.Hashable Snap.Util.CORS.HashableURI
instance GHC.Internal.Show.Show Snap.Util.CORS.HashableMethod
instance GHC.Internal.Show.Show Snap.Util.CORS.HashableURI

-- | Contains web handlers to serve files from a directory.
--   
--   Example usage:
--   
--   
--   {-# LANGUAGE OverloadedStrings #-}
--   
--   module Main where
--   
--   import Snap.Core           (Snap, route)
--   import Snap.Http.Server    (quickHttpServe)
--   import Snap.Util.FileServe
--   
--   site :: Snap ()
--   site = route
--     [ ("/files",   serveDirectory                            "static")
--     , ("/simple",  serveDirectoryWith simpleDirectoryConfig  "static")
--     , ("/default", serveDirectoryWith defaultDirectoryConfig "static")
--     , ("/fancy",   serveDirectoryWith fancyDirectoryConfig   "static")
--     , ("/paper",   serveFile                                 "static/paper.pdf")
--     , ("/thesis",  serveFileAs        "application/pdf"      "static/thesis.pdf")
--     ]
--   
--   main :: IO ()
--   main = quickHttpServe site
--   
module Snap.Util.FileServe

-- | Gets a path from the Request using rqPathInfo and makes
--   sure it is safe to use for opening files. A path is safe if it is a
--   relative path and has no ".." elements to escape the intended
--   directory structure.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> import qualified Data.ByteString.Char8 as B8
--   ghci> T.runHandler (T.get "/foo/bar" M.empty) (getSafePath >>= writeBS . B8.pack)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Fri, 08 Aug 2014 16:13:20 GMT
--   
--   foo/bar
--   ghci> T.runHandler (T.get "/foo/../bar" M.empty) (getSafePath >>= writeBS . B8.pack)
--   HTTP/1.1 404 Not Found
--   ...
--   
getSafePath :: MonadSnap m => m FilePath

-- | A type alias for MIME type
type MimeMap = HashMap FilePath ByteString

-- | A type alias for dynamic handlers
type HandlerMap (m :: Type -> Type) = HashMap FilePath FilePath -> m ()

-- | A collection of options for serving static files out of a directory.
data DirectoryConfig (m :: Type -> Type)
DirectoryConfig :: [FilePath] -> (FilePath -> m ()) -> HandlerMap m -> MimeMap -> (FilePath -> m ()) -> DirectoryConfig (m :: Type -> Type)

-- | Files to look for when a directory is requested (e.g., index.html)
[indexFiles] :: DirectoryConfig (m :: Type -> Type) -> [FilePath]

-- | Handler to generate a directory listing if there is no index.
[indexGenerator] :: DirectoryConfig (m :: Type -> Type) -> FilePath -> m ()

-- | Map of extensions to pass to dynamic file handlers. This could be
--   used, for example, to implement CGI dispatch, pretty printing of
--   source code, etc.
[dynamicHandlers] :: DirectoryConfig (m :: Type -> Type) -> HandlerMap m

-- | MIME type map to look up content types.
[mimeTypes] :: DirectoryConfig (m :: Type -> Type) -> MimeMap

-- | Handler that is called before a file is served. It will only be called
--   when a file is actually found, not for generated index pages.
[preServeHook] :: DirectoryConfig (m :: Type -> Type) -> FilePath -> m ()

-- | A very simple configuration for directory serving. This configuration
--   uses built-in MIME types from defaultMimeTypes, and has no
--   index files, index generator, dynamic file handlers, or
--   preServeHook.
simpleDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m

-- | A reasonable default configuration for directory serving. This
--   configuration uses built-in MIME types from defaultMimeTypes,
--   serves common index files index.html and index.htm,
--   but does not autogenerate directory indexes, nor have any dynamic file
--   handlers. The preServeHook will not do anything.
defaultDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m

-- | A more elaborate configuration for file serving. This configuration
--   uses built-in MIME types from defaultMimeTypes, serves common
--   index files index.html and index.htm, and
--   autogenerates directory indexes with a Snap-like feel. It still has no
--   dynamic file handlers, nor preServeHook, which should be added
--   as needed.
--   
--   Files recognized as indexes include index.html,
--   index.htm, default.html, default.htm,
--   home.html
--   
--   Example of how the autogenerated directory index looks like:
--   
fancyDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m

-- | An automatic index generator, which is fairly small and does not rely
--   on any external files (which may not be there depending on external
--   request routing).
--   
--   A MimeMap is passed in to display the types of files in the
--   directory listing based on their extension. Preferably, this is the
--   same as the map in the DirectoryConfig
--   
--   The styles parameter allows you to apply styles to the directory
--   listing. The listing itself consists of a table, containing a header
--   row using th elements, and one row per file using td elements, so
--   styles for those pieces may be attached to the appropriate tags.
defaultIndexGenerator :: MonadSnap m => MimeMap -> ByteString -> FilePath -> m ()

-- | The default set of mime type mappings we use when serving files. Its
--   value:
--   
--   
--   Map.fromList [
--     ( ".asc"     , "text/plain"                                             ),
--     ( ".asf"     , "video/x-ms-asf"                                         ),
--     ( ".asx"     , "video/x-ms-asf"                                         ),
--     ( ".au"      , "audio/basic"                                            ),
--     ( ".avi"     , "video/x-msvideo"                                        ),
--     ( ".bmp"     , "image/bmp"                                              ),
--     ( ".bz2"     , "application/x-bzip"                                     ),
--     ( ".c"       , "text/plain"                                             ),
--     ( ".class"   , "application/octet-stream"                               ),
--     ( ".conf"    , "text/plain"                                             ),
--     ( ".cpp"     , "text/plain"                                             ),
--     ( ".css"     , "text/css"                                               ),
--     ( ".csv"     , "text/csv"                                               ),
--     ( ".cxx"     , "text/plain"                                             ),
--     ( ".doc"     , "application/msword"                                     ),
--     ( ".docx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".wordprocessingml.document"                    ),
--     ( ".dotx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".wordprocessingml.template"                    ),
--     ( ".dtd"     , "application/xml-dtd"                                    ),
--     ( ".dvi"     , "application/x-dvi"                                      ),
--     ( ".exe"     , "application/octet-stream"                               ),
--     ( ".flv"     , "video/x-flv"                                            ),
--     ( ".gif"     , "image/gif"                                              ),
--     ( ".gz"      , "application/x-gzip"                                     ),
--     ( ".hs"      , "text/plain"                                             ),
--     ( ".htm"     , "text/html"                                              ),
--     ( ".html"    , "text/html"                                              ),
--     ( ".ico"     , "image/x-icon"                                           ),
--     ( ".jar"     , "application/x-java-archive"                             ),
--     ( ".jpeg"    , "image/jpeg"                                             ),
--     ( ".jpg"     , "image/jpeg"                                             ),
--     ( ".js"      , "text/javascript"                                        ),
--     ( ".json"    , "application/json"                                       ),
--     ( ".log"     , "text/plain"                                             ),
--     ( ".m3u"     , "audio/x-mpegurl"                                        ),
--     ( ".m3u8"    , "application/x-mpegURL"                                  ),
--     ( ".mka"     , "audio/x-matroska"                                       ),
--     ( ".mk3d"    , "video/x-matroska"                                       ),
--     ( ".mkv"     , "video/x-matroska"                                       ),
--     ( ".mov"     , "video/quicktime"                                        ),
--     ( ".mp3"     , "audio/mpeg"                                             ),
--     ( ".mp4"     , "video/mp4"                                              ),
--     ( ".mpeg"    , "video/mpeg"                                             ),
--     ( ".mpg"     , "video/mpeg"                                             ),
--     ( ".ogg"     , "application/ogg"                                        ),
--     ( ".pac"     , "application/x-ns-proxy-autoconfig"                      ),
--     ( ".pdf"     , "application/pdf"                                        ),
--     ( ".png"     , "image/png"                                              ),
--     ( ".potx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.template"                      ),
--     ( ".ppsx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.slideshow"                     ),
--     ( ".ppt"     , "application/vnd.ms-powerpoint"                          ),
--     ( ".pptx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.presentation"                  ),
--     ( ".ps"      , "application/postscript"                                 ),
--     ( ".qt"      , "video/quicktime"                                        ),
--     ( ".rtf"     , "text/rtf"                                               ),
--     ( ".sig"     , "application/pgp-signature"                              ),
--     ( ".sldx"    , S.append "application/vnd.openxmlformats-officedocument"
--                             ".presentationml.slide"                         ),
--     ( ".spl"     , "application/futuresplash"                               ),
--     ( ".svg"     , "image/svg+xml"                                          ),
--     ( ".swf"     , "application/x-shockwave-flash"                          ),
--     ( ".tar"     , "application/x-tar"                                      ),
--     ( ".tar.bz2" , "application/x-bzip-compressed-tar"                      ),
--     ( ".tar.gz"  , "application/x-tgz"                                      ),
--     ( ".tbz"     , "application/x-bzip-compressed-tar"                      ),
--     ( ".text"    , "text/plain"                                             ),
--     ( ".tgz"     , "application/x-tgz"                                      ),
--     ( ".tif"     , "image/tiff"                                             ),
--     ( ".tiff"    , "image/tiff"                                             ),
--     ( ".torrent" , "application/x-bittorrent"                               ),
--     ( ".ts"      , "video/mp2t"                                             ),
--     ( ".txt"     , "text/plain"                                             ),
--     ( ".wav"     , "audio/x-wav"                                            ),
--     ( ".wax"     , "audio/x-ms-wax"                                         ),
--     ( ".webm"    , "video/webm"                                             ),
--     ( ".wma"     , "audio/x-ms-wma"                                         ),
--     ( ".wmv"     , "video/x-ms-wmv"                                         ),
--     ( ".xbm"     , "image/x-xbitmap"                                        ),
--     ( ".xlam"    , "application/vnd.ms-excel.addin.macroEnabled.12"         ),
--     ( ".xls"     , "application/vnd.ms-excel"                               ),
--     ( ".xlsb"    , "application/vnd.ms-excel.sheet.binary.macroEnabled.12"  ),
--     ( ".xlsx"    , S.append "application/vnd.openxmlformats-officedocument."
--                             "spreadsheetml.sheet"                           ),
--     ( ".xltx"    , S.append "application/vnd.openxmlformats-officedocument."
--                             "spreadsheetml.template"                        ),
--     ( ".xml"     , "text/xml"                                               ),
--     ( ".xpm"     , "image/x-xpixmap"                                        ),
--     ( ".xwd"     , "image/x-xwindowdump"                                    ),
--     ( ".zip"     , "application/zip"                                        ) ]
--   
defaultMimeTypes :: MimeMap

-- | Determine a given file's MIME type from its filename and the provided
--   MIME map.
fileType :: MimeMap -> FilePath -> ByteString

-- | Serves static files from a directory using the default configuration
--   as given in defaultDirectoryConfig.
serveDirectory :: MonadSnap m => FilePath -> m ()

-- | Serves static files from a directory. Configuration options are passed
--   in a DirectoryConfig that captures various choices about
--   desired behavior. The relative path given in rqPathInfo is
--   searched for a requested file, and the file is served with the
--   appropriate mime type if it is found. Absolute paths and ".."
--   are prohibited to prevent files from being served from outside the
--   sandbox.
serveDirectoryWith :: MonadSnap m => DirectoryConfig m -> FilePath -> m ()

-- | Serves a single file specified by a full or relative path. If the file
--   does not exist, throws an exception (not that it does not pass
--   to the next handler). The path restrictions on serveDirectory
--   don't apply to this function since the path is not being supplied by
--   the user.
serveFile :: MonadSnap m => FilePath -> m ()

-- | Same as serveFile, with control over the MIME mapping used.
serveFileAs :: MonadSnap m => ByteString -> FilePath -> m ()

-- | This module contains primitives and helper functions for handling
--   requests with Content-type: multipart/form-data, i.e. HTML
--   forms and file uploads.
--   
--   Typically most users will want to use handleFileUploads, which
--   writes uploaded files to a temporary directory before sending them on
--   to a handler specified by the user.
--   
--   Users who wish to handle their file uploads differently can use the
--   lower-level interface called handleMultipart. That function
--   takes uploaded files and streams them to a consumer of the user's
--   choosing.
--   
--   Using these functions requires making "policy" decisions which Snap
--   can't really make for users, such as "what's the largest PDF file a
--   user is allowed to upload?" and "should we read form inputs into the
--   parameters mapping?". Policy is specified on a "global" basis (using
--   UploadPolicy), and on a per-file basis (using
--   PartUploadPolicy, which allows you to reject or limit the size
--   of certain uploaded Content-types).
--   
--   Example usage:
--   
--   
--   {-# LANGUAGE OverloadedStrings #-}
--   
--   module Main where
--   
--   import qualified Data.ByteString.Char8 as B8
--   import           Data.Functor          ((<$>))
--   import           Snap.Core             (Snap, route, writeBS)
--   import           Snap.Http.Server      (quickHttpServe)
--   import           Snap.Util.FileUploads
--   import           System.Posix          (FileOffset, fileSize, getFileStatus)
--   
--   uploadForm :: Snap ()
--   uploadForm = writeBS "<form enctype=\"multipart/form-data\" action=\"/do-upload\" method=\"POST\">\
--       \<input name=\"file\" type=\"file\" />\
--       \<input type=\"submit\" value=\"Send File\" />\
--       \</form>"
--   
--   getFileSize :: FilePath -> IO FileOffset
--   getFileSize path = fileSize <$> getFileStatus path
--   
--   -- Upload handler that prints out the uploaded file's size.
--   doUpload :: Snap ()
--   doUpload = do
--     l <- handleFileUploads "/tmp" defaultUploadPolicy
--          (const $ allowWithMaximumSize (getMaximumFormInputSize defaultUploadPolicy))
--          (\pinfo mbfname -> do fsize <- either (const $ return 0) getFileSize mbfname
--                                return (partFileName pinfo, fsize))
--     writeBS . B8.pack . show $ l
--   
--   site :: Snap ()
--   site = route
--     [ ("/upload",    uploadForm)
--     , ("/do-upload", doUpload)]
--   
--   main :: IO ()
--   main = quickHttpServe site
--   
module Snap.Util.FileUploads

-- | Processes form data and calls provided storage function on file parts.
--   
--   You can use this together with withTemporaryStore,
--   storeAsLazyByteString or provide your own callback to store
--   uploaded files.
--   
--   If you need to process uploaded file mime type or file name, do it in
--   the store callback function.
--   
--   See also foldMultipart.
--   
--   Example using with small files which can safely be stored in memory.
--   
--   
--   import qualified Data.ByteString.Lazy as Lazy
--   
--   handleSmallFiles :: MonadSnap m => [(ByteString, ByteString, Lazy.ByteString)]
--   handleSmallFiles = handleFormUploads uploadPolicy filePolicy store
--   
--     where
--       uploadPolicy = defaultUploadPolicy
--       filePolicy = setMaximumFileSize (64*1024)
--                    $ setMaximumNumberOfFiles 5
--                      defaultUploadPolicy
--       store partInfo stream = do
--          content <- storeAsLazyByteString partInfo stream
--          let
--            fileName = partFileName partInfo
--            fileMime = partContentType partInfo
--          in (fileName, fileMime, content)
--   
handleFormUploads :: MonadSnap m => UploadPolicy -> FileUploadPolicy -> (PartInfo -> InputStream ByteString -> IO a) -> m ([FormParam], [FormFile a])

-- | Given an upload policy and a function to consume uploaded "parts",
--   consume a request body uploaded with Content-type:
--   multipart/form-data.
--   
--   If setProcessFormInputs is True, then parts with
--   disposition form-data (a form parameter) will be processed
--   and returned as first element of resulting pair. Parts with other
--   disposition will be fed to PartFold handler.
--   
--   If setProcessFormInputs is False, then parts with any
--   disposition will be fed to PartFold handler and first element
--   of returned pair will be empty. In this case it is important that you
--   limit number of form inputs and sizes of inputs in your
--   PartFold handler to avoid common DOS attacks.
--   
--   Note: THE REQUEST MUST BE CORRECTLY ENCODED. If the request's
--   Content-type is not "multipart/formdata", this
--   function skips processing using pass.
--   
--   Most users will opt for the higher-level handleFileUploads,
--   which writes to temporary files, rather than handleMultipart.
--   This function should be chosen, however, if you need to stream
--   uploaded files directly to your own processing function: e.g. to a
--   database or a remote service via RPC.
--   
--   If the client's upload rate passes below the configured minimum (see
--   setMinimumUploadRate and setMinimumUploadSeconds), this
--   function terminates the connection. This setting is there to protect
--   the server against slowloris-style denial of service attacks.
--   
--   Exceptions
--   
--   If the given UploadPolicy stipulates that you wish form inputs
--   to be processed (using setProcessFormInputs), and a form input
--   exceeds the maximum allowable size or the form exceeds maximum number
--   of inputs, this function will throw a PolicyViolationException.
--   
--   If an uploaded part contains MIME headers longer than a fixed internal
--   threshold (currently 32KB), this function will throw a
--   BadPartException.
--   
--   Since: 1.0.3.0
foldMultipart :: MonadSnap m => UploadPolicy -> PartFold a -> a -> m ([FormParam], a)

-- | A type alias for a function that will process one of the parts of a
--   multipart/form-data HTTP request body with accumulator.
type PartFold a = PartInfo -> InputStream ByteString -> a -> IO a

-- | A form parameter name-value pair
type FormParam = (ByteString, ByteString)

-- | Contents of form field of type file
data FormFile a
FormFile :: !ByteString -> a -> FormFile a

-- | Name of a field
[formFileName] :: FormFile a -> !ByteString

-- | Result of storing file
[formFileValue] :: FormFile a -> a

-- | Stores file body in memory as Lazy ByteString.
storeAsLazyByteString :: InputStream ByteString -> IO ByteString

-- | Store files in a temporary directory, and clean up on function exit.
--   
--   Files are safe to move until function exists.
--   
--   If asynchronous exception is thrown during cleanup, temporary files
--   may remain.
--   
--   
--   uploadsHandler = withTemporaryStore "vartmp" "upload-" $ store -> do
--       (inputs, files) <- handleFormUploads defaultUploadpolicy
--                                            defaultFileUploadPolicy
--                                            (const store)
--       saveFiles files
--   
withTemporaryStore :: MonadSnap m => FilePath -> String -> ((InputStream ByteString -> IO FilePath) -> m a) -> m a

-- | Reads uploaded files into a temporary directory and calls a user
--   handler to process them.
--   
--   Note: THE REQUEST MUST BE CORRECTLY ENCODED. If the request's
--   Content-type is not "multipart/formdata", this
--   function skips processing using pass.
--   
--   Given a temporary directory, global and file-specific upload policies,
--   and a user handler, this function consumes a request body uploaded
--   with Content-type: multipart/form-data. Each file is read
--   into the temporary directory, and is then passed to the user handler.
--   After the user handler runs (but before the Response body is
--   streamed to the client), the files are deleted from disk; so if you
--   want to retain or use the uploaded files in the generated response,
--   you need to move or otherwise process them.
--   
--   The argument passed to the user handler is a tuple:
--   
--   
--   (PartInfo, Either PolicyViolationException FilePath)
--   
--   
--   The first half of this tuple is a PartInfo, which contains the
--   information the client browser sent about the given upload part (like
--   filename, content-type, etc). The second half of this tuple is an
--   Either stipulating that either:
--   
--   
--   
- the file was rejected on a policy basis because of the provided
--   PartUploadPolicy handler
--   
- the file was accepted and exists at the given path.
--   
--   
--   Exceptions
--   
--   If the client's upload rate passes below the configured minimum (see
--   setMinimumUploadRate and setMinimumUploadSeconds), this
--   function terminates the connection. This setting is there to protect
--   the server against slowloris-style denial of service attacks.
--   
--   If the given UploadPolicy stipulates that you wish form inputs
--   to be placed in the rqParams parameter map (using
--   setProcessFormInputs), and a form input exceeds the maximum
--   allowable size, this function will throw a
--   PolicyViolationException.
--   
--   If an uploaded part contains MIME headers longer than a fixed internal
--   threshold (currently 32KB), this function will throw a
--   BadPartException.
handleFileUploads :: MonadSnap m => FilePath -> UploadPolicy -> (PartInfo -> PartUploadPolicy) -> (PartInfo -> Either PolicyViolationException FilePath -> IO a) -> m [a]

-- | A variant of foldMultipart accumulating results into a list.
--   Also puts captured FormParams into rqPostParams and rqParams
--   maps.
handleMultipart :: MonadSnap m => UploadPolicy -> PartProcessor a -> m [a]

-- | A type alias for a function that will process one of the parts of a
--   multipart/form-data HTTP request body without usinc
--   accumulator.
type PartProcessor a = PartInfo -> InputStream ByteString -> IO a

-- | PartInfo contains information about a "part" in a request
--   uploaded with Content-type: multipart/form-data.
data PartInfo

-- | Represents the disposition type specified via the
--   Content-Disposition header field. See RFC 1806.
data PartDisposition

-- | Content-Disposition: attachment.
DispositionAttachment :: PartDisposition

-- | Content-Disposition: file.
DispositionFile :: PartDisposition

-- | Content-Disposition: form-data.
DispositionFormData :: PartDisposition

-- | Any other value.
DispositionOther :: ByteString -> PartDisposition

-- | Field name associated with this part (i.e., the name specified with
--   <input name="partFieldName" ...).
partFieldName :: PartInfo -> ByteString

-- | Name of the uploaded file.
partFileName :: PartInfo -> Maybe ByteString

-- | Content type of this part.
partContentType :: PartInfo -> ByteString

-- | Remaining headers associated with this part.
partHeaders :: PartInfo -> Headers

-- | Disposition type of this part. See PartDisposition.
partDisposition :: PartInfo -> PartDisposition

-- | UploadPolicy controls overall policy decisions relating to
--   multipart/form-data uploads, specifically:
--   
--   
--   
- whether to treat parts without filenames as form input (reading
--   them into the rqParams map)
--   
- because form input is read into memory, the maximum size of a form
--   input read in this manner, and the maximum number of form inputs
--   
- the minimum upload rate a client must maintain before we kill the
--   connection; if very low-bitrate uploads were allowed then a Snap
--   server would be vulnerable to a trivial denial-of-service using a
--   "slowloris"-type attack
--   
- the minimum number of seconds which must elapse before we start
--   killing uploads for having too low an upload rate.
--   
- the amount of time we should wait before timing out the connection
--   whenever we receive input from the client.
--   
data UploadPolicy

-- | A reasonable set of defaults for upload policy. The default policy is:
--   
--   
--   
- maximum form input size 128kB
--   
- maximum number of form inputs 10
--   
- minimum upload rate 1kB/s
--   
- seconds before rate limiting kicks in 10
--   
- inactivity timeout 20 seconds
--   
defaultUploadPolicy :: UploadPolicy

-- | Does this upload policy stipulate that we want to treat parts without
--   filenames as form input?
doProcessFormInputs :: UploadPolicy -> Bool

-- | Set the upload policy for treating parts without filenames as form
--   input.
setProcessFormInputs :: Bool -> UploadPolicy -> UploadPolicy

-- | Get the maximum size of a form input which will be read into our
--   rqParams map.
getMaximumFormInputSize :: UploadPolicy -> Int64

-- | Set the maximum size of a form input which will be read into our
--   rqParams map.
setMaximumFormInputSize :: Int64 -> UploadPolicy -> UploadPolicy

-- | Get the maximum size of a form input which will be read into our
--   rqParams map.
getMaximumNumberOfFormInputs :: UploadPolicy -> Int

-- | Set the maximum size of a form input which will be read into our
--   rqParams map.
setMaximumNumberOfFormInputs :: Int -> UploadPolicy -> UploadPolicy

-- | Get the minimum rate (in bytes/second) a client must maintain
--   before we kill the connection.
getMinimumUploadRate :: UploadPolicy -> Double

-- | Set the minimum rate (in bytes/second) a client must maintain
--   before we kill the connection.
setMinimumUploadRate :: Double -> UploadPolicy -> UploadPolicy

-- | Get the amount of time which must elapse before we begin enforcing the
--   upload rate minimum
getMinimumUploadSeconds :: UploadPolicy -> Int

-- | Set the amount of time which must elapse before we begin enforcing the
--   upload rate minimum
setMinimumUploadSeconds :: Int -> UploadPolicy -> UploadPolicy

-- | Get the "upload timeout". Whenever input is received from the client,
--   the connection timeout is set this many seconds in the future.
getUploadTimeout :: UploadPolicy -> Int

-- | Set the upload timeout.
setUploadTimeout :: Int -> UploadPolicy -> UploadPolicy

-- | File upload policy, if any policy is violated then
--   PolicyViolationException is thrown
data FileUploadPolicy

-- | A default FileUploadPolicy
--   
--   
--   
- maximum file size 1MB
--   
- maximum number of files 10
--   
- skip files without name yes
--   
- maximum size of skipped file 0
--   
defaultFileUploadPolicy :: FileUploadPolicy

-- | Maximum size of single uploaded file.
setMaximumFileSize :: Int64 -> FileUploadPolicy -> FileUploadPolicy

-- | Maximum number of uploaded files.
setMaximumNumberOfFiles :: Int -> FileUploadPolicy -> FileUploadPolicy

-- | Skip files with empty file names.
--   
--   If set, parts without filenames will not be fed to storage function.
--   
--   HTML5 form data encoding standard states that form input fields of
--   type file, without value set, are encoded same way as if file with
--   empty body, empty file name, and type
--   application/octet-stream was set as value.
--   
--   You most likely want to use this with zero bytes allowed to avoid
--   storing such fields (see setMaximumSkippedFileSize).
--   
--   By default files without names are skipped.
--   
--   Since: 1.0.3.0
setSkipFilesWithoutNames :: Bool -> FileUploadPolicy -> FileUploadPolicy

-- | Maximum size of file without name which can be skipped.
--   
--   Ignored if setSkipFilesWithoutNames is False.
--   
--   If skipped file is larger than this setting then
--   FileUploadException is thrown.
--   
--   By default maximum file size is 0.
--   
--   Since: 1.0.3.0
setMaximumSkippedFileSize :: Int64 -> FileUploadPolicy -> FileUploadPolicy

-- | Upload policy can be set on an "general" basis (using
--   UploadPolicy), but handlers can also make policy decisions on
--   individual files/parts uploaded. For each part uploaded, handlers can
--   decide:
--   
--   
--   
- whether to allow the file upload at all
--   
- the maximum size of uploaded files, if allowed
--   
data PartUploadPolicy

-- | Disallows the file to be uploaded.
disallow :: PartUploadPolicy

-- | Allows the file to be uploaded, with maximum size n in bytes.
allowWithMaximumSize :: Int64 -> PartUploadPolicy

-- | All of the exceptions defined in this package inherit from
--   FileUploadException, so if you write
--   
--   
--   foo `catch` \(e :: FileUploadException) -> ...
--   
--   
--   you can catch a BadPartException, a
--   PolicyViolationException, etc.
data FileUploadException

-- | Human-readable error message corresponding to the
--   FileUploadException.
fileUploadExceptionReason :: FileUploadException -> Text

-- | Thrown when a part is invalid in some way (e.g. the headers are too
--   large).
data BadPartException

-- | Human-readable error message corresponding to the
--   BadPartException.
badPartExceptionReason :: BadPartException -> Text

-- | Thrown when an UploadPolicy or PartUploadPolicy is
--   violated.
data PolicyViolationException

-- | Human-readable error message corresponding to the
--   PolicyViolationException.
policyViolationExceptionReason :: PolicyViolationException -> Text

-- | Helpers for running a Snap web handler with compression.
module Snap.Util.GZip

-- | Runs a Snap web handler with compression if available.
--   
--   If the client has indicated support for gzip or
--   deflate in its Accept-Encoding header, and the
--   Content-Type in the response is one of the following types:
--   
--   
--   
- 
application/x-javascript

--   
- 
application/json

--   
- 
text/css

--   
- 
text/html

--   
- 
text/javascript

--   
- 
text/plain

--   
- 
text/xml

--   
- 
application/x-font-truetype

--   
--   
--   Then the given handler's output stream will be compressed,
--   Content-Encoding will be set in the output headers, and the
--   Content-Length will be cleared if it was set. (We can't
--   process the stream in O(1) space if the length is known beforehand.)
--   
--   The wrapped handler will be run to completion, and then the
--   Response that's contained within the Snap monad
--   state will be passed to finishWith to prevent further
--   processing.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/" M.empty >> T.addHeader "Accept-Encoding" "gzip,deflate"
--   ghci> let h = modifyResponse (setContentType "text/plain") >> writeBS "some text"
--   ghci> T.runHandler r h
--   HTTP/1.1 200 OK
--   content-type: text/plain
--   server: Snap/test
--   date: Fri, 08 Aug 2014 15:40:45 GMT
--   
--   some text
--   ghci> T.runHandler r (withCompression h)
--   HTTP/1.1 200 OK
--   content-type: text/plain
--   vary: Accept-Encoding
--   content-encoding: gzip
--   server: Snap/test
--   date: Fri, 08 Aug 2014 15:40:10 GMT
--   
withCompression :: MonadSnap m => m a -> m ()

-- | The same as withCompression, with control over which MIME types
--   to compress.
withCompression' :: MonadSnap m => Set ByteString -> m a -> m ()

-- | Turn off compression by setting "Content-Encoding: identity" in the
--   response headers. withCompression is a no-op when a
--   content-encoding is already set.
noCompression :: MonadSnap m => m ()

-- | Thrown when the 'Accept-Encoding' request header has invalid format.
data BadAcceptEncodingException
compressibleMimeTypes :: Set ByteString
instance GHC.Internal.Exception.Type.Exception Snap.Util.GZip.BadAcceptEncodingException
instance GHC.Internal.Show.Show Snap.Util.GZip.BadAcceptEncodingException

-- | This module provides facilities for patching incoming
--   Requests to correct the value of rqClientAddr if the
--   snap server is running behind a proxy.
--   
--   Example usage:
--   
--   
--   m :: Snap ()
--   m = undefined  -- code goes here
--   
--   applicationHandler :: Snap ()
--   applicationHandler = behindProxy X_Forwarded_For m
--   
module Snap.Util.Proxy

-- | What kind of proxy is this? Affects which headers behindProxy
--   pulls the original remote address from.
--   
--   Currently only proxy servers that send X-Forwarded-For or
--   Forwarded-For are supported.
data ProxyType

-- | no proxy, leave the request alone
NoProxy :: ProxyType

-- | Use the Forwarded-For or X-Forwarded-For header
X_Forwarded_For :: ProxyType

-- | Rewrite rqClientAddr if we're behind a proxy.
--   
--   Example:
--   
--   
--   ghci> :set -XOverloadedStrings
--   ghci> import qualified Data.Map as M
--   ghci> import qualified Snap.Test as T
--   ghci> let r = T.get "/foo" M.empty >> T.addHeader "X-Forwarded-For" "1.2.3.4"
--   ghci> let h = getsRequest rqClientAddr >>= writeBS)
--   ghci> T.runHandler r h
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Fri, 08 Aug 2014 14:32:29 GMT
--   
--   127.0.0.1
--   ghci> T.runHandler r (behindProxy X_Forwarded_For h)
--   HTTP/1.1 200 OK
--   server: Snap/test
--   date: Fri, 08 Aug 2014 14:33:02 GMT
--   
--   1.2.3.4
--   
behindProxy :: MonadSnap m => ProxyType -> m a -> m a
instance GHC.Classes.Eq Snap.Util.Proxy.ProxyType
instance GHC.Classes.Ord Snap.Util.Proxy.ProxyType
instance GHC.Internal.Read.Read Snap.Util.Proxy.ProxyType
instance GHC.Internal.Show.Show Snap.Util.Proxy.ProxyType
