[Started section on file serving Jeremy Shaw **20101114233629 Ignore-this: 9082e986e8d79f07d5104678693660e4 ] addfile ./FileServing.lhs hunk ./FileServing.lhs 1 + + + + Crash Course in Happstack + + + + + +

Back to Table of Contents

+

Serving Files from Disk

+ +

Happstack can be used to serve static files from disk, such as .html, .jpg, etc.

+ +

The file serving capabilities can be divided into two categories:

+
    +
  1. Serving files from a directory based on a direct mapping of a portion of the URI to file names on the disk
  2. +
  3. Serving an specific, individual file on disk, whose name may be different from the URI
  4. +
+ +#include "FileServingDirectory.lhs" + + + + + addfile ./FileServingDirectory.lhs hunk ./FileServingDirectory.lhs 1 + + +

Serving Files from a Directory

+ +

The most common way to serve files is by using serveDirectory:

+ +
+#ifdef HsColour +> data Browsing = EnableBrowsing | DisableBrowsing +> +> serveDirectory :: ( WebMonad Response m, ServerMonad m, FilterMonad Response m +> , MonadIO m, MonadPlus m ) => +> Browsing -- ^ enable/disable directory browsing +> -> [FilePath] -- ^ index file names, in case the requested path is a directory +> -> FilePath -- ^ file/directory to serve +> -> m Response +#endif +
+ +

For example:

+ +
+#ifdef HsColour +> serveDirectory EnableBrowsing ["index.html"] "path/to/directory/on/disk" +#endif +
+

If the requested path does not map to a file or directory, then serveDirectory returns mzero.

+ +

If the requested path is a file then the file is served normally using serveFile.

+ +

When a directory is requested, serveDirectory will first try to find one of the index files (in the order they are listed). If that fails, it will show a directory listing if EnableBrowsing, otherwise it will return forbidden "Directory index forbidden".

+ +

The formula for mapping the URL to a file on disk is simply:

+ +
+path/to/directory/on/disk </> unconsumed/portion/of/request/url +
+ +

Note that we are only mapping the unconsumed portion of the URL. For example, let says that we had the handler:

+ +
+#ifdef HsColour +> dir "static" $ serveDirectory EnableBrowsing ["index.html"] "/srv/mysite/datafiles" +#endif +
+ +

And the requested url is:

+ +
+http://localhost/static/foo/bar.html +
+ +

Because, dir "static" consumes the static component we are going to have:

+ +
+/srv/mysite/datafiles </> foo/bar.html => /srv/mysite/datafiles/foo/bar.html +
+ +

The following demo will allow you to browse the directory that the server is running in. (So be careful where you run it).

+ +
+ +> module Main where +> +> import Happstack.Server (Browsing(EnableBrowsing), nullConf, serveDirectory, simpleHTTP) +> +> main :: IO () +> main = simpleHTTP nullConf $ serveDirectory EnableBrowsing [] "." + +
+

[Source code for the app is here.]

+ +

Simply run it and point your browser at http://localhost:8000/.

hunk ./Makefile 5 -DEPS := HelloWorld.lhs RouteFilters.lhs Templates.lhs RqData.lhs HappstackState.lhs +DEPS := HelloWorld.lhs RouteFilters.lhs Templates.lhs RqData.lhs HappstackState.lhs FileServing.lhs hunk ./Makefile 11 -COOKIE_DEMOS := CookieCounter.lhs +COOKIE_DEMOS := CookieCounter.lhs +FILESERVING_DEMOS := FileServingDirectory.lhs hunk ./Makefile 16 -DEMOS := $(RQDATA_DEMOS) $(ROUTE_FILTER_DEMOS) $(HELLOWORLD_DEMOS) $(TEMPLATES_DEPS) $(TEMPLATES_DEMOS) $(COOKIE_DEMOS) $(MACID_DEMOS) +DEMOS := $(RQDATA_DEMOS) $(ROUTE_FILTER_DEMOS) $(HELLOWORLD_DEMOS) $(TEMPLATES_DEPS) $(TEMPLATES_DEMOS) $(COOKIE_DEMOS) $(FILESERVING_DEMOS) $(MACID_DEMOS) hunk ./Makefile 27 +FileServing.html : FileServing.lhs $(FILESERVING_DEMOS)