-- 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.6 -- | 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: -- -- -- -- In general, you don't have to use this module directly. module Network.HTTP.Lucu.Parser -- | Parser a is obviously a parser which parses and -- returns a. data Parser a data ParserResult a Success :: !a -> ParserResult a IllegalInput :: ParserResult a ReachedEOF :: ParserResult a -- | failP is just a synonym for fail -- undefined. failP :: Parser a -- | parse p bstr parses bstr with p and -- returns (# result, remaining #). parse :: Parser a -> ByteString -> (# ParserResult a, ByteString #) -- | parseStr p str packs str and parses it. parseStr :: Parser a -> String -> (# ParserResult a, ByteString #) anyChar :: Parser Char eof :: Parser () -- | allowEOF p makes p treat reaching EOF a -- normal failure. allowEOF :: Parser a -> Parser a satisfy :: (Char -> Bool) -> Parser Char char :: Char -> Parser Char string :: String -> Parser String -- | This is the backtracking alternation. There is no non-backtracking -- equivalent. (<|>) :: Parser a -> Parser a -> Parser a choice :: [Parser a] -> Parser a oneOf :: [Char] -> Parser Char digit :: Parser Char hexDigit :: Parser Char notFollowedBy :: Parser a -> Parser () many :: Parser a -> Parser [a] manyChar :: Parser Char -> Parser ByteString many1 :: Parser a -> Parser [a] count :: Int -> Parser a -> Parser [a] option :: a -> Parser a -> Parser a sepBy :: Parser a -> Parser sep -> Parser [a] sepBy1 :: Parser a -> Parser sep -> Parser [a] sp :: Parser Char ht :: Parser Char crlf :: Parser String instance (Eq a) => Eq (ParserResult a) instance (Show a) => Show (ParserResult a) instance Eq ParserState instance Show ParserState instance Functor Parser instance Monad Parser -- | This is an auxiliary parser utilities for parsing things related on -- HTTP protocol. -- -- In general you don't have to use this module directly. module Network.HTTP.Lucu.Parser.Http -- | isCtl c is False iff 0x20 <= c -- < 0x7F. isCtl :: Char -> Bool -- | isSeparator c is True iff c is one of HTTP -- separators. isSeparator :: Char -> Bool -- | isChar c is True iff c <= 0x7f. isChar :: Char -> Bool -- | isToken c is equivalent to not (isCtl c || -- isSeparator c) isToken :: Char -> Bool -- | listOf p is similar to sepBy p (char -- ',') but it allows any occurrences of LWS before and after each -- tokens. listOf :: Parser a -> Parser [a] -- | token is equivalent to many1 $ satisfy -- isToken token :: Parser String -- | lws is an HTTP LWS: crlf? (sp | -- ht)+ lws :: Parser String -- | text accepts one character which doesn't satisfy isCtl. text :: Parser Char -- | separator accepts one character which satisfies -- isSeparator. separator :: Parser Char -- | quotedStr accepts a string surrounded by double quotation -- marks. Quotes can be escaped by backslashes. quotedStr :: Parser String -- | qvalue accepts a so-called qvalue. qvalue :: Parser Double -- | Manipulation of HTTP version string. module Network.HTTP.Lucu.HttpVersion -- | HttpVersion major minor represents "HTTP/major.minor". data HttpVersion HttpVersion :: !Int -> !Int -> HttpVersion instance Eq HttpVersion instance Ord HttpVersion instance Show HttpVersion -- | Definition of things related on HTTP request. -- -- In general you don't have to use this module directly. module Network.HTTP.Lucu.Request -- | This is the definition of HTTP request methods, which shouldn't -- require any description. data Method OPTIONS :: Method GET :: Method HEAD :: Method POST :: Method PUT :: Method DELETE :: Method TRACE :: Method CONNECT :: Method ExtensionMethod :: !String -> Method -- | This is the definition of HTTP reqest. data Request Request :: !Method -> !URI -> !HttpVersion -> !Headers -> Request reqMethod :: Request -> !Method reqURI :: Request -> !URI reqVersion :: Request -> !HttpVersion reqHeaders :: Request -> !Headers instance Show Request instance Eq Request instance Eq Method instance Show Method instance HasHeaders Request -- | Definition of things related on HTTP response. module Network.HTTP.Lucu.Response -- | 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 -- | isInformational sc is True iff sc < -- 200. isInformational :: StatusCode -> Bool -- | isSuccessful sc is True iff 200 <= sc -- < 300. isSuccessful :: StatusCode -> Bool -- | isRedirection sc is True iff 300 <= sc -- < 400. isRedirection :: StatusCode -> Bool -- | isError sc is True iff 400 <= sc isError :: StatusCode -> Bool -- | isClientError sc is True iff 400 <= sc -- < 500. isClientError :: StatusCode -> Bool -- | isServerError sc is True iff 500 <= -- sc. isServerError :: StatusCode -> Bool -- | statusCode sc returns an unboxed tuple of numeric and -- textual representation of sc. statusCode :: StatusCode -> (# Int, ByteString #) instance Typeable StatusCode instance Show Response instance Eq Response instance Eq StatusCode instance HasHeaders Response instance Show StatusCode -- | Manipulation of MIME Types. module Network.HTTP.Lucu.MIMEType -- | 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)] -- | Parse MIMEType from a String. This function throws an -- exception for parse error. parseMIMEType :: String -> MIMEType instance Eq MIMEType instance Read MIMEType instance Show MIMEType -- | MIME Type guessing by a file extension. This is a poor man's way of -- guessing MIME Types. It is simple and fast. -- -- In general you don't have to use this module directly. module Network.HTTP.Lucu.MIMEType.Guess -- | Map from extension to MIME Type. type ExtMap = Map String MIMEType -- | Guess the MIME Type of file. guessTypeByFileName :: ExtMap -> FilePath -> Maybe MIMEType -- | Read an Apache mime.types and parse it. parseExtMapFile :: FilePath -> IO ExtMap -- | serializeExtMap extMap moduleName variableName -- generates a Haskell source code which contains the following things: -- -- -- -- The module Network.HTTP.Lucu.MIMEType.DefaultExtensionMap is -- surely generated using this function. serializeExtMap :: ExtMap -> String -> String -> String -- | This module is automatically generated from data/mime.types. -- defaultExtensionMap contains every possible pairs of an -- extension and a MIME Type. module Network.HTTP.Lucu.MIMEType.DefaultExtensionMap defaultExtensionMap :: ExtMap -- | Manipulation of entity tags. module Network.HTTP.Lucu.ETag -- | 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 instance Eq ETag instance Show ETag -- | Manipulation of WWW authorization. module Network.HTTP.Lucu.Authorization -- | 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 -- | Realm is just a string which must not contain any non-ASCII -- letters. type Realm = String -- | UserID is just a string which must not contain colon and any -- non-ASCII letters. type UserID = String -- | Password is just a string which must not contain any non-ASCII -- letters. type Password = String instance Show AuthCredential instance Eq AuthCredential instance Eq AuthChallenge instance Show AuthChallenge -- | Configurations for the Lucu httpd like a port to listen. module Network.HTTP.Lucu.Config -- | Configuration record for the Lucu httpd. You need to use -- defaultConfig or setup your own configuration to run the httpd. data Config Config :: !ByteString -> !ByteString -> !ServiceName -> !Maybe HostName -> !Maybe HostName -> !Maybe SSLConfig -> !Int -> !Int -> !Int -> !Bool -> !ExtMap -> Config -- | A string which will be sent to clients as "Server" field. cnfServerSoftware :: Config -> !ByteString -- | The host name of the server. This value will be used in built-in pages -- like "404 Not Found". cnfServerHost :: Config -> !ByteString -- | A port number (or service name) to listen to HTTP clients. cnfServerPort :: Config -> !ServiceName -- | Local IPv4 address to listen to both HTTP and HTTPS clients. Set this -- to (Just 0.0.0.0) if you want to accept any -- IPv4 connections. Set this to Nothing to disable IPv4. cnfServerV4Addr :: Config -> !Maybe HostName -- | Local IPv6 address to listen to both HTTP and HTTPS clients. Set this -- to (Just ::) if you want to accept any IPv6 -- connections. Set this to Nothing to disable IPv6. Note that -- there is currently no way to assign separate ports to IPv4 and IPv6 -- server sockets. cnfServerV6Addr :: Config -> !Maybe HostName -- | Configuration for HTTPS connections. Set this Nothing to -- disable HTTPS. cnfSSLConfig :: Config -> !Maybe SSLConfig -- | The maximum number of requests to accept in one connection -- simultaneously. If a client exceeds this limitation, its last request -- won't be processed until a response for its earliest pending request -- is sent back to the client. cnfMaxPipelineDepth :: Config -> !Int -- | The maximum length of request entity to accept in bytes. Note that -- this is nothing but the default value which is used when -- Network.HTTP.Lucu.Resource.input and such like are applied to -- Network.HTTP.Lucu.Resource.defaultLimit, so there is no -- guarantee that this value always constrains all the requests. cnfMaxEntityLength :: Config -> !Int -- | The maximum length of chunk to output. This value is used by -- Network.HTTP.Lucu.Resource.output and such like to limit the -- chunk length so you can safely output an infinite string (like a lazy -- stream of /dev/random) using those actions. cnfMaxOutputChunkLength :: Config -> !Int -- | Whether to dump too late abortion to the stderr or not. See -- Network.HTTP.Lucu.Abortion.abort. cnfDumpTooLateAbortionToStderr :: Config -> !Bool -- | A mapping from extension to MIME Type. This value is used by -- Network.HTTP.Lucu.StaticFile.staticFile to guess the MIME -- Type of static files. Note that MIME Types are currently guessed only -- by file name. -- -- Guessing by file magic is indeed a wonderful idea but that is not -- implemented (yet). But, don't you think it's better a file system got -- a MIME Type as a part of inode? Or it might be a good idea to use -- GnomeVFS -- (http://developer.gnome.org/doc/API/2.0/gnome-vfs-2.0/) instead -- of vanilla FS. cnfExtToMIMEType :: Config -> !ExtMap -- | Configuration record for HTTPS connections. data SSLConfig SSLConfig :: !ServiceName -> !SSLContext -> SSLConfig -- | A port ID to listen to HTTPS clients. Local addresses (both for IPv4 -- and IPv6) will be derived from the parent Config. sslServerPort :: SSLConfig -> !ServiceName -- | An SSL context for accepting connections. sslContext :: SSLConfig -> !SSLContext -- | The default configuration. Generally you can use this value as-is, or -- possibly you just want to replace the cnfServerSoftware and -- cnfServerPort. SSL connections are disabled by default. defaultConfig :: Config -- | Aborting the computation of -- Network.HTTP.Lucu.Resource.Resource in any IO monads -- or arrows. module Network.HTTP.Lucu.Abortion -- | 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. --
  3. 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.
  4. --
-- -- 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 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. --
  3. If the URI of it matches to any resource, the corresponding -- Resource Monad starts running on a newly spawned thread.
  4. --
  5. 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.
  6. --
  7. The Resource Monad and its thread stops running. The client -- may or may not be sending us the next request at this point.
  8. --
-- -- Resource Monad takes the following states. The initial state is -- Examining Request and the final state is Done. -- -- -- -- Note that the state transition is one-way: for instance, it is an -- error to try to read a request body after writing some response. This -- limitation is for efficiency. We don't want to read the entire request -- before starting Resource, nor we don't want to postpone writing -- the entire response till the end of Resource computation. module Network.HTTP.Lucu.Resource -- | The Resource monad. This monad implements -- Control.Monad.Trans.MonadIO so it can do any IO -- actions. data Resource a -- | This data type represents a form entry name, form value and possibly -- an uploaded file name. data FormData FormData :: String -> Maybe String -> ByteString -> FormData fdName :: FormData -> String fdFileName :: FormData -> Maybe String fdContent :: FormData -> ByteString -- | Get the Config value which is used for the httpd. getConfig :: Resource Config -- | Get the SockAddr of the remote host. If you want a string -- representation instead of SockAddr, use getRemoteAddr'. getRemoteAddr :: Resource SockAddr -- | Get the string representation of the address of remote host. If you -- want a SockAddr instead of String, use -- getRemoteAddr. getRemoteAddr' :: Resource String -- | Resolve an address to the remote host. getRemoteHost :: Resource String -- | Return the X.509 certificate of the client, or Nothing if: -- -- getRemoteCertificate :: Resource (Maybe X509) -- | Get the Request value which represents the request header. In -- general you don't have to use this action. getRequest :: Resource Request -- | Get the Method value of the request. getMethod :: Resource Method -- | Get the URI of the request. getRequestURI :: Resource URI -- | Get the HTTP version of the request. getRequestVersion :: Resource HttpVersion -- | Get the path of this Resource (to be exact, -- Network.HTTP.Lucu.Resource.Tree.ResourceDef) in the -- Network.HTTP.Lucu.Resource.Tree.ResTree. The result of this -- action is the exact path in the tree even if the -- Network.HTTP.Lucu.Resource.Tree.ResourceDef is greedy. -- -- Example: -- --
--   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. The result is URI-unescaped. It -- 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 [FormData] -- | 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 [FormData] -- | 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 ()) -- | emptyResource is a resource definition with no actual handlers. -- You can construct a ResourceDef by selectively overriding -- emptyResource. It is defined as follows: -- --
--   emptyResource = ResourceDef {
--                     resUsesNativeThread = False
--                   , resIsGreedy         = False
--                   , resGet              = Nothing
--                   , resHead             = Nothing
--                   , resPost             = Nothing
--                   , resPut              = Nothing
--                   , resDelete           = Nothing
--                   }
--   
emptyResource :: ResourceDef -- | 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: -- -- -- -- 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 the following (otherwise essential) facilities: -- -- module Network.HTTP.Lucu -- | 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 () -- | 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 ()) -- | emptyResource is a resource definition with no actual handlers. -- You can construct a ResourceDef by selectively overriding -- emptyResource. It is defined as follows: -- --
--   emptyResource = ResourceDef {
--                     resUsesNativeThread = False
--                   , resIsGreedy         = False
--                   , resGet              = Nothing
--                   , resHead             = Nothing
--                   , resPost             = Nothing
--                   , resPut              = Nothing
--                   , resDelete           = Nothing
--                   }
--   
emptyResource :: ResourceDef -- | 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. --
  3. 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.
  4. --
-- -- 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