module Network.HTTP.Lucu.Preprocess
( preprocess
)
where
import Control.Concurrent.STM
import Control.Monad
import qualified Data.ByteString as Strict (ByteString)
import qualified Data.ByteString.Char8 as C8 hiding (ByteString)
import Data.Char
import Data.Maybe
import Network.HTTP.Lucu.Config
import Network.HTTP.Lucu.Headers
import Network.HTTP.Lucu.HttpVersion
import Network.HTTP.Lucu.Interaction
import Network.HTTP.Lucu.Request
import Network.HTTP.Lucu.Response
import Network.URI
preprocess :: Interaction -> STM ()
preprocess !itr
= do req <- readItr itr itrRequest fromJust
let reqVer = reqVersion req
if reqVer /= HttpVersion 1 0 &&
reqVer /= HttpVersion 1 1 then
do setStatus HttpVersionNotSupported
writeItr itr itrWillClose True
else
do when (reqVer == HttpVersion 1 0)
$ writeItr itr itrWillClose True
completeAuthority req
case reqMethod req of
GET -> return ()
HEAD -> writeItr itr itrWillDiscardBody True
POST -> writeItr itr itrRequestHasBody True
PUT -> writeItr itr itrRequestHasBody True
DELETE -> return ()
_ -> setStatus NotImplemented
preprocessHeader req
where
setStatus :: StatusCode -> STM ()
setStatus !status
= updateItr itr itrResponse
$! \ res -> res {
resStatus = status
}
completeAuthority :: Request -> STM ()
completeAuthority !req
= when (uriAuthority (reqURI req) == Nothing)
$ if reqVersion req == HttpVersion 1 0 then
do let conf = itrConfig itr
host = cnfServerHost conf
port = itrLocalPort itr
portStr
= case port of
80 -> ""
n -> ':' : show n
updateAuthority host (C8.pack portStr)
else
case getHeader (C8.pack "Host") req of
Just str -> let (host, portStr) = parseHost str
in updateAuthority host portStr
Nothing -> setStatus BadRequest
parseHost :: Strict.ByteString -> (Strict.ByteString, Strict.ByteString)
parseHost = C8.break (== ':')
updateAuthority :: Strict.ByteString -> Strict.ByteString -> STM ()
updateAuthority !host !portStr
= updateItr itr itrRequest
$! \ (Just req) -> Just req {
reqURI = let uri = reqURI req
in uri {
uriAuthority = Just URIAuth {
uriUserInfo = ""
, uriRegName = C8.unpack host
, uriPort = C8.unpack portStr
}
}
}
preprocessHeader :: Request -> STM ()
preprocessHeader !req
= do case getHeader (C8.pack "Expect") req of
Nothing -> return ()
Just value -> if value `noCaseEq` C8.pack "100-continue" then
writeItr itr itrExpectedContinue True
else
setStatus ExpectationFailed
case getHeader (C8.pack "Transfer-Encoding") req of
Nothing -> return ()
Just value -> unless (value `noCaseEq` C8.pack "identity")
$ if value `noCaseEq` C8.pack "chunked" then
writeItr itr itrRequestIsChunked True
else
setStatus NotImplemented
case getHeader (C8.pack "Content-Length") req of
Nothing -> return ()
Just value -> if C8.all isDigit value then
do let Just (len, _) = C8.readInt value
writeItr itr itrReqChunkLength $ Just len
writeItr itr itrReqChunkRemaining $ Just len
else
setStatus BadRequest
case getHeader (C8.pack "Connection") req of
Nothing -> return ()
Just value -> when (value `noCaseEq` C8.pack "close")
$ writeItr itr itrWillClose True