module Network.MoHWS.Part.Listing (Configuration, desc, ) where
import qualified Network.MoHWS.Module as Module
import qualified Network.MoHWS.Module.Description as ModuleDesc
import qualified Network.MoHWS.Server.Request as ServerRequest
import qualified Network.MoHWS.Server.Context as ServerContext
import qualified Network.MoHWS.HTTP.Header as Header
import qualified Network.MoHWS.HTTP.Request as Request
import qualified Network.MoHWS.HTTP.Response as Response
import qualified Network.MoHWS.Stream as Stream
import qualified Network.MoHWS.Configuration as Config
import qualified Network.MoHWS.Configuration.Accessor as ConfigA
import qualified Network.MoHWS.Configuration.Parser as ConfigParser
import qualified Data.Accessor.Basic as Accessor
import Data.Accessor.Basic ((.>))
import qualified Text.Html as Html
import Text.Html((<<), (+++))
import qualified Network.URI as URI
import Control.Monad.IO.Class (liftIO, )
import Control.Monad (guard, )
import Data.List (sort, )
import Control.Monad.Trans.Maybe (MaybeT, )
import Network.MoHWS.Utility (hasTrailingSlash, statFile, )
import qualified System.Directory as Dir
import System.Posix (isDirectory, )
desc :: (Stream.C body) => ModuleDesc.T body Configuration
desc =
ModuleDesc.empty {
ModuleDesc.name = "directorylisting",
ModuleDesc.load = return . funs,
ModuleDesc.configParser = parser,
ModuleDesc.setDefltConfig = const defltConfig
}
data Configuration =
Configuration {
listing_ :: Bool
}
defltConfig :: Configuration
defltConfig =
Configuration {
listing_ = True
}
listing :: Accessor.T Configuration Bool
listing =
Accessor.fromSetGet (\x c -> c{listing_ = x}) listing_
parser :: ConfigParser.T st Configuration
parser =
ConfigParser.field "directorylisting" p_listing
p_listing :: ConfigParser.T st Configuration
p_listing =
ConfigParser.set (ConfigA.extension .> listing) $ ConfigParser.bool
funs :: (Stream.C body) => ServerContext.T Configuration -> Module.T body
funs st =
Module.empty {
Module.handleRequest = handleRequest st
}
handleRequest :: (Stream.C body) =>
ServerContext.T Configuration -> ServerRequest.T body -> MaybeT IO (Response.T body)
handleRequest st req =
let conf = ServerContext.config st
dir = ServerRequest.serverFilename req
uri = Request.uri $ ServerRequest.clientRequest req
in do
guard $ listing_ $ Config.extension conf
guard =<< (fmap isDirectory $ statFile $ dir)
guard $ hasTrailingSlash $ URI.uriPath uri
files <- liftIO $ Dir.getDirectoryContents dir
return $ htmlResponse conf uri $ htmlList $
sort $ filter (not . flip elem [".", ".."]) $ files
htmlList :: [String] -> Html.Html
htmlList =
Html.unordList .
map (\s -> (Html.anchor << s) Html.! [Html.href s])
htmlResponse :: (Stream.C body) =>
Config.T ext -> URI.URI -> Html.Html -> Response.T body
htmlResponse conf addr body =
Response.makeOk
conf
True
(Header.group [Header.makeContentType "text/html"])
(Response.bodyWithSizeFromString $
Stream.fromString (Config.chunkSize conf) $
Html.renderHtml $
htmlDoc ("Directory listing of " ++ show addr) body)
htmlDoc :: String -> Html.Html -> Html.Html
htmlDoc title body =
Html.header
(Html.meta Html.! [Html.httpequiv "content-type",
Html.content "text/html; charset=ISO-8859-1"]
+++
Html.thetitle << title)
+++
Html.body body