X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FInteraction.hs;h=19faec28fe7a1fb506f42d5416123f17ec52a61d;hb=c7a8bc012b1b70353d567bfab86fc6e849d60c20;hp=6045d97752e9551f1cf449da20939f60adb56e9e;hpb=34b0ad7f2ffc5e7ca67fa3468d01c5551edc8a8b;p=Lucu.git diff --git a/Network/HTTP/Lucu/Interaction.hs b/Network/HTTP/Lucu/Interaction.hs index 6045d97..19faec2 100644 --- a/Network/HTTP/Lucu/Interaction.hs +++ b/Network/HTTP/Lucu/Interaction.hs @@ -1,4 +1,8 @@ --- #hide +{-# LANGUAGE + BangPatterns + , OverloadedStrings + , UnicodeSyntax + #-} module Network.HTTP.Lucu.Interaction ( Interaction(..) , InteractionState(..) @@ -14,56 +18,57 @@ module Network.HTTP.Lucu.Interaction , updateItrF ) where - -import Control.Concurrent.STM -import qualified Data.ByteString.Lazy.Char8 as B -import Data.ByteString.Lazy.Char8 (ByteString) +import Control.Applicative +import Control.Concurrent.STM +import Data.Ascii (Ascii) +import qualified Data.ByteString as BS +import Data.Sequence (Seq) import qualified Data.Sequence as S -import Data.Sequence (Seq) -import Network -import Network.HTTP.Lucu.Config -import Network.HTTP.Lucu.HttpVersion -import Network.HTTP.Lucu.Request -import Network.HTTP.Lucu.Response +import Network.Socket +import Network.HTTP.Lucu.Config +import Network.HTTP.Lucu.Headers +import Network.HTTP.Lucu.HttpVersion +import Network.HTTP.Lucu.Request +import Network.HTTP.Lucu.Response +import OpenSSL.X509 +import Prelude.Unicode data Interaction = Interaction { - itrConfig :: Config - , itrRemoteHost :: HostName - , itrResourcePath :: Maybe [String] - , itrRequest :: Maybe Request - , itrResponse :: TVar Response - - -- FIXME: この三つは本來 TVar であるべきでないので、唯の Bool にす - -- るに越した事は無いが、それは重要でない。そんな golf で自分の貴重 - -- な時間を /dev/null に突っ込むのは、他にしたい事が何も無くなって - -- からにすべき。 - , itrRequestHasBody :: TVar Bool - , itrRequestIsChunked :: TVar Bool - , itrExpectedContinue :: TVar Bool - - , itrReqChunkLength :: TVar (Maybe Int) - , itrReqChunkRemaining :: TVar (Maybe Int) - , itrReqChunkIsOver :: TVar Bool - , itrReqBodyWanted :: TVar (Maybe Int) - , itrReqBodyWasteAll :: TVar Bool - , itrReceivedBody :: TVar ByteString -- Resource が受領した部分は削除される - - , itrWillReceiveBody :: TVar Bool - , itrWillChunkBody :: TVar Bool - , itrWillDiscardBody :: TVar Bool - , itrWillClose :: TVar Bool - - , itrBodyToSend :: TVar ByteString - , itrBodyIsNull :: TVar Bool - - , itrState :: TVar InteractionState - - , itrWroteContinue :: TVar Bool - , itrWroteHeader :: TVar Bool + itrConfig ∷ !Config + , itrLocalPort ∷ !PortNumber + , itrRemoteAddr ∷ !SockAddr + , itrRemoteCert ∷ !(Maybe X509) + , itrResourcePath ∷ !(Maybe [Ascii]) + , itrRequest ∷ !(TVar (Maybe Request)) + , itrResponse ∷ !(TVar Response) + + , itrRequestHasBody ∷ !(TVar Bool) + , itrRequestIsChunked ∷ !(TVar Bool) + , itrExpectedContinue ∷ !(TVar Bool) + + , itrReqChunkLength ∷ !(TVar (Maybe Int)) + , itrReqChunkRemaining ∷ !(TVar (Maybe Int)) + , itrReqChunkIsOver ∷ !(TVar Bool) + , itrReqBodyWanted ∷ !(TVar (Maybe Int)) + , itrReqBodyWasteAll ∷ !(TVar Bool) + , itrReceivedBody ∷ !(TVar (Seq BS.ByteString)) + + , itrWillReceiveBody ∷ !(TVar Bool) + , itrWillChunkBody ∷ !(TVar Bool) + , itrWillDiscardBody ∷ !(TVar Bool) + , itrWillClose ∷ !(TVar Bool) + + , itrBodyToSend ∷ !(TVar (Seq BS.ByteString)) + , itrBodyIsNull ∷ !(TVar Bool) + + , itrState ∷ !(TVar InteractionState) + + , itrWroteContinue ∷ !(TVar Bool) + , itrWroteHeader ∷ !(TVar Bool) } --- Resource の視點で見た時の状態。常に上から下へ行き、逆行しない。初期 --- 状態は ExaminingRequest。 +-- |The interaction state of Resource monad. 'ExaminingRequest' is the +-- initial state. data InteractionState = ExaminingRequest | GettingBody | DecidingHeader @@ -73,56 +78,56 @@ data InteractionState = ExaminingRequest type InteractionQueue = TVar (Seq Interaction) - -newInteractionQueue :: IO InteractionQueue +newInteractionQueue ∷ IO InteractionQueue newInteractionQueue = newTVarIO S.empty - -defaultPageContentType :: String +defaultPageContentType ∷ Ascii defaultPageContentType = "application/xhtml+xml" - -newInteraction :: Config -> HostName -> Maybe Request -> IO Interaction -newInteraction conf host req - = do responce <- newTVarIO $ Response { +newInteraction ∷ Config → PortNumber → SockAddr → Maybe X509 → Maybe Request → IO Interaction +newInteraction !conf !port !addr !cert !req + = do request ← newTVarIO req + responce ← newTVarIO Response { resVersion = HttpVersion 1 1 , resStatus = Ok - , resHeaders = [("Content-Type", defaultPageContentType)] + , resHeaders = toHeaders [("Content-Type", defaultPageContentType)] } - requestHasBody <- newTVarIO False - requestIsChunked <- newTVarIO False - expectedContinue <- newTVarIO False + requestHasBody ← newTVarIO False + requestIsChunked ← newTVarIO False + expectedContinue ← newTVarIO False - reqChunkLength <- newTVarIO Nothing -- 現在のチャンク長 - reqChunkRemaining <- newTVarIO Nothing -- 現在のチャンクの殘り - reqChunkIsOver <- newTVarIO False -- 最後のチャンクを讀み終へた - reqBodyWanted <- newTVarIO Nothing -- Resource が要求してゐるチャンク長 - reqBodyWasteAll <- newTVarIO False -- 殘りの body を讀み捨てよと云ふ要求 - receivedBody <- newTVarIO B.empty + reqChunkLength ← newTVarIO Nothing -- 現在のチャンク長 + reqChunkRemaining ← newTVarIO Nothing -- 現在のチャンクの殘り + reqChunkIsOver ← newTVarIO False -- 最後のチャンクを讀み終へた + reqBodyWanted ← newTVarIO Nothing -- Resource が要求してゐるチャンク長 + reqBodyWasteAll ← newTVarIO False -- 殘りの body を讀み捨てよと云ふ要求 + receivedBody ← newTVarIO S.empty - willReceiveBody <- newTVarIO False - willChunkBody <- newTVarIO False - willDiscardBody <- newTVarIO False - willClose <- newTVarIO False + willReceiveBody ← newTVarIO False + willChunkBody ← newTVarIO False + willDiscardBody ← newTVarIO False + willClose ← newTVarIO False - bodyToSend <- newTVarIO B.empty - bodyIsNull <- newTVarIO True -- 一度でも bodyToSend が空でなくなったら False + bodyToSend ← newTVarIO S.empty + bodyIsNull ← newTVarIO True -- 一度でも bodyToSend が空でなくなったら False - state <- newTVarIO ExaminingRequest + state ← newTVarIO ExaminingRequest - wroteContinue <- newTVarIO False - wroteHeader <- newTVarIO False + wroteContinue ← newTVarIO False + wroteHeader ← newTVarIO False - return $ Interaction { + return Interaction { itrConfig = conf - , itrRemoteHost = host + , itrLocalPort = port + , itrRemoteAddr = addr + , itrRemoteCert = cert , itrResourcePath = Nothing - , itrRequest = req + , itrRequest = request , itrResponse = responce - , itrRequestHasBody = requestHasBody - , itrRequestIsChunked = requestIsChunked + , itrRequestHasBody = requestHasBody + , itrRequestIsChunked = requestIsChunked , itrExpectedContinue = expectedContinue , itrReqChunkLength = reqChunkLength @@ -146,28 +151,28 @@ newInteraction conf host req , itrWroteHeader = wroteHeader } +writeItr ∷ Interaction → (Interaction → TVar a) → a → STM () +{-# INLINE writeItr #-} +writeItr itr accessor + = writeTVar (accessor itr) -writeItr :: Interaction -> (Interaction -> TVar a) -> a -> STM () -writeItr itr accessor value - = writeTVar (accessor itr) value - - -readItr :: Interaction -> (Interaction -> TVar a) -> (a -> b) -> STM b +readItr ∷ Interaction → (Interaction → TVar a) → (a → b) → STM b +{-# INLINE readItr #-} readItr itr accessor reader - = readTVar (accessor itr) >>= return . reader - + = reader <$> readTVar (accessor itr) -readItrF :: (Functor f) => Interaction -> (Interaction -> TVar (f a)) -> (a -> b) -> STM (f b) +readItrF ∷ Functor f => Interaction → (Interaction → TVar (f a)) → (a → b) → STM (f b) +{-# INLINE readItrF #-} readItrF itr accessor reader = readItr itr accessor (fmap reader) - -updateItr :: Interaction -> (Interaction -> TVar a) -> (a -> a) -> STM () +updateItr ∷ Interaction → (Interaction → TVar a) → (a → a) → STM () +{-# INLINE updateItr #-} updateItr itr accessor updator - = do old <- readItr itr accessor id + = do old ← readItr itr accessor id writeItr itr accessor (updator old) - -updateItrF :: (Functor f) => Interaction -> (Interaction -> TVar (f a)) -> (a -> a) -> STM () -updateItrF itr accessor updator - = updateItr itr accessor (fmap updator) +updateItrF ∷ Functor f => Interaction → (Interaction → TVar (f a)) → (a → a) → STM () +{-# INLINE updateItrF #-} +updateItrF itr accessor + = updateItr itr accessor ∘ fmap