[Haskell-cafe] happstack file serving

Jeremy Shaw jeremy at n-heptane.com
Wed Nov 2 22:05:08 CET 2011

On Tue, Nov 1, 2011 at 9:48 AM, Gary Klindt <gary.klindt at googlemail.com> wrote:
> Hello all,
> I want to have a web application using one 'index.html' file with ajax
> requests and a happstack web server which response to server requests.
> For that purpose I need to use some javascript libraries in my directory
> tree. I tried:
> main = simpleHTTP nullConf $ msum [ serveFile (asContentType "text/html")
> "index.html"
>                                  , serveFile (asContentType
> "text/javascript") "javascript/js.js" ]

As you discovered, serveDirectory is what you probably want. But,
let's say you really want to use serveFile for some reason.

The problem with  your code is that each of those lines will response
to *any* incoming request. You really want the first line to only
respond to requests for /index.html and the second to only respond to
requests for "/javascript/js.js". So you would need to rewrite you
code like:

 simpleHTTP nullConf msum $
   [ dir "index.html" $ serveFile (asContentType "text/html;
charset=UTF-8") "index.html"
   , dir "javascript" $ dir "js.js" $ serveFile (asContentType
"text/javascript") "javascript/js.js"

That would allow you to request /index.html vs javascript/js.js. Now,
obviously it is annoying to have to specify the names of the files
twice. But that is because serveFile is not really intended to be used
that way.

serveFile is typically used when the name of the file in the request
is different from the name of the file on the disk. For example, let's
say we have an image gallery. When people upload images, they might
have very common names like DSC_0123.jpg. So, we might get file
collisions if we tried to use the original file name to store the
file. Instead, we might rename the file to same unique name that we
know won't have any collisions. But, we might have the url be
something like, /image/theuniqueid/DSC_0123.jpg. That way when someone
downloads the file, their original file name is still intact. That
means we need some way to serve a file from the disk where the name of
the file on the disk is not the same of the name of the file in the

For that scheme we would have something like:

dir "image" $
 path $ \uniqueid ->
  anyPath $
    do locationOnDisk <- lookupDiskLocation uniqueId
        serveFile guessContentTypeM locationOnDisk

where "lookDiskLocation" is some application specific function.

- jeremy

More information about the Haskell-Cafe mailing list