Lucu is an HTTP daemonic library. It can be embedded in any Haskell program and runs in an independent thread.
Features:
- Full support of HTTP\1.1/
- Lucu supports request pipelining, chunked I/O, ETag comparison and "100 Continue".
- Performance
- Lucu doesn't fork/exec to handle requests like CGI. It just spawns a new thread. Inter-process communication is done with STM.
- Affinity for RESTafarians
- Lucu is a carefully designed web server for RESTful applications.
- SSL connections
- Lucu can handle HTTP connections over SSL layer.
Lucu is not a replacement for Apache or lighttpd. It is intended to be used to create an efficient web-based RESTful 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:
- Logging
- Lucu doesn't log any requests from any clients.
- Client Filtering
- Lucu always accepts any clients. No IP filter is implemented.
- Bandwidth Limitting
- Lucu doesn't limit bandwidth it consumes.
- Protection Against Wicked Clients
- Lucu is fragile against wicked clients. No attacker should be able to cause a buffer-overflow but can possibly DoS it.
- runHttpd :: Config -> ResTree -> [FallbackHandler] -> IO ()
- module Network.HTTP.Lucu.Config
- data ResourceDef = ResourceDef {}
- emptyResource :: ResourceDef
- data ResTree
- mkResTree :: [([String], ResourceDef)] -> ResTree
- module Network.HTTP.Lucu.Resource
- data StatusCode
- = Continue
- | SwitchingProtocols
- | Processing
- | Ok
- | Created
- | Accepted
- | NonAuthoritativeInformation
- | NoContent
- | ResetContent
- | PartialContent
- | MultiStatus
- | MultipleChoices
- | MovedPermanently
- | Found
- | SeeOther
- | NotModified
- | UseProxy
- | TemporaryRedirect
- | BadRequest
- | Unauthorized
- | PaymentRequired
- | Forbidden
- | NotFound
- | MethodNotAllowed
- | NotAcceptable
- | ProxyAuthenticationRequired
- | RequestTimeout
- | Conflict
- | Gone
- | LengthRequired
- | PreconditionFailed
- | RequestEntityTooLarge
- | RequestURITooLarge
- | UnsupportedMediaType
- | RequestRangeNotSatisfiable
- | ExpectationFailed
- | UnprocessableEntitiy
- | Locked
- | FailedDependency
- | InternalServerError
- | NotImplemented
- | BadGateway
- | ServiceUnavailable
- | GatewayTimeout
- | HttpVersionNotSupported
- | InsufficientStorage
- abort :: MonadIO m => StatusCode -> [(String, String)] -> Maybe String -> m a
- abortPurely :: StatusCode -> [(String, String)] -> Maybe String -> a
- abortA :: ArrowIO a => a (StatusCode, ([(String, String)], Maybe String)) c
- data ETag = ETag {
- etagIsWeak :: !Bool
- etagToken :: !String
- strongETag :: String -> ETag
- weakETag :: String -> ETag
- data MIMEType = MIMEType {}
- data AuthChallenge = BasicAuthChallenge Realm
- data AuthCredential = BasicAuthCredential UserID Password
- module Network.HTTP.Lucu.StaticFile
Entry Point
runHttpd :: Config -> ResTree -> [FallbackHandler] -> IO ()Source
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
. This can hardly cause a problem but it may do.
installHandler
sigPIPE
Ignore
Nothing
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 }
Configuration
module Network.HTTP.Lucu.Config
Resource Tree
data ResourceDef Source
ResourceDef
is basically a set of
Resource
monads for each HTTP methods.
ResourceDef | |
|
emptyResource :: ResourceDefSource
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 }
ResTree
is an opaque structure which is a map from resource path
to ResourceDef
.
mkResTree :: [([String], ResourceDef)] -> ResTreeSource
Resource Monad
module Network.HTTP.Lucu.Resource
Things to be used in the Resource monad
Status Code
data StatusCode Source
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.
Abortion
abort :: MonadIO m => StatusCode -> [(String, String)] -> Maybe String -> m aSource
Computation of
aborts the
abort
status headers msgNetwork.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.
- If the
Network.HTTP.Lucu.Resource.Resource
is in the /Deciding Header/ or any precedent states, it is possible to use thestatus
and such like as a HTTP response to be sent to the client. - 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")
abortPurely :: StatusCode -> [(String, String)] -> Maybe String -> aSource
This is similar to abort
but computes it with
unsafePerformIO
.
ETag
An entity tag is made of a weakness flag and a opaque string.
ETag | |
|
strongETag :: String -> ETagSource
MIME Type
represents "major/minor; name=value".
MIMEType
"major" "minor" [("name", "value")]
Authorization
data AuthChallenge Source
Authorization challenge to be sent to client with
"WWW-Authenticate" header. See
Network.HTTP.Lucu.Resource.setWWWAuthenticate
.
data AuthCredential Source
Authorization credential to be sent by client with
"Authorization" header. See
Network.HTTP.Lucu.Resource.getAuthorization
.
Utility
Static file handling
module Network.HTTP.Lucu.StaticFile