X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FPreprocess.hs;h=17a23b2435e50527674f3d51f75fb214d3dbad6b;hb=7bb9f32;hp=1915b1bd44e3a93f95ffba41f922d3f2bea0bc94;hpb=246d66d6d3130e03834a6c3badc38711a1879aae;p=Lucu.git diff --git a/Network/HTTP/Lucu/Preprocess.hs b/Network/HTTP/Lucu/Preprocess.hs index 1915b1b..17a23b2 100644 --- a/Network/HTTP/Lucu/Preprocess.hs +++ b/Network/HTTP/Lucu/Preprocess.hs @@ -3,6 +3,7 @@ , OverloadedStrings , RecordWildCards , UnicodeSyntax + , ViewPatterns #-} module Network.HTTP.Lucu.Preprocess ( AugmentedRequest(..) @@ -11,6 +12,7 @@ module Network.HTTP.Lucu.Preprocess ) where import Control.Applicative +import Control.Applicative.Unicode import Control.Monad import Control.Monad.State.Strict import Data.Ascii (Ascii) @@ -26,7 +28,7 @@ import qualified Data.Text.Encoding as T import Network.HTTP.Lucu.Headers import Network.HTTP.Lucu.HttpVersion import Network.HTTP.Lucu.Request -import Network.HTTP.Lucu.Response +import Network.HTTP.Lucu.Response.StatusCode import Network.Socket import Network.URI import Prelude.Unicode @@ -46,8 +48,8 @@ data RequestBodyLength | Chunked deriving (Eq, Show) -preprocess ∷ CI Text → PortNumber → Request → AugmentedRequest -preprocess localHost localPort req@(Request {..}) +preprocess ∷ CI Text → PortNumber → Bool → Request → AugmentedRequest +preprocess localHost localPort isSSL req@(Request {..}) = execState go initialAR where initialAR ∷ AugmentedRequest @@ -62,6 +64,7 @@ preprocess localHost localPort req@(Request {..}) go ∷ State AugmentedRequest () go = do examineHttpVersion examineMethod + examineScheme isSSL examineAuthority localHost localPort examineHeaders examineBodyLength @@ -105,6 +108,20 @@ examineMethod DELETE → return () _ → setStatus NotImplemented +examineScheme ∷ Bool → State AugmentedRequest () +examineScheme isSSL + = do req ← gets arRequest + when (null ∘ uriScheme $ reqURI req) $ + let uri' = (reqURI req) { + uriScheme = if isSSL then + "https:" + else + "http:" + } + req' = req { reqURI = uri' } + in + setRequest req' + examineAuthority ∷ CI Text → PortNumber → State AugmentedRequest () examineAuthority localHost localPort = do req ← gets arRequest @@ -115,25 +132,39 @@ examineAuthority localHost localPort HttpVersion 1 0 → let host = localHost port = case localPort of - 80 → "" - n → A.unsafeFromString $ ':':show n + n | Just n ≡ defaultPort (reqURI req) + → "" + n → A.unsafeFromString $ ':':show n req' = updateAuthority host port req in setRequest req' - -- HTTP/1.1 requests MUST have a Host header. + -- HTTP/1.1 requests MUST have a Host header, but if + -- the requested URI has an authority, the value of + -- Host header must be ignored. See: + -- http://tools.ietf.org/html/rfc2616#section-5.2 HttpVersion 1 1 → case getHeader "Host" req of Just str - → let (host, port) - = parseHost str - req' = updateAuthority host port req - in - setRequest req' + | isNothing ∘ uriAuthority ∘ reqURI $ req + → let (host, port) + = parseHost str + req' = updateAuthority host port req + in + setRequest req' + | otherwise + → return () Nothing → setStatus BadRequest -- Should never reach here... ver → fail ("internal error: unknown version: " ⧺ show ver) +defaultPort ∷ Alternative f ⇒ URI → f PortNumber +{-# INLINEABLE defaultPort #-} +defaultPort (uriScheme → s) + | s ≡ "http:" = pure 80 + | s ≡ "https:" = pure 443 + | otherwise = (∅) + parseHost ∷ Ascii → (CI Text, Ascii) parseHost hp = let (h, p) = C8.break (≡ ':') $ cs hp @@ -144,9 +175,8 @@ parseHost hp (hText, pAscii) updateAuthority ∷ CI Text → Ascii → Request → Request -updateAuthority host port req - = let uri = reqURI req - uri' = uri { +updateAuthority host port req@(Request {..}) + = let uri' = reqURI { uriAuthority = Just URIAuth { uriUserInfo = "" , uriRegName = cs $ CI.original host @@ -196,7 +226,7 @@ examineBodyLength ∷ State AugmentedRequest () examineBodyLength = do req ← gets arRequest len ← gets arReqBodyLength - if reqMustHaveBody req then + if reqHasBody req then -- POST and PUT requests must have an entity body. when (isNothing len) $ setStatus LengthRequired