{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS -Wall #-} module Network.Web.Server.Params where import Control.Applicative ((<$>)) import qualified Data.ByteString.Char8 as S import qualified Data.ByteString.Lazy.Char8 as L import Data.Time import Data.Time.Clock.POSIX import Network.TCPInfo import Network.Web.HTTP import System.Posix.Files {-| The configuration for the basic web server. -} data BasicConfig = BasicConfig { -- | A mapper from 'URI' to 'Path'. mapper :: Request -> Path -- | Resource obtaining function. The second argument is -- (offset of the resource, and length from the offset). , obtain :: FilePath -> Maybe (Integer,Integer) -> IO L.ByteString -- | A function to return the size of the resource and -- its modification time if exists. , info :: FilePath -> IO (Maybe (Integer, UTCTime)) -- | A server name specified the Server: field. , serverName :: S.ByteString -- | 'TCPInfo' for passing CGI. (See c10k library.) , tcpInfo :: TCPInfo } {-| Default 'BasicConfig', with 'obtain', 'info', and 'serverName' filled in. It is necessary to override the 'mapper' and 'tcpInfo' fields -} defaultConfig :: BasicConfig defaultConfig = BasicConfig { mapper = error "BasicConfig: no mapper defined" , obtain = defaultObtain , info = defaultInfo , serverName = "BasicConfig: no server name" , tcpInfo = error "BasicConfig: no TCPInfo" } {-| Control information of how to handle 'URI'. -} data Path = -- | 'URI' cannot be converted into any resources. None -- | 'URI' is converted into a resource (typically a file). | File FilePath -- | 'URI' is converted into CGI. | PathCGI CGI -- | 'URI' is converted into a handler callback | Handler (IO Response) instance Eq Path where (File fp1) == (File fp2) = fp1 == fp2 (PathCGI cgi1) == (PathCGI cgi2) = cgi1 == cgi2 None == None = True _ == _ = False instance Show Path where show None = "None" show (File fp) = "File " ++ show fp show (PathCGI cgi) = "PathCGI (" ++ show cgi ++ ")" show (Handler _) = "Handler" {-| Internal information of CGI converted from 'URI'. -} data CGI = CGI { -- | A program path to be executed. progPath :: FilePath -- | A script name. , scriptName :: String -- | A path information. , pathInfo :: String -- | A query string. , queryString :: String } deriving (Eq,Show) -- | Get the size and modification time of a file, if possible. defaultInfo :: FilePath -> IO (Maybe (Integer, UTCTime)) defaultInfo fp = do exists <- fileExist fp if exists then do status <- getFileStatus fp let size = fromIntegral $ fileSize status mt = posixSecondsToUTCTime . realToFrac $ modificationTime status return $ Just (size,mt) else return Nothing -- | Obtain a data slice from a file as a lazy bytestring. defaultObtain :: FilePath -> Maybe (Integer,Integer) -> IO L.ByteString defaultObtain fp Nothing = L.readFile fp defaultObtain fp (Just (offset,numBytes)) = L.take nb . L.drop ofs <$> L.readFile fp where nb = fromIntegral numBytes ofs = fromIntegral offset