Lucu-0.3: HTTP Daemonic LibrarySource codeContentsIndex
Network.HTTP.Lucu
Contents
Entry Point
Configuration
Resource Tree
Resource Monad
Things to be used in the Resource monad
Status Code
Abortion
ETag
MIME Type
Authorization
Utility
Static file handling
Description

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

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.
Synopsis
runHttpd :: Config -> ResTree -> [FallbackHandler] -> IO ()
module Network.HTTP.Lucu.Config
data ResourceDef = ResourceDef {
resUsesNativeThread :: !Bool
resIsGreedy :: !Bool
resGet :: !(Maybe (Resource ()))
resHead :: !(Maybe (Resource ()))
resPost :: !(Maybe (Resource ()))
resPut :: !(Maybe (Resource ()))
resDelete :: !(Maybe (Resource ()))
}
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 {
mtMajor :: !String
mtMinor :: !String
mtParams :: ![(String, String)]
}
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 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
              }
Configuration
module Network.HTTP.Lucu.Config
Resource Tree
data ResourceDef Source
ResourceDef is basically a set of Resource monads for each HTTP methods.
Constructors
ResourceDef
resUsesNativeThread :: !BoolWhether 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.
resIsGreedy :: !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.

resGet :: !(Maybe (Resource ()))

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.

resHead :: !(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.
resPost :: !(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.
resPut :: !(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.
resDelete :: !(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.
data ResTree Source
ResTree is an opaque structure which is a map from resource path to ResourceDef.
mkResTree :: [([String], ResourceDef)] -> ResTreeSource

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
             ]
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.
Constructors
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
show/hide Instances
Abortion
abort :: MonadIO m => StatusCode -> [(String, String)] -> Maybe String -> m aSource

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")
abortPurely :: StatusCode -> [(String, String)] -> Maybe String -> aSource
This is similar to abort but computes it with unsafePerformIO.
abortA :: ArrowIO a => a (StatusCode, ([(String, String)], Maybe String)) cSource
Computation of abortA -< (status, (headers, msg)) just computes abort in an ArrowIO.
ETag
data ETag Source
An entity tag is made of a weakness flag and a opaque string.
Constructors
ETag
etagIsWeak :: !BoolThe weakness flag. Weak tags looks like W/"blahblah" and strong tags are like "blahblah".
etagToken :: !StringAn opaque string. Only characters from 0x20 (sp) to 0x7e (~) are allowed.
show/hide Instances
strongETag :: String -> ETagSource
This is equivalent to ETag False. If you want to generate an ETag from a file, try using Network.HTTP.Lucu.StaticFile.generateETagFromFile.
weakETag :: String -> ETagSource
This is equivalent to ETag True.
MIME Type
data MIMEType Source
MIMEType "major" "minor" [("name", "value")] represents "major/minor; name=value".
Constructors
MIMEType
mtMajor :: !String
mtMinor :: !String
mtParams :: ![(String, String)]
show/hide Instances
Authorization
data AuthChallenge Source
Authorization challenge to be sent to client with "WWW-Authenticate" header. See Network.HTTP.Lucu.Resource.setWWWAuthenticate.
Constructors
BasicAuthChallenge Realm
show/hide Instances
data AuthCredential Source
Authorization credential to be sent by client with "Authorization" header. See Network.HTTP.Lucu.Resource.getAuthorization.
Constructors
BasicAuthCredential UserID Password
show/hide Instances
Utility
Static file handling
module Network.HTTP.Lucu.StaticFile
Produced by Haddock version 2.4.2