A web handler which, given a mapping from URL entry points to web
handlers, efficiently routes requests to the correct handler.

The URL entry points are given as relative paths, for example:

route [ ("foo/bar/quux", fooBarQuux) ]

If the URI of the incoming request is

/foo/bar/quux

or

/foo/bar/quux/...anything...

then the request will be routed to "fooBarQuux", with rqContextPath
set to "/foo/bar/quux/" and rqPathInfo set to
"...anything...".

A path component within an URL entry point beginning with a colon (":")
is treated as a variable capture; the corresponding path component within
the request URI will be entered into the rqParams parameters mapping with
the given name. For instance, if the routes were:

route [ ("foo/:bar/baz", fooBazHandler) ]

Then a request for "/foo/saskatchewan/baz" would be routed to
fooBazHandler with a mapping for:

"bar" => "saskatchewan"

in its parameters table.

Longer paths are matched first, and specific routes are matched before
captures. That is, if given routes:

[ ("a", h1), ("a/b", h2), ("a/:x", h3) ]

a request for "/a/b" will go to h2, "/a/s" for any s will go
to h3, and "/a" will go to h1.

The following example matches "/article" to an article index,
"/login" to a login, and "/article/..." to an article renderer.

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.

Detaches the request body's Enumerator from the Request and
returns it. You would want to use this if you needed to send the
HTTP request body (transformed or otherwise) through to the output
in O(1) space. (Examples: transcoding, "echo", etc)

Normally Snap is careful to ensure that the request body is fully
consumed after your web handler runs; this function is marked
"unsafe" because it breaks this guarantee and leaves the
responsibility up to you. If you don't fully consume the
Enumerator you get here, the next HTTP request in the pipeline
(if any) will misparse. Be careful with exception handlers.

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"].

Handlers can (will be; --ed) be hung on a URI "entry point";
this is called the "context path". If a handler is hung on the
context path "/foo/", and you request "/foo/bar", the value
of rqPathInfo will be "bar".

The "context path" of the request; catenating rqContextPath, and
rqPathInfo should get you back to the original rqURI. The
rqContextPath always begins and ends with a slash ("/")
character, and represents the path (relative to your
component/snaplet) you took to get to your handler.

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.

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.

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().