-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | HTTP Daemonic Library -- -- Lucu is an HTTP daemonic library. It can be embedded in any Haskell -- program and runs in an independent thread. Lucu is not a replacement -- for Apache. It is intended to be used to create an efficient web-based -- application without messing around FastCGI. It is also intended to be -- run behind a reverse-proxy so it doesn't have some facilities like -- logging, client filtering or such like. @package Lucu @version 0.2 -- | Utility functions used internally in the Lucu httpd. These functions -- may be useful too for something else. module Network.HTTP.Lucu.Utils -- |
-- splitBy (== ':') "ab:c:def" -- ==> ["ab", "c", "def"] --splitBy :: (a -> Bool) -> [a] -> [[a]] -- |
-- joinWith ":" ["ab", "c", "def"] -- ==> "ab:c:def" --joinWith :: [a] -> [[a]] -> [a] -- |
-- trim (== '_') "__ab_c__def___" -- ==> "ab_c__def" --trim :: (a -> Bool) -> [a] -> [a] -- | isWhiteSpace c is True iff c is one of SP, HT, -- CR and LF. isWhiteSpace :: Char -> Bool -- |
-- quoteStr "abc" -- ==> "\"abc\"" ---- --
-- quoteStr "ab\"c" -- ==> "\"ab\\\"c\"" --quoteStr :: String -> String -- |
-- parseWWWFormURLEncoded "aaa=bbb&ccc=ddd"
-- ==> [("aaa", "bbb"), ("ccc", "ddd")]
--
parseWWWFormURLEncoded :: String -> [(String, String)]
-- | Yet another parser combinator. This is mostly a subset of
-- Text.ParserCombinators.Parsec but there are some differences:
--
-- Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC -- 1123
Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC -- 1036
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() -- format
-- abort MovedPermanently
-- [("Location", "http://example.net/")]
-- (Just "It has been moved to example.net")
--
abort :: (MonadIO m) => StatusCode -> [(String, String)] -> Maybe String -> m a
-- | This is similar to abort but computes it with
-- unsafePerformIO.
abortPurely :: StatusCode -> [(String, String)] -> Maybe String -> a
-- | Computation of abortSTM status headers msg just
-- computes abort in a Control.Monad.STM.STM monad.
abortSTM :: StatusCode -> [(String, String)] -> Maybe String -> STM a
-- | Computation of abortA -< (status, (headers, msg))
-- just computes abort in an ArrowIO.
abortA :: (ArrowIO a) => a (StatusCode, ([(String, String)], Maybe String)) c
instance Typeable Abortion
instance Show Abortion
instance Exception Abortion
-- | This is the Resource Monad; monadic actions to define the behavior of
-- each resources. The Resource Monad is a kind of IO Monad
-- thus it implements Control.Monad.Trans.MonadIO class. It is also a
-- state machine.
--
-- Request Processing Flow:
--
-- 1. A client issues an HTTP request.
--
-- 2. If the URI of it matches to any resource, the corresponding
-- Resource Monad starts running on a newly spawned thread.
--
-- 3. The Resource Monad looks at the request header, find (or not
-- find) an entity, receive the request body (if any), decide the
-- response header, and decide the response body. This process will be
-- discussed later.
--
-- 4. The Resource Monad and its thread stops running. The client
-- may or may not be sending us the next request at this point.
--
-- Resource Monad takes the following states. The initial state is
-- Examining Request and the final state is Done.
--
--
-- main = let tree = mkResTree [ (["foo"], resFoo) ]
-- in runHttpd defaultConfig tree
--
-- resFoo = ResourceDef {
-- resIsGreedy = True
-- , resGet = Just $ do requestURI <- getRequestURI
-- resourcePath <- getResourcePath
-- pathInfo <- getPathInfo
-- -- uriPath requestURI == "/foo/bar/baz"
-- -- resourcePath == ["foo"]
-- -- pathInfo == ["bar", "baz"]
-- ...
-- , ...
-- }
--
getResourcePath :: Resource [String]
-- | This is an analogy of CGI PATH_INFO. Its result is always []
-- if the Network.HTTP.Lucu.Resource.Tree.ResourceDef is not greedy. See
-- getResourcePath.
getPathInfo :: Resource [String]
-- | Assume the query part of request URI as
-- application/x-www-form-urlencoded, and parse it. This action doesn't
-- parse the request body. See inputForm.
getQueryForm :: Resource [(String, String)]
-- | Get a value of given request header. Comparison of header name is
-- case-insensitive. Note that this action is not intended to be used so
-- frequently: there should be actions like getContentType for
-- every common headers.
getHeader :: ByteString -> Resource (Maybe ByteString)
-- | Get a list of MIMEType enumerated on header "Accept".
getAccept :: Resource [MIMEType]
-- | Get a list of (contentCoding, qvalue) enumerated on header
-- "Accept-Encoding". The list is sorted in descending order by qvalue.
getAcceptEncoding :: Resource [(String, Maybe Double)]
-- | Check whether a given content-coding is acceptable.
isEncodingAcceptable :: String -> Resource Bool
-- | Get the header "Content-Type" as MIMEType.
getContentType :: Resource (Maybe MIMEType)
-- | Get the header "Authorization" as AuthCredential.
getAuthorization :: Resource (Maybe AuthCredential)
-- | Tell the system that the Resource found an entity for the
-- request URI. If this is a GET or HEAD request, a found entity means a
-- datum to be replied. If this is a PUT or DELETE request, it means a
-- datum which was stored for the URI up to now. It is an error to
-- compute foundEntity if this is a POST request.
--
-- Computation of foundEntity performs "If-Match" test or
-- "If-None-Match" test if possible. When those tests fail, the
-- computation of Resource immediately aborts with status "412
-- Precondition Failed" or "304 Not Modified" depending on the situation.
--
-- If this is a GET or HEAD request, foundEntity automatically
-- puts "ETag" and "Last-Modified" headers into the response.
foundEntity :: ETag -> UTCTime -> Resource ()
-- | Tell the system that the Resource found an entity for the
-- request URI. The only difference from foundEntity is that
-- foundETag doesn't (and can't) put "Last-Modified" header into
-- the response.
--
-- This action is not preferred. You should use foundEntity
-- whenever possible.
foundETag :: ETag -> Resource ()
-- | Tell the system that the Resource found an entity for the
-- request URI. The only difference from foundEntity is that
-- foundTimeStamp performs "If-Modified-Since" test or
-- "If-Unmodified-Since" test instead of "If-Match" test or
-- "If-None-Match" test. Be aware that any tests based on last
-- modification time are unsafe because it is possible to mess up such
-- tests by modifying the entity twice in a second.
--
-- This action is not preferred. You should use foundEntity
-- whenever possible.
foundTimeStamp :: UTCTime -> Resource ()
-- | Computation of foundNoEntity mStr tells the system
-- that the Resource found no entity for the request URI.
-- mStr is an optional error message to be replied to the
-- client.
--
-- If this is a PUT request, foundNoEntity performs "If-Match"
-- test and aborts with status "412 Precondition Failed" when it failed.
-- If this is a GET, HEAD, POST or DELETE request, foundNoEntity
-- always aborts with status "404 Not Found".
foundNoEntity :: Maybe String -> Resource ()
-- | Computation of input limit attempts to read the
-- request body up to limit bytes, and then make the
-- Resource transit to Deciding Header state. When the
-- actual size of body is larger than limit bytes, computation
-- of Resource immediately aborts with status "413 Request Entity
-- Too Large". When the request has no body, input returns an
-- empty string.
--
-- limit may be less than or equal to zero. In this case, the
-- default limitation value (cnfMaxEntityLength) is used. See
-- defaultLimit.
--
-- Note that inputLBS is more efficient than input so you
-- should use it whenever possible.
input :: Int -> Resource String
-- | Computation of inputChunk limit attempts to read a
-- part of request body up to limit bytes. You can read any
-- large request by repeating computation of this action. When you've
-- read all the request body, inputChunk returns an empty string
-- and then make the Resource transit to Deciding Header
-- state.
--
-- limit may be less than or equal to zero. In this case, the
-- default limitation value (cnfMaxEntityLength) is used. See
-- defaultLimit.
--
-- Note that inputChunkLBS is more efficient than
-- inputChunk so you should use it whenever possible.
inputChunk :: Int -> Resource String
-- | This is mostly the same as input but is more efficient.
-- inputLBS returns a Data.ByteString.Lazy.ByteString but it's not
-- really lazy: reading from the socket just happens at the computation
-- of inputLBS, not at the evaluation of the
-- Data.ByteString.Lazy.ByteString. The same goes for
-- inputChunkLBS.
inputLBS :: Int -> Resource ByteString
-- | This is mostly the same as inputChunk but is more efficient.
-- See inputLBS.
inputChunkLBS :: Int -> Resource ByteString
-- | Computation of inputForm limit attempts to read the
-- request body with input and parse it as
-- application/x-www-form-urlencoded or multipart/form-data. If the
-- request header "Content-Type" is neither of them, inputForm
-- makes Resource abort with status "415 Unsupported Media Type".
-- If the request has no "Content-Type", it aborts with "400 Bad
-- Request".
inputForm :: Int -> Resource [(String, String)]
-- | This is just a constant -1. It's better to say
-- input defaultLimit than to say input
-- (-1) but these are exactly the same.
defaultLimit :: Int
-- | Set the response status code. If you omit to compute this action, the
-- status code will be defaulted to "200 OK".
setStatus :: StatusCode -> Resource ()
-- | Set a value of given resource header. Comparison of header name is
-- case-insensitive. Note that this action is not intended to be used so
-- frequently: there should be actions like setContentType for
-- every common headers.
--
-- Some important headers (especially "Content-Length" and
-- "Transfer-Encoding") may be silently dropped or overwritten by the
-- system not to corrupt the interaction with client at the viewpoint of
-- HTTP protocol layer. For instance, if we are keeping the connection
-- alive, without this process it causes a catastrophe to send a header
-- "Content-Length: 10" and actually send a body of 20 bytes long. In
-- this case the client shall only accept the first 10 bytes of response
-- body and thinks that the residual 10 bytes is a part of header of the
-- next response.
setHeader :: ByteString -> ByteString -> Resource ()
-- | Computation of redirect code uri sets the response
-- status to code and "Location" header to uri. The
-- code must satisfy isRedirection or it causes an error.
redirect :: StatusCode -> URI -> Resource ()
-- | Computation of setContentType mType sets the response
-- header "Content-Type" to mType.
setContentType :: MIMEType -> Resource ()
-- | Computation of setLocation uri sets the response
-- header "Location" to uri.
setLocation :: URI -> Resource ()
-- | Computation of setContentEncoding codings sets the
-- response header "Content-Encoding" to codings.
setContentEncoding :: [String] -> Resource ()
-- | Computation of setWWWAuthenticate challenge sets the
-- response header "WWW-Authenticate" to challenge.
setWWWAuthenticate :: AuthChallenge -> Resource ()
-- | Computation of output str writes str as a
-- response body, and then make the Resource transit to
-- Done state. It is safe to apply output to an infinite
-- string, such as a lazy stream of /dev/random.
--
-- Note that outputLBS is more efficient than output so you
-- should use it whenever possible.
output :: String -> Resource ()
-- | Computation of outputChunk str writes str as
-- a part of response body. You can compute this action multiple times to
-- write a body little at a time. It is safe to apply outputChunk
-- to an infinite string.
--
-- Note that outputChunkLBS is more efficient than
-- outputChunk so you should use it whenever possible.
outputChunk :: String -> Resource ()
-- | This is mostly the same as output but is more efficient.
outputLBS :: ByteString -> Resource ()
-- | This is mostly the same as outputChunk but is more efficient.
outputChunkLBS :: ByteString -> Resource ()
instance MonadIO Resource
instance Monad Resource
instance Functor Resource
-- | Repository of the resources in httpd.
module Network.HTTP.Lucu.Resource.Tree
-- | ResourceDef is basically a set of Resource monads for
-- each HTTP methods.
data ResourceDef
ResourceDef :: !Bool -> !Bool -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> ResourceDef
-- | Whether to run a Resource on a native thread (spawned by
-- forkOS) or to run it on a user thread (spanwed by
-- forkIO). Generally you don't need to set this field to
-- True.
resUsesNativeThread :: ResourceDef -> !Bool
-- | Whether to be greedy or not.
--
-- Say a client is trying to access /aaa/bbb/ccc. If there is a greedy
-- resource at /aaa/bbb, it is always chosen even if there is another
-- resource at /aaa/bbb/ccc. If the resource at /aaa/bbb is not greedy,
-- it is just ignored. Greedy resources are like CGI scripts.
resIsGreedy :: ResourceDef -> !Bool
-- | A Resource to be run when a GET request comes for the resource
-- path. If resGet is Nothing, the system responds "405 Method Not
-- Allowed" for GET requests.
--
-- It also runs for HEAD request if the resHead is Nothing. In
-- this case output and such like don't actually write a response
-- body.
resGet :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a HEAD request comes for the resource
-- path. If resHead is Nothing, the system runs resGet
-- instead. If resGet is also Nothing, the system responds "405
-- Method Not Allowed" for HEAD requests.
resHead :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a POST request comes for the resource
-- path. If resPost is Nothing, the system responds "405 Method
-- Not Allowed" for POST requests.
resPost :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a PUT request comes for the resource
-- path. If resPut is Nothing, the system responds "405 Method Not
-- Allowed" for PUT requests.
resPut :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a DELETE request comes for the
-- resource path. If resDelete is Nothing, the system responds
-- "405 Method Not Allowed" for DELETE requests.
resDelete :: ResourceDef -> !Maybe (Resource ())
-- | ResTree is an opaque structure which is a map from resource
-- path to ResourceDef.
data ResTree
-- | FallbackHandler is an extra resource handler for resources
-- which can't be statically located somewhere in the resource tree. The
-- Lucu httpd first search for a resource in the tree, and then call
-- fallback handlers to ask them for a resource. If all of the handlers
-- returned Nothing, the httpd responds with 404 Not Found.
type FallbackHandler = [String] -> IO (Maybe ResourceDef)
-- | mkResTree converts a list of (path, def) to a
-- ResTree e.g.
--
-- -- mkResTree [ ([] , Network.HTTP.Lucu.StaticFile.staticFile "/usr/include/stdio.h" ) -- / -- , (["unistd"], Network.HTTP.Lucu.StaticFile.staticFile "/usr/include/unistd.h") -- /unistd -- ] --mkResTree :: [([String], ResourceDef)] -> ResTree -- | Handling static files on the filesystem. module Network.HTTP.Lucu.StaticFile -- | staticFile fpath is a ResourceDef which serves -- the file at fpath on the filesystem. staticFile :: FilePath -> ResourceDef -- | Computation of handleStaticFile fpath serves the file -- at fpath on the filesystem. The Resource must be in -- the /Examining Request state before the computation. It will be in -- the Done/ state after the computation. -- -- If you just want to place a static file on the ResTree, you had -- better use staticFile instead of this. handleStaticFile :: FilePath -> Resource () -- | staticDir dir is a ResourceDef which maps all -- files in dir and its subdirectories on the filesystem to the -- ResTree. staticDir :: FilePath -> ResourceDef -- | Computation of handleStaticDir dir maps all files in -- dir and its subdirectories on the filesystem to the -- ResTree. The Resource must be in the /Examining -- Request state before the computation. It will be in the Done/ -- state after the computation. -- -- If you just want to place a static directory tree on the -- ResTree, you had better use staticDir instead of this. handleStaticDir :: FilePath -> Resource () -- | Computation of generateETagFromFile fpath generates a -- strong entity tag from a file. The file doesn't necessarily have to be -- a regular file; it may be a FIFO or a device file. The tag is made of -- inode ID, size and modification time. -- -- Note that the tag is not strictly strong because the file could be -- modified twice at a second without changing inode ID or size, but it's -- not really possible to generate a strict strong ETag from a file since -- we don't want to simply grab the entire file and use it as an ETag. It -- is indeed possible to hash it with SHA-1 or MD5 to increase -- strictness, but it's too inefficient if the file is really large (say, -- 1 TiB). generateETagFromFile :: FilePath -> IO ETag -- | The entry point of Lucu httpd. module Network.HTTP.Lucu.Httpd -- | FallbackHandler is an extra resource handler for resources -- which can't be statically located somewhere in the resource tree. The -- Lucu httpd first search for a resource in the tree, and then call -- fallback handlers to ask them for a resource. If all of the handlers -- returned Nothing, the httpd responds with 404 Not Found. type FallbackHandler = [String] -> IO (Maybe ResourceDef) -- | This is the entry point of Lucu httpd. It listens to a socket and -- waits for clients. Computation of runHttpd never stops by -- itself so the only way to stop it is to raise an exception in the -- thread computing it. -- -- Note that runHttpd automatically makes SIGPIPE be ignored by -- computing installHandler sigPIPE Ignore -- Nothing. This can hardly cause a problem but it may do. -- -- Example: -- --
-- module Main where
-- import Network.HTTP.Lucu
--
-- main :: IO ()
-- main = let config = defaultConfig
-- resources = mkResTree [ ([], helloWorld) ]
-- in
-- runHttpd config resourcees []
--
-- helloWorld :: ResourceDef
-- helloWorld = ResourceDef {
-- resUsesNativeThread = False
-- , resIsGreedy = False
-- , resGet
-- = Just $ do setContentType $ read "text/plain"
-- output "Hello, world!"
-- , resHead = Nothing
-- , resPost = Nothing
-- , resPut = Nothing
-- , resDelete = Nothing
-- }
--
runHttpd :: Config -> ResTree -> [FallbackHandler] -> IO ()
-- | Lucu is an HTTP daemonic library. It can be embedded in any Haskell
-- program and runs in an independent thread.
--
-- Features:
--
--
-- module Main where
-- import Network.HTTP.Lucu
--
-- main :: IO ()
-- main = let config = defaultConfig
-- resources = mkResTree [ ([], helloWorld) ]
-- in
-- runHttpd config resourcees []
--
-- helloWorld :: ResourceDef
-- helloWorld = ResourceDef {
-- resUsesNativeThread = False
-- , resIsGreedy = False
-- , resGet
-- = Just $ do setContentType $ read "text/plain"
-- output "Hello, world!"
-- , resHead = Nothing
-- , resPost = Nothing
-- , resPut = Nothing
-- , resDelete = Nothing
-- }
--
runHttpd :: Config -> ResTree -> [FallbackHandler] -> IO ()
-- | ResourceDef is basically a set of Resource monads for
-- each HTTP methods.
data ResourceDef
ResourceDef :: !Bool -> !Bool -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> !Maybe (Resource ()) -> ResourceDef
-- | Whether to run a Resource on a native thread (spawned by
-- forkOS) or to run it on a user thread (spanwed by
-- forkIO). Generally you don't need to set this field to
-- True.
resUsesNativeThread :: ResourceDef -> !Bool
-- | Whether to be greedy or not.
--
-- Say a client is trying to access /aaa/bbb/ccc. If there is a greedy
-- resource at /aaa/bbb, it is always chosen even if there is another
-- resource at /aaa/bbb/ccc. If the resource at /aaa/bbb is not greedy,
-- it is just ignored. Greedy resources are like CGI scripts.
resIsGreedy :: ResourceDef -> !Bool
-- | A Resource to be run when a GET request comes for the resource
-- path. If resGet is Nothing, the system responds "405 Method Not
-- Allowed" for GET requests.
--
-- It also runs for HEAD request if the resHead is Nothing. In
-- this case output and such like don't actually write a response
-- body.
resGet :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a HEAD request comes for the resource
-- path. If resHead is Nothing, the system runs resGet
-- instead. If resGet is also Nothing, the system responds "405
-- Method Not Allowed" for HEAD requests.
resHead :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a POST request comes for the resource
-- path. If resPost is Nothing, the system responds "405 Method
-- Not Allowed" for POST requests.
resPost :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a PUT request comes for the resource
-- path. If resPut is Nothing, the system responds "405 Method Not
-- Allowed" for PUT requests.
resPut :: ResourceDef -> !Maybe (Resource ())
-- | A Resource to be run when a DELETE request comes for the
-- resource path. If resDelete is Nothing, the system responds
-- "405 Method Not Allowed" for DELETE requests.
resDelete :: ResourceDef -> !Maybe (Resource ())
-- | ResTree is an opaque structure which is a map from resource
-- path to ResourceDef.
data ResTree
-- | mkResTree converts a list of (path, def) to a
-- ResTree e.g.
--
-- -- mkResTree [ ([] , Network.HTTP.Lucu.StaticFile.staticFile "/usr/include/stdio.h" ) -- / -- , (["unistd"], Network.HTTP.Lucu.StaticFile.staticFile "/usr/include/unistd.h") -- /unistd -- ] --mkResTree :: [([String], ResourceDef)] -> ResTree -- | This is the definition of HTTP status code. -- Network.HTTP.Lucu.Resource.setStatus accepts these named statuses so -- you don't have to memorize, for instance, that "Gateway Timeout" is -- 504. data StatusCode Continue :: StatusCode SwitchingProtocols :: StatusCode Processing :: StatusCode Ok :: StatusCode Created :: StatusCode Accepted :: StatusCode NonAuthoritativeInformation :: StatusCode NoContent :: StatusCode ResetContent :: StatusCode PartialContent :: StatusCode MultiStatus :: StatusCode MultipleChoices :: StatusCode MovedPermanently :: StatusCode Found :: StatusCode SeeOther :: StatusCode NotModified :: StatusCode UseProxy :: StatusCode TemporaryRedirect :: StatusCode BadRequest :: StatusCode Unauthorized :: StatusCode PaymentRequired :: StatusCode Forbidden :: StatusCode NotFound :: StatusCode MethodNotAllowed :: StatusCode NotAcceptable :: StatusCode ProxyAuthenticationRequired :: StatusCode RequestTimeout :: StatusCode Conflict :: StatusCode Gone :: StatusCode LengthRequired :: StatusCode PreconditionFailed :: StatusCode RequestEntityTooLarge :: StatusCode RequestURITooLarge :: StatusCode UnsupportedMediaType :: StatusCode RequestRangeNotSatisfiable :: StatusCode ExpectationFailed :: StatusCode UnprocessableEntitiy :: StatusCode Locked :: StatusCode FailedDependency :: StatusCode InternalServerError :: StatusCode NotImplemented :: StatusCode BadGateway :: StatusCode ServiceUnavailable :: StatusCode GatewayTimeout :: StatusCode HttpVersionNotSupported :: StatusCode InsufficientStorage :: StatusCode -- | Computation of abort status headers msg aborts the -- Network.HTTP.Lucu.Resource.Resource monad with given status, -- additional response headers, and optional message string. -- -- What this really does is to throw a special Exception. The -- exception will be caught by the Lucu system. -- -- 1. If the Network.HTTP.Lucu.Resource.Resource is in the /Deciding -- Header/ or any precedent states, it is possible to use the -- status and such like as a HTTP response to be sent to the -- client. -- -- 2. Otherwise the HTTP response can't be modified anymore so the only -- possible thing the system can do is to dump it to the stderr. See -- cnfDumpTooLateAbortionToStderr. -- -- Note that the status code doesn't have to be an error code so you can -- use this action for redirection as well as error reporting e.g. -- --
-- abort MovedPermanently
-- [("Location", "http://example.net/")]
-- (Just "It has been moved to example.net")
--
abort :: (MonadIO m) => StatusCode -> [(String, String)] -> Maybe String -> m a
-- | This is similar to abort but computes it with
-- unsafePerformIO.
abortPurely :: StatusCode -> [(String, String)] -> Maybe String -> a
-- | Computation of abortA -< (status, (headers, msg))
-- just computes abort in an ArrowIO.
abortA :: (ArrowIO a) => a (StatusCode, ([(String, String)], Maybe String)) c
-- | An entity tag is made of a weakness flag and a opaque string.
data ETag
ETag :: !Bool -> !String -> ETag
-- | The weakness flag. Weak tags looks like W/"blahblah" and strong tags
-- are like "blahblah".
etagIsWeak :: ETag -> !Bool
-- | An opaque string. Only characters from 0x20 (sp) to 0x7e (~) are
-- allowed.
etagToken :: ETag -> !String
-- | This is equivalent to ETag False. If you want
-- to generate an ETag from a file, try using
-- Network.HTTP.Lucu.StaticFile.generateETagFromFile.
strongETag :: String -> ETag
-- | This is equivalent to ETag True.
weakETag :: String -> ETag
-- | MIMEType "major" "minor" [("name", "value")]
-- represents "major/minor; name=value".
data MIMEType
MIMEType :: !String -> !String -> ![(String, String)] -> MIMEType
mtMajor :: MIMEType -> !String
mtMinor :: MIMEType -> !String
mtParams :: MIMEType -> ![(String, String)]
-- | Authorization challenge to be sent to client with "WWW-Authenticate"
-- header. See Network.HTTP.Lucu.Resource.setWWWAuthenticate.
data AuthChallenge
BasicAuthChallenge :: Realm -> AuthChallenge
-- | Authorization credential to be sent by client with "Authorization"
-- header. See Network.HTTP.Lucu.Resource.getAuthorization.
data AuthCredential
BasicAuthCredential :: UserID -> Password -> AuthCredential