packages feed

mohws-0.1: src/Module/File.hs

-- Copyright 2002, Simon Marlow.
-- Copyright 2006, Bjorn Bringert.
module Module.File (desc) where

import Config
import Headers
import Request
import Response
import ServerRequest
import ServerState
import Util

import Control.Monad
import System.Posix

desc :: ModuleDesc
desc = emptyModuleDesc {
                        moduleName = "file",
                        moduleLoad = return funs
                       }

funs :: Module
funs = emptyModule { 
                    moduleHandleRequest = fileHandler
                   }

fileHandler :: ServerState -> ServerRequest  -> IO (Maybe Response)
fileHandler st (ServerRequest { clientRequest = req, 
                                  serverFilename = filename }) = 
   do m_lstat <- statSymLink filename
      checkStat m_lstat
  where
    conf = serverConfig st
    checkStat (Just stat)
         | isRegularFile stat = 
             liftM Just $ case reqCmd req of
                            GetReq  -> serveFile st filename stat False
                            HeadReq -> serveFile st filename stat True
                            _       -> return (notImplementedResponse conf)
         | isSymbolicLink stat =
             if followSymLinks conf 
                then statFile filename >>= checkStat
                else do debug st $ "findProg: Not following symlink: " ++ show filename
                        return Nothing 
         | otherwise = do debug st $ "Strange file: " ++ show filename
                          return Nothing
    checkStat Nothing = do debug st $ "File not found: " ++ show filename
                           return Nothing

serveFile :: ServerState -> FilePath -> FileStatus -> Bool -> IO Response
serveFile st filename stat is_head =
   do -- check we can actually read this file
     access <- fileAccess filename True{-read-} False False
     case access of
       False -> return (notFoundResponse conf);
                   -- not "permission denied", we're being paranoid
                   -- about security.
       True -> 
         do let content_type = getMimeType st filename

            let last_modified = epochTimeToClockTime (modificationTime stat)

            let size = toInteger (fileSize stat)

            return (okResponse conf
                    (FileBody size filename)
                    (mkHeaders [contentTypeHeader content_type, 
                                lastModifiedHeader last_modified])
                    (not is_head) {- send body -})
  where conf = serverConfig st