X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Lucu.git;a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FInteraction.hs;h=d36c4d1773d4ebcaad2cf2937d5ce0fcddf716b0;hp=f1e7ab371734304bf18b00f57a70c608e3f4c16a;hb=b5dc373;hpb=3eb69879d3b336c7c3e613c0ce4bfb3c67989ff3 diff --git a/Network/HTTP/Lucu/Interaction.hs b/Network/HTTP/Lucu/Interaction.hs index f1e7ab3..d36c4d1 100644 --- a/Network/HTTP/Lucu/Interaction.hs +++ b/Network/HTTP/Lucu/Interaction.hs @@ -1,5 +1,6 @@ {-# LANGUAGE - DeriveDataTypeable + CPP + , DeriveDataTypeable , ExistentialQuantification , OverloadedStrings , RecordWildCards @@ -8,6 +9,7 @@ module Network.HTTP.Lucu.Interaction ( Interaction(..) , SomeInteraction(..) + , EndOfInteraction(..) , SyntacticallyInvalidInteraction(..) , mkSyntacticallyInvalidInteraction @@ -23,7 +25,6 @@ module Network.HTTP.Lucu.Interaction , InteractionQueue , mkInteractionQueue - , setResponseStatus , getCurrentDate ) where @@ -31,11 +32,13 @@ import Blaze.ByteString.Builder (Builder) import Control.Applicative import Control.Concurrent.STM import Data.Ascii (Ascii) -import qualified Data.ByteString as Strict +import Data.ByteString (ByteString) +import Data.Convertible.Base import Data.Monoid.Unicode +import Data.Proxy import Data.Sequence (Seq) import Data.Time -import qualified Data.Time.HTTP as HTTP +import Data.Time.Format.HTTP import Data.Typeable import Network.Socket import Network.HTTP.Lucu.Config @@ -44,7 +47,11 @@ import Network.HTTP.Lucu.Headers import Network.HTTP.Lucu.Preprocess import Network.HTTP.Lucu.Request import Network.HTTP.Lucu.Response +import Network.HTTP.Lucu.Utils +#if defined(HAVE_SSL) import OpenSSL.X509 +#endif +import Prelude.Unicode class Typeable i ⇒ Interaction i where toInteraction ∷ i → SomeInteraction @@ -61,6 +68,13 @@ instance Interaction SomeInteraction where toInteraction = id fromInteraction = Just +-- |'EndOfInteraction' is an 'Interaction' indicating the end of +-- (possibly pipelined) requests. The connection has already been +-- closed so no need to reply anything. +data EndOfInteraction = EndOfInteraction + deriving Typeable +instance Interaction EndOfInteraction + -- |'SyntacticallyInvalidInteraction' is an 'Interaction' without even -- a syntactically valid 'Request'. The response code will always be -- 'BadRequest'. @@ -74,13 +88,13 @@ instance Interaction SyntacticallyInvalidInteraction mkSyntacticallyInvalidInteraction ∷ Config → IO SyntacticallyInvalidInteraction -mkSyntacticallyInvalidInteraction config@(Config {..}) +mkSyntacticallyInvalidInteraction conf@(Config {..}) = do date ← getCurrentDate let res = setHeader "Server" cnfServerSoftware $ setHeader "Date" date $ setHeader "Content-Type" defaultPageContentType $ emptyResponse BadRequest - body = getDefaultPage config Nothing res + body = defaultPageForResponse conf Nothing res return SYI { syiResponse = res , syiBodyToSend = body @@ -112,8 +126,16 @@ mkSemanticallyInvalidInteraction config@(Config {..}) (AugmentedRequest {..}) let res = setHeader "Server" cnfServerSoftware $ setHeader "Date" date $ setHeader "Content-Type" defaultPageContentType $ + ( if arWillChunkBody + then setHeader "Transfer-Encoding" "chunked" + else id + ) $ + ( if arWillClose + then setHeader "Connection" "close" + else id + ) $ emptyResponse arInitialStatus - body = getDefaultPage config (Just arRequest) res + body = defaultPageForResponse config (Just arRequest) res return SEI { seiRequest = arRequest , seiExpectedContinue = arExpectedContinue @@ -132,14 +154,16 @@ data NormalInteraction = NI { niConfig ∷ !Config , niRemoteAddr ∷ !SockAddr +#if defined(HAVE_SSL) , niRemoteCert ∷ !(Maybe X509) +#endif , niRequest ∷ !Request - , niResourcePath ∷ ![Strict.ByteString] + , niResourcePath ∷ !Path , niExpectedContinue ∷ !Bool , niReqBodyLength ∷ !(Maybe RequestBodyLength) , niReceiveBodyReq ∷ !(TMVar ReceiveBodyRequest) - , niReceivedBody ∷ !(TMVar Strict.ByteString) + , niReceivedBody ∷ !(TMVar ByteString) , niResponse ∷ !(TVar Response) , niSendContinue ∷ !(TMVar Bool) @@ -147,6 +171,7 @@ data NormalInteraction , niWillDiscardBody ∷ !(TVar Bool) , niWillClose ∷ !(TVar Bool) , niResponseHasCType ∷ !(TVar Bool) + -- FIXME: use TBChan Builder (in stm-chans package) , niBodyToSend ∷ !(TMVar Builder) , niState ∷ !(TVar InteractionState) @@ -171,11 +196,17 @@ data InteractionState mkNormalInteraction ∷ Config → SockAddr +#if defined(HAVE_SSL) → Maybe X509 +#endif → AugmentedRequest - → [Strict.ByteString] + → Path → IO NormalInteraction +#if defined(HAVE_SSL) mkNormalInteraction config remoteAddr remoteCert (AugmentedRequest {..}) rsrcPath +#else +mkNormalInteraction config remoteAddr (AugmentedRequest {..}) rsrcPath +#endif = do receiveBodyReq ← newEmptyTMVarIO receivedBody ← newEmptyTMVarIO @@ -191,7 +222,9 @@ mkNormalInteraction config remoteAddr remoteCert (AugmentedRequest {..}) rsrcPat return NI { niConfig = config , niRemoteAddr = remoteAddr +#if defined(HAVE_SSL) , niRemoteCert = remoteCert +#endif , niRequest = arRequest , niResourcePath = rsrcPath , niExpectedContinue = arExpectedContinue @@ -214,15 +247,9 @@ mkNormalInteraction config remoteAddr remoteCert (AugmentedRequest {..}) rsrcPat type InteractionQueue = TVar (Seq SomeInteraction) mkInteractionQueue ∷ IO InteractionQueue +{-# INLINE mkInteractionQueue #-} mkInteractionQueue = newTVarIO (∅) -setResponseStatus ∷ NormalInteraction → StatusCode → STM () -setResponseStatus (NI {..}) sc - = do res ← readTVar niResponse - let res' = res { - resStatus = sc - } - writeTVar niResponse res' - getCurrentDate ∷ IO Ascii -getCurrentDate = HTTP.toAscii <$> getCurrentTime +{-# INLINE getCurrentDate #-} +getCurrentDate = flip proxy http ∘ cs <$> getCurrentTime