Snap.Util.FileServe

snap-core-1.0.5.1: Snap: A Haskell Web Framework (core interfaces and types)

Safe Haskell | None
Language | Haskell2010

Snap.Util.FileServe

Contents

- Helper functions
- Configuration for directory serving
- File servers

Description

Contains web handlers to serve files from a directory.

Example usage:

    {-# LANGUAGE OverloadedStrings #-}

    module Main where

    import Snap.Core           (Snap, route)
    import Snap.Http.Server    (quickHttpServe)
    import Snap.Util.FileServe

    site :: Snap ()
    site = route
      [ ("/files",   serveDirectory                            "static")
      , ("/simple",  serveDirectoryWith simpleDirectoryConfig  "static")
      , ("/default", serveDirectoryWith defaultDirectoryConfig "static")
      , ("/fancy",   serveDirectoryWith fancyDirectoryConfig   "static")
      , ("/paper",   serveFile                                 "static/paper.pdf")
      , ("/thesis",  serveFileAs        "application/pdf"      "static/thesis.pdf")
      ]

    main :: IO ()
    main = quickHttpServe site

Synopsis

- getSafePath :: MonadSnap m => m FilePath
- type MimeMap = HashMap FilePath ByteString
- type HandlerMap (m :: Type -> Type) = HashMap FilePath (FilePath -> m ())
- data DirectoryConfig (m :: Type -> Type) = DirectoryConfig {
  - indexFiles :: [FilePath]
  - indexGenerator :: FilePath -> m ()
  - dynamicHandlers :: HandlerMap m
  - mimeTypes :: MimeMap
  - preServeHook :: FilePath -> m ()
  }
- simpleDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m
- defaultDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m
- fancyDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m
- defaultIndexGenerator :: MonadSnap m => MimeMap -> ByteString -> FilePath -> m ()
- defaultMimeTypes :: MimeMap
- fileType :: MimeMap -> FilePath -> ByteString
- serveDirectory :: MonadSnap m => FilePath -> m ()
- serveDirectoryWith :: MonadSnap m => DirectoryConfig m -> FilePath -> m ()
- serveFile :: MonadSnap m => FilePath -> m ()
- serveFileAs :: MonadSnap m => ByteString -> FilePath -> m ()

# Helper functions

getSafePath :: MonadSnap m => m FilePath #

Gets a path from the `Request` using `rqPathInfo` and makes sure it is safe to use for opening files. A path is safe if it is a relative path and has no ".." elements to escape the intended directory structure.

Example:

    ghci> :set -XOverloadedStrings
    ghci> import qualified Data.Map as M
    ghci> import qualified Snap.Test as T
    ghci> import qualified Data.ByteString.Char8 as B8
    ghci> T.runHandler (T.get "/foo/bar" M.empty) (getSafePath >>= writeBS . B8.pack)
    HTTP/1.1 200 OK
    server: Snap/test
    date: Fri, 08 Aug 2014 16:13:20 GMT

    foo/bar
    ghci> T.runHandler (T.get "/foo/../bar" M.empty) (getSafePath >>= writeBS . B8.pack)
    HTTP/1.1 404 Not Found
    ...

# Configuration for directory serving

type MimeMap = HashMap FilePath ByteString #

A type alias for MIME type

type HandlerMap (m :: Type -> Type) = HashMap FilePath (FilePath -> m ()) #

A type alias for dynamic handlers

data DirectoryConfig (m :: Type -> Type) #

A collection of options for serving static files out of a directory.

Constructors

DirectoryConfig |
Fields indexFiles :: [FilePath] Files to look for when a directory is requested (e.g., index.html) indexGenerator :: FilePath -> m () Handler to generate a directory listing if there is no index. dynamicHandlers :: HandlerMap m Map of extensions to pass to dynamic file handlers. This could be used, for example, to implement CGI dispatch, pretty printing of source code, etc. mimeTypes :: MimeMap MIME type map to look up content types. preServeHook :: FilePath -> m () Handler that is called before a file is served. It will only be called when a file is actually found, not for generated index pages.

simpleDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m #

A very simple configuration for directory serving. This configuration uses built-in MIME types from `defaultMimeTypes`, and has no index files, index generator, dynamic file handlers, or `preServeHook`.

defaultDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m #

A reasonable default configuration for directory serving. This configuration uses built-in MIME types from `defaultMimeTypes`, serves common index files `index.html` and `index.htm`, but does not autogenerate directory indexes, nor have any dynamic file handlers. The `preServeHook` will not do anything.

fancyDirectoryConfig :: forall (m :: Type -> Type). MonadSnap m => DirectoryConfig m #

A more elaborate configuration for file serving. This configuration uses built-in MIME types from `defaultMimeTypes`, serves common index files `index.html` and `index.htm`, and autogenerates directory indexes with a Snap-like feel. It still has no dynamic file handlers, nor `preServeHook`, which should be added as needed.

Files recognized as indexes include `index.html`, `index.htm`, `default.html`, `default.htm`, `home.html`

Example of how the autogenerated directory index looks like:

defaultIndexGenerator #

Arguments

:: MonadSnap m |
=> MimeMap | MIME type mapping for reporting types
-> ByteString | Style info to insert in header
-> FilePath | Directory to generate index for
-> m () |

An automatic index generator, which is fairly small and does not rely on any external files (which may not be there depending on external request routing).

A `MimeMap` is passed in to display the types of files in the directory listing based on their extension. Preferably, this is the same as the map in the `DirectoryConfig`

The styles parameter allows you to apply styles to the directory listing. The listing itself consists of a table, containing a header row using th elements, and one row per file using td elements, so styles for those pieces may be attached to the appropriate tags.

defaultMimeTypes :: MimeMap #

The default set of mime type mappings we use when serving files. Its value:

    Map.fromList [
      ( ".asc"     , "text/plain"                                             ),
      ( ".asf"     , "video/x-ms-asf"                                         ),
      ( ".asx"     , "video/x-ms-asf"                                         ),
      ( ".au"      , "audio/basic"                                            ),
      ( ".avi"     , "video/x-msvideo"                                        ),
      ( ".bmp"     , "image/bmp"                                              ),
      ( ".bz2"     , "application/x-bzip"                                     ),
      ( ".c"       , "text/plain"                                             ),
      ( ".class"   , "application/octet-stream"                               ),
      ( ".conf"    , "text/plain"                                             ),
      ( ".cpp"     , "text/plain"                                             ),
      ( ".css"     , "text/css"                                               ),
      ( ".csv"     , "text/csv"                                               ),
      ( ".cxx"     , "text/plain"                                             ),
      ( ".doc"     , "application/msword"                                     ),
      ( ".docx"    , S.append "application/vnd.openxmlformats-officedocument"
                              ".wordprocessingml.document"                    ),
      ( ".dotx"    , S.append "application/vnd.openxmlformats-officedocument"
                              ".wordprocessingml.template"                    ),
      ( ".dtd"     , "application/xml-dtd"                                    ),
      ( ".dvi"     , "application/x-dvi"                                      ),
      ( ".exe"     , "application/octet-stream"                               ),
      ( ".flv"     , "video/x-flv"                                            ),
      ( ".gif"     , "image/gif"                                              ),
      ( ".gz"      , "application/x-gzip"                                     ),
      ( ".hs"      , "text/plain"                                             ),
      ( ".htm"     , "text/html"                                              ),
      ( ".html"    , "text/html"                                              ),
      ( ".ico"     , "image/x-icon"                                           ),
      ( ".jar"     , "application/x-java-archive"                             ),
      ( ".jpeg"    , "image/jpeg"                                             ),
      ( ".jpg"     , "image/jpeg"                                             ),
      ( ".js"      , "text/javascript"                                        ),
      ( ".json"    , "application/json"                                       ),
      ( ".log"     , "text/plain"                                             ),
      ( ".m3u"     , "audio/x-mpegurl"                                        ),
      ( ".m3u8"    , "application/x-mpegURL"                                  ),
      ( ".mka"     , "audio/x-matroska"                                       ),
      ( ".mk3d"    , "video/x-matroska"                                       ),
      ( ".mkv"     , "video/x-matroska"                                       ),
      ( ".mov"     , "video/quicktime"                                        ),
      ( ".mp3"     , "audio/mpeg"                                             ),
      ( ".mp4"     , "video/mp4"                                              ),
      ( ".mpeg"    , "video/mpeg"                                             ),
      ( ".mpg"     , "video/mpeg"                                             ),
      ( ".ogg"     , "application/ogg"                                        ),
      ( ".pac"     , "application/x-ns-proxy-autoconfig"                      ),
      ( ".pdf"     , "application/pdf"                                        ),
      ( ".png"     , "image/png"                                              ),
      ( ".potx"    , S.append "application/vnd.openxmlformats-officedocument"
                              ".presentationml.template"                      ),
      ( ".ppsx"    , S.append "application/vnd.openxmlformats-officedocument"
                              ".presentationml.slideshow"                     ),
      ( ".ppt"     , "application/vnd.ms-powerpoint"                          ),
      ( ".pptx"    , S.append "application/vnd.openxmlformats-officedocument"
                              ".presentationml.presentation"                  ),
      ( ".ps"      , "application/postscript"                                 ),
      ( ".qt"      , "video/quicktime"                                        ),
      ( ".rtf"     , "text/rtf"                                               ),
      ( ".sig"     , "application/pgp-signature"                              ),
      ( ".sldx"    , S.append "application/vnd.openxmlformats-officedocument"
                              ".presentationml.slide"                         ),
      ( ".spl"     , "application/futuresplash"                               ),
      ( ".svg"     , "image/svg+xml"                                          ),
      ( ".swf"     , "application/x-shockwave-flash"                          ),
      ( ".tar"     , "application/x-tar"                                      ),
      ( ".tar.bz2" , "application/x-bzip-compressed-tar"                      ),
      ( ".tar.gz"  , "application/x-tgz"                                      ),
      ( ".tbz"     , "application/x-bzip-compressed-tar"                      ),
      ( ".text"    , "text/plain"                                             ),
      ( ".tgz"     , "application/x-tgz"                                      ),
      ( ".tif"     , "image/tiff"                                             ),
      ( ".tiff"    , "image/tiff"                                             ),
      ( ".torrent" , "application/x-bittorrent"                               ),
      ( ".ts"      , "video/mp2t"                                             ),
      ( ".txt"     , "text/plain"                                             ),
      ( ".wav"     , "audio/x-wav"                                            ),
      ( ".wax"     , "audio/x-ms-wax"                                         ),
      ( ".webm"    , "video/webm"                                             ),
      ( ".wma"     , "audio/x-ms-wma"                                         ),
      ( ".wmv"     , "video/x-ms-wmv"                                         ),
      ( ".xbm"     , "image/x-xbitmap"                                        ),
      ( ".xlam"    , "application/vnd.ms-excel.addin.macroEnabled.12"         ),
      ( ".xls"     , "application/vnd.ms-excel"                               ),
      ( ".xlsb"    , "application/vnd.ms-excel.sheet.binary.macroEnabled.12"  ),
      ( ".xlsx"    , S.append "application/vnd.openxmlformats-officedocument."
                              "spreadsheetml.sheet"                           ),
      ( ".xltx"    , S.append "application/vnd.openxmlformats-officedocument."
                              "spreadsheetml.template"                        ),
      ( ".xml"     , "text/xml"                                               ),
      ( ".xpm"     , "image/x-xpixmap"                                        ),
      ( ".xwd"     , "image/x-xwindowdump"                                    ),
      ( ".zip"     , "application/zip"                                        ) ]

fileType :: MimeMap -> FilePath -> ByteString #

Determine a given file's MIME type from its filename and the provided MIME map.

# File servers

serveDirectory #

Arguments

:: MonadSnap m |
=> FilePath | Directory to serve from
-> m () |

Serves static files from a directory using the default configuration as given in `defaultDirectoryConfig`.

serveDirectoryWith #

Arguments

:: MonadSnap m |
=> DirectoryConfig m | Configuration options
-> FilePath | Directory to serve from
-> m () |

Serves static files from a directory. Configuration options are passed in a `DirectoryConfig` that captures various choices about desired behavior. The relative path given in `rqPathInfo` is searched for a requested file, and the file is served with the appropriate mime type if it is found. Absolute paths and "`..`" are prohibited to prevent files from being served from outside the sandbox.

serveFile #

Arguments

:: MonadSnap m |
=> FilePath | path to file
-> m () |

Serves a single file specified by a full or relative path. If the file does not exist, throws an exception (not that it does not pass to the next handler). The path restrictions on `serveDirectory` don't apply to this function since the path is not being supplied by the user.

serveFileAs #

Arguments

:: MonadSnap m |
=> ByteString | MIME type
-> FilePath | path to file
-> m () |

Same as `serveFile`, with control over the MIME mapping used.