packages feed

salvia-0.1: src/Network/Salvia/Handler/Directory.hs

module Network.Salvia.Handler.Directory (
    hDirectory
  , hDirectoryResource
  ) where

import Control.Monad.State
import Data.List (sort)
import Data.Record.Label
import Misc.Misc (bool)
import Network.Protocol.Http
import Network.Protocol.Uri (path)
import Network.Salvia.Handler.File (hResource)
import Network.Salvia.Handler.Redirect
import Network.Salvia.Httpd
import System.Directory (doesDirectoryExist, getDirectoryContents)

{- |
Serve a simple HTML directory listing for the specified directory on the
filesystem.
-}

hDirectoryResource :: ResourceHandler ()
hDirectoryResource dirName = do
  (u, p) <- bothM (uri % request) (getM path)
  if (null p) || last p /= '/'
   then hRedirect (lmod path (++"/") u)
   else dirHandler dirName

{- |
Like `hDirectoryResource` but uses the path of the current request URI.
-}

hDirectory :: Handler ()
hDirectory = hResource hDirectoryResource

dirHandler:: ResourceHandler ()
dirHandler dirName = do
  p <- getM (path % uri % request)
  filenames <- lift $ getDirectoryContents dirName
  processed <- lift $ mapM (processFilename dirName) (sort filenames)
  let b = listing p processed
  enterM response $ do
    setM contentType ("text/html", Nothing)
    setM contentLength (Just $ length b)
    setM status OK
  sendStr b

-- Add trailing slash to a directory name.
processFilename :: FilePath -> FilePath -> IO FilePath
processFilename d f = bool (f ++ "/") f `liftM` doesDirectoryExist (d ++ f)

-- Turn a list of filenames into HTML directory listing.
listing :: FilePath -> [FilePath] -> String
listing dirName fileNames =
  concat [
    "<html><head><title>Index of "
  , dirName
  , "</title></head><body><h1>Index of "
  , dirName
  , "</h1><ul>"
  , fileNames >>= \f -> concat ["<li><a href='", f, "'>", f, "</a></li>"]
  , "</ul></body></html>"
  ]