network-minihttp-0.2: A ByteString based library for writing HTTP(S) servers and clients.




This module contains functions for writing webservers. These servers process requests in a state monad pipeline and several useful actions are provided herein.

See examples/test.hs for an example of how to use this module.


The processing monad

type WebMonad = StateT WebState IOSource

The processing monad

data WebState Source

Processing a request involves running a number of actions in a StateT monad where the state for that monad is this record. This contains both a Source and a Handle element. Often something will fill in the Handle and expect later processing to convert it to a Source. Somehow, you have to end up with a Source, however.




wsRequest :: Request

the original request

wsBody :: Maybe Source

the client's payload

wsMimeTypes :: Map ByteString MediaType

the system mime types db, mapping file extensions

wsReply :: Reply

the current reply

wsSource :: Maybe Source

the current source

wsHandle :: Maybe Handle

the current handle

wsAction :: Maybe (IO ())

an action to be performed before sending the reply

getRequest :: WebMonad RequestSource

Return the request

getPayload :: WebMonad (Maybe Source)Source

Return the client's request payload (if any)



:: Int

max number of bytes to read

-> WebMonad (Map ByteString ByteString) 

Get the arguments to a POST request

getGET :: WebMonad (Map ByteString ByteString)Source

Get the arguments to a GET request

getReply :: WebMonad ReplySource

Return the current reply

setReply :: Int -> WebMonad ()Source

Set the current reply to be a reply with the given status code, the default message for that status code, an empty body and an empty set of headers.

setHeader :: (Headers -> Headers) -> WebMonad ()Source

Set a header in the current reply. Because of the way records work, you use this function like this:

 setHeader $ \h -> h { httpSomeHeader = Just value }

WebMonad actions

handleConditionalRequest :: WebMonad ()Source

This handles the If-*Matches and If-*Modified conditional headers. It takes its information from the Last-Modified and ETag headers of the current reply. Note that, for the purposes of ETag matching, a reply without an ETag header is considered not to exist from the point of view of, say, If-Matches: *.

handleHandleToSource :: WebMonad ()Source

If the current state includes a Handle, this turns it into a Source

handleRangeRequests :: WebMonad ()Source

This handles Range requests and also translates from Handles to Sources. If the WebMonad has a Handle at this point, then we can construct sources from any subrange of the file. (We also assume that Content-Length is correctly set.)

See RFC 2616, section 14.35

handleDecoration :: WebMonad ()Source

At the moment, this just adds the header Server: Network.MiniHTTP



:: FilePath

the root of the filesystem to serve from

-> WebMonad () 

This is a very simple handler which deals with requests by returning the requested file from the filesystem. It sets a Handle in the state and sets the Content-Type, Content-Length and Last-Modified headers

Running the server



:: Int

the port number to listen on

-> WebMonad ()

the processing action

-> IO () 

Start an IPv4 HTTP server



:: Int

the port number to listen on

-> FilePath

path to public key (certificate)

-> FilePath

path to private key

-> WebMonad ()

the processing action

-> IO () 

Start an IPv4 HTTPS server. Plese remember to have wrapped your main function in OpenSSL.withOpenSSL otherwise you'll probably crash the process.



:: [(DispatchMatch, WebMonad ())]

the list of URL prefixes (with /!) and their actions

-> WebMonad () 

This is an, optional, helper function which you might find useful. The serving fuctions both expect a WebMonad action which is called to process each request. In general you have to write that and dispatch based on the client's request.

This might save you some work: it tries each of the elements in the list in turn. As soon as one matches it runs the given action to process the request.