Safe Haskell | None |
---|---|
Language | Haskell2010 |
Build your own file serving functions
If the functions in Happstack.Server.FileServe do not quite do you want you can roll your own by reusing pieces from this module.
You will likely want to start by copying the source for a function
like, serveDirectory
and then modifying it to suit your needs.
Synopsis
- fileServe :: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [FilePath] -> FilePath -> m Response
- fileServe' :: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => (String -> FilePath -> m Response) -> (FilePath -> m String) -> (FilePath -> m Response) -> FilePath -> m Response
- fileServeLazy :: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [FilePath] -> FilePath -> m Response
- fileServeStrict :: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [FilePath] -> FilePath -> m Response
- data Browsing
- serveDirectory :: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => Browsing -> [FilePath] -> FilePath -> m Response
- serveDirectory' :: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => Browsing -> [FilePath] -> (FilePath -> m String) -> FilePath -> m Response
- serveFile :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => (FilePath -> m String) -> FilePath -> m Response
- serveFileFrom :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => FilePath -> (FilePath -> m String) -> FilePath -> m Response
- serveFileUsing :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => (String -> FilePath -> m Response) -> (FilePath -> m String) -> FilePath -> m Response
- sendFileResponse :: String -> FilePath -> Maybe (UTCTime, Request) -> Integer -> Integer -> Response
- lazyByteStringResponse :: String -> ByteString -> Maybe (UTCTime, Request) -> Integer -> Integer -> Response
- strictByteStringResponse :: String -> ByteString -> Maybe (UTCTime, Request) -> Integer -> Integer -> Response
- filePathSendFile :: (ServerMonad m, MonadIO m) => String -> FilePath -> m Response
- filePathLazy :: (ServerMonad m, MonadIO m) => String -> FilePath -> m Response
- filePathStrict :: (ServerMonad m, MonadIO m) => String -> FilePath -> m Response
- type MimeMap = Map String String
- mimeTypes :: MimeMap
- asContentType :: Monad m => String -> FilePath -> m String
- guessContentType :: MimeMap -> FilePath -> Maybe String
- guessContentTypeM :: Monad m => MimeMap -> FilePath -> m String
- data EntryKind
- = File
- | Directory
- | UnknownKind
- browseIndex :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m, ToMessage b) => (FilePath -> [FilePath] -> m b) -> (String -> FilePath -> m Response) -> (FilePath -> m String) -> [String] -> FilePath -> m Response
- renderDirectoryContents :: MonadIO m => FilePath -> [FilePath] -> m Html
- renderDirectoryContentsTable :: [(FilePath, Maybe UTCTime, Maybe Integer, EntryKind)] -> Html
- blockDotFiles :: (Request -> IO Response) -> Request -> IO Response
- defaultIxFiles :: [FilePath]
- combineSafe :: FilePath -> FilePath -> Maybe FilePath
- isSafePath :: [FilePath] -> Bool
- tryIndex :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => (String -> FilePath -> m Response) -> (FilePath -> m String) -> [String] -> FilePath -> m Response
- doIndex :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [FilePath] -> MimeMap -> FilePath -> m Response
- doIndex' :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => (String -> FilePath -> m Response) -> (FilePath -> m String) -> [String] -> FilePath -> m Response
- doIndexLazy :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [String] -> MimeMap -> FilePath -> m Response
- doIndexStrict :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [String] -> MimeMap -> FilePath -> m Response
- fileNotFound :: (Monad m, FilterMonad Response m) => FilePath -> m Response
- isDot :: String -> Bool
High-Level
Serving files from a directory
:: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> [FilePath] | index file names, in case the requested path is a directory |
-> FilePath | file/directory to serve |
-> m Response |
Deprecated: use serveDirectory instead.
Serve files from a directory and its subdirectories using sendFile
.
Usage:
fileServe ["index.html"] "path/to/files/on/disk"
fileServe
does not support directory browsing. See serveDirectory
DEPRECATED: use serveDirectory
instead.
Note:
The list of index files ["index.html"]
is only used to determine what file to show if the user requests a directory. You *do not* need to explicitly list all the files you want to serve.
:: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> (String -> FilePath -> m Response) | function which takes a content-type and filepath and generates a response (typically |
-> (FilePath -> m String) | function which returns the mime-type for FilePath -> [FilePath] -- ^ index file names, in case the requested path is a directory |
-> (FilePath -> m Response) | |
-> FilePath | file/directory to serve |
-> m Response |
Serve files from a directory and its subdirectories (parameterizable version)
Parameterize this function to create functions like, fileServe
, fileServeLazy
, and fileServeStrict
You supply:
- a low-level function which takes a content-type and
FilePath
and generates a Response - a function which determines the content-type from the
FilePath
- a list of all the default index files
NOTE: unlike fileServe, there are no index files by default. See defaultIxFiles
.
:: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> [FilePath] | index file names, in case the requested path is a directory |
-> FilePath | file/directory to serve |
-> m Response |
Serve files from a directory and its subdirectories (lazy ByteString version).
WARNING: May leak file handles. You should probably use fileServe
instead.
:: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> [FilePath] | index file names, in case the next argument is a directory |
-> FilePath | file/directory to serve |
-> m Response |
Serve files from a directory and its subdirectories (strict ByteString version).
WARNING: the entire file will be read into RAM before being served. You should probably use fileServe
instead.
see serveDirectory
Instances
Enum Browsing Source # | |
Defined in Happstack.Server.FileServe.BuildingBlocks | |
Eq Browsing Source # | |
Data Browsing Source # | |
Defined in Happstack.Server.FileServe.BuildingBlocks gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Browsing -> c Browsing # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Browsing # toConstr :: Browsing -> Constr # dataTypeOf :: Browsing -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Browsing) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Browsing) # gmapT :: (forall b. Data b => b -> b) -> Browsing -> Browsing # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Browsing -> r # gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Browsing -> r # gmapQ :: (forall d. Data d => d -> u) -> Browsing -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Browsing -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Browsing -> m Browsing # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Browsing -> m Browsing # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Browsing -> m Browsing # | |
Ord Browsing Source # | |
Defined in Happstack.Server.FileServe.BuildingBlocks | |
Read Browsing Source # | |
Show Browsing Source # | |
:: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> Browsing | allow directory browsing |
-> [FilePath] | index file names, in case the requested path is a directory |
-> FilePath | file/directory to serve |
-> m Response |
Serve files and directories from a directory and its subdirectories using sendFile
.
Usage:
serveDirectory EnableBrowsing ["index.html"] "path/to/files/on/disk"
If the requested path does not match a file or directory on the
disk, then serveDirectory
calls mzero
.
If the requested path is a file then the file is served normally.
If the requested path is a directory, then the result depends on what the first two arguments to the function are.
The first argument controls whether directory browsing is enabled.
The second argument is a list of index files (such as index.html).
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
is set,
otherwise it will return forbidden "Directory index forbidden"
.
Here is an explicit list of all the possible outcomes when the argument is a (valid) directory:
DisableBrowsing
, empty index file list
This will always return, forbidden "Directory index forbidden"
DisableBrowsing
, non-empty index file list
- If an index file is found it will be shown.
- Otherwise returns, forbidden "Directory index forbidden"
EnableBrowsing
, empty index file list
Always shows a directory index.
EnableBrowsing
, non-empty index file list
- If an index file is found it will be shown
- Otherwise shows a directory index
see also: defaultIxFiles
, serveFile
:: (WebMonad Response m, ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> Browsing | allow directory browsing |
-> [FilePath] | index file names, in case the requested path is a directory |
-> (FilePath -> m String) | function which returns the mime-type for FilePath |
-> FilePath | file/directory to serve |
-> m Response |
like serveDirectory
but with custom mimeTypes
Serving a single file
:: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> (FilePath -> m String) | function for determining content-type of file. Typically |
-> FilePath | path to the file to serve |
-> m Response |
Serve a single, specified file. The name of the file being served is specified explicity. It is not derived automatically from the Request
url.
example 1:
Serve as a specific content-type:
serveFile (asContentType "image/jpeg") "/srv/data/image.jpg"
example 2:
Serve guessing the content-type from the extension:
serveFile (guessContentTypeM mimeTypes) "/srv/data/image.jpg"
If the specified path does not exist or is not a file, this function will return mzero
.
WARNING: No security checks are performed.
NOTE: alias for serveFileUsing
filePathSendFile
:: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> FilePath | directory wherein served files must be contained |
-> (FilePath -> m String) | function for determining content-type of file. Typically |
-> FilePath | path to the file to serve |
-> m Response |
Like serveFile
, but uses combineSafe
to prevent directory
traversal attacks when the path to the file is supplied by the user.
:: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> (String -> FilePath -> m Response) | typically |
-> (FilePath -> m String) | function for determining content-type of file. Typically |
-> FilePath | path to the file to serve |
-> m Response |
Serve a single, specified file. The name of the file being served is specified explicity. It is not derived automatically from the Request
url.
example 1:
Serve using sendfile() and the specified content-type
serveFileUsing filePathSendFile (asContentType "image/jpeg") "/srv/data/image.jpg"
example 2:
Serve using a lazy ByteString and the guess the content-type from the extension
serveFileUsing filePathLazy (guessContentTypeM mimeTypes) "/srv/data/image.jpg"
WARNING: No security checks are performed.
Low-Level
:: String | content-type string |
-> FilePath | file path for content to send |
-> Maybe (UTCTime, Request) | mod-time for the handle (MUST NOT be later than server's time of message origination), incoming request (used to check for if-modified-since header) |
-> Integer | offset into Handle |
-> Integer | number of bytes to send |
-> Response |
Use sendFile to send the contents of a Handle
lazyByteStringResponse Source #
:: String | content-type string (e.g. |
-> ByteString | lazy bytestring content to send |
-> Maybe (UTCTime, Request) | mod-time for the bytestring, incoming request (used to check for if-modified-since header) |
-> Integer | offset into the bytestring |
-> Integer | number of bytes to send (offset + count must be less than or equal to the length of the bytestring) |
-> Response |
Send the contents of a Lazy ByteString
strictByteStringResponse Source #
:: String | content-type string (e.g. |
-> ByteString | lazy bytestring content to send |
-> Maybe (UTCTime, Request) | mod-time for the bytestring, incoming request (used to check for if-modified-since header) |
-> Integer | offset into the bytestring |
-> Integer | number of bytes to send (offset + count must be less than or equal to the length of the bytestring) |
-> Response |
Send the contents of a Lazy ByteString
:: (ServerMonad m, MonadIO m) | |
=> String | content-type string |
-> FilePath | path to file on disk |
-> m Response |
Send the specified file with the specified mime-type using sendFile()
NOTE: assumes file exists and is readable by the server. See serveFileUsing
.
WARNING: No security checks are performed.
:: (ServerMonad m, MonadIO m) | |
=> String | content-type string |
-> FilePath | path to file on disk |
-> m Response |
Send the specified file with the specified mime-type using lazy ByteStrings
NOTE: assumes file exists and is readable by the server. See serveFileUsing
.
WARNING: No security checks are performed.
:: (ServerMonad m, MonadIO m) | |
=> String | content-type string |
-> FilePath | path to file on disk |
-> m Response |
Send the specified file with the specified mime-type using strict ByteStrings
NOTE: assumes file exists and is readable by the server. See serveFileUsing
.
WARNING: No security checks are performed.
Content-Type / Mime-Type
Ready collection of common mime types. Except for the first two entries, the mappings come from an Ubuntu 8.04 /etc/mime.types file.
returns a specific content type, completely ignoring the FilePath
argument.
Use this with serveFile
if you want to explicitly specify the
content-type.
see also: guessContentTypeM
, serveFile
guessContentType :: MimeMap -> FilePath -> Maybe String Source #
try to guess the content-type of a file based on its extension
see also: guessContentTypeM
guessContentTypeM :: Monad m => MimeMap -> FilePath -> m String Source #
try to guess the content-type of a file based on its extension
defaults to "application/octet-stream" if no match was found.
Useful as an argument to serveFile
see also: guessContentType
, serveFile
Directory Browsing
Instances
browseIndex :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m, ToMessage b) => (FilePath -> [FilePath] -> m b) -> (String -> FilePath -> m Response) -> (FilePath -> m String) -> [String] -> FilePath -> m Response Source #
renderDirectoryContents Source #
a function to generate an HTML page showing the contents of a directory on the disk
see also: browseIndex
, renderDirectoryContentsTable
renderDirectoryContentsTable Source #
:: [(FilePath, Maybe UTCTime, Maybe Integer, EntryKind)] | list of files+meta data, see |
-> Html |
a function to generate an HTML table showing the contents of a directory on the disk
This function generates most of the content of the
renderDirectoryContents
page. If you want to style the page
differently, or add google analytics code, etc, you can just create
a new page template to wrap around this HTML.
see also: getMetaData
, renderDirectoryContents
Other
blockDotFiles :: (Request -> IO Response) -> Request -> IO Response Source #
Prevents files of the form '.foo' or 'bar/.foo' from being served
defaultIxFiles :: [FilePath] Source #
a list of common index files. Specifically: index.html
, index.xml
, index.gif
Typically used as an argument to serveDiretory
.
combineSafe :: FilePath -> FilePath -> Maybe FilePath Source #
Combine two FilePath
s, ensuring that the resulting path leads to
a file within the first FilePath
.
>>>
combineSafe "/var/uploads/" "etc/passwd"
Just "/var/uploads/etc/passwd">>>
combineSafe "/var/uploads/" "/etc/passwd"
Nothing>>>
combineSafe "/var/uploads/" "../../etc/passwd"
Nothing>>>
combineSafe "/var/uploads/" "../uploads/home/../etc/passwd"
Just "/var/uploads/etc/passwd"
isSafePath :: [FilePath] -> Bool Source #
:: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> (String -> FilePath -> m Response) | usually |
-> (FilePath -> m String) | function to calculate mime type, usually |
-> [String] | list of index files. See also |
-> FilePath | directory to search in |
-> m Response |
try to find an index file, calls mzero on failure
:: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) | |
=> [FilePath] | list of possible index files (e.g., |
-> MimeMap | see also |
-> FilePath | directory on disk to search for index files |
-> m Response |
attempt to serve index files
doIndex' :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => (String -> FilePath -> m Response) -> (FilePath -> m String) -> [String] -> FilePath -> m Response Source #
doIndexLazy :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [String] -> MimeMap -> FilePath -> m Response Source #
doIndexStrict :: (ServerMonad m, FilterMonad Response m, MonadIO m, MonadPlus m) => [String] -> MimeMap -> FilePath -> m Response Source #
fileNotFound :: (Monad m, FilterMonad Response m) => FilePath -> m Response Source #
return a simple "File not found 404 page."