[added section on advanced file serving. Added some next links. moved fileserving before happstack-state Jeremy Shaw **20101115001700 Ignore-this: 66bf67f6867b7c4712093687f0230034 ] hunk ./FileServing.lhs 17 +

The contents of this section are based on the development version of Happstack which includes new functionality and a slightly different API.

hunk ./FileServing.lhs 28 - +#include "FileServingSingle.lhs" +#include "FileServingAdvanced.lhs" hunk ./FileServing.lhs 31 +

Next: Happstack State

addfile ./FileServingAdvanced.lhs hunk ./FileServingAdvanced.lhs 1 + + +

Advanced File Serving

+ +

serveDirectory and serveFile should cover a majority of your file serving needs. But if you want something a little different, it is also possible to roll-your-own solution. The Happstack.Server.FileServe.BuildingBlocks module contains all the pieces used to assemble the high-level serveDirectory and serveFile functions. You can reuse those pieces to build your own custom serving functions. For example, you might want to use a different method for calculating the mime-types, or perhaps you want to create a different look-and-feel for directory browsing, or maybe you want to use something other than sendFile for sending the files. I recommend starting by copying the source for serveDirectory or serveFile and then modifying it to suit your needs.

addfile ./FileServingSingle.lhs hunk ./FileServingSingle.lhs 1 + + +

Serving a Single File

+ +

Sometimes we want to serve files from disk whose name is not a direct mapping from the URL. For example, let's say that you have an image and you want to allow the client to request the images in different sizes by setting a query parameter. e.g. + +

+http://localhost:8000/images/photo.jpg?size=medium +
+ +

Clearly, we can not just map the path info portion of the URL to a file disk, because all the different sizes have the same name -- only the query parameter is different. Instead, the application will use some custom algorithm to calculate where the image lives on the disk. It may even need to generate the resized image on-demand. Once the application knows where the file lives on disk it can use serveFile to send that file as a Response using sendFile:

+ +
+#ifdef HsColour +> serveFile :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => +> (FilePath -> m String) -- ^ function for determining content-type of file. +> -- Typically 'asContentType' or 'guessContentTypeM' +> -> FilePath -- ^ path to the file to serve +> -> m Response +#endif +
+ +

The first argument is a function which calculates the mime-type for a FilePath. The second argument is path to the file to send. So we might do something like:

+ +
+#ifdef HsColour +> serveFile guessContentTypeM "/path/to/photos/photo_medium.jpg" +#endif +
+ +

Note that even though the file is named photo_medium.jpg on the disk, that name is not exposed to the client. They will only see the name they requested, i.e., photo.jpg.

+ +

guessContentTypeM will guess the content-type of the file by looking at the filename extension. But, if our photo app only supports JPEG files, there is no need to guess. Furthermore, the name of the file on the disk may not even have the proper extension. It could just be the md5sum of the file or something. So we can also hardcode the correct content-type: + +

+#ifdef HsColour +> serveFile (asContentType "image/jpeg") "/path/to/photos/photo_medium.jpg" +#endif +
+ +

The following, example attempts to serve its own source code for any incoming request.

+ +
+ +> module Main where +> +> import Happstack.Server (asContentType, nullConf, serveFile, simpleHTTP) +> +> main :: IO () +> main = simpleHTTP nullConf $ serveFile (asContentType "text/x-haskell") "FileServingSingle.hs" + +
+

[Source code for the app is here.]

+ hunk ./HelloWorld.lhs 19 -

Your first app!

+

Your first app!

hunk ./Makefile 5 -DEPS := HelloWorld.lhs RouteFilters.lhs Templates.lhs RqData.lhs HappstackState.lhs FileServing.lhs +DEPS := HelloWorld.lhs RouteFilters.lhs Templates.lhs RqData.lhs FileServing.lhs HappstackState.lhs hunk ./Makefile 12 -FILESERVING_DEMOS := FileServingDirectory.lhs +FILESERVING_DEMOS := FileServingDirectory.lhs FileServingSingle.lhs hunk ./Makefile 27 -FileServing.html : FileServing.lhs $(FILESERVING_DEMOS) +FileServing.html : FileServing.lhs $(FILESERVING_DEMOS) FileServingAdvanced.lhs hunk ./RqData.lhs 31 +

Next: Serving Files from Disk

hunk ./RqData.lhs 33 -