X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FPostprocess.hs;h=4950a0b97006e29b00446a9a6cfbf8ee90ea1781;hb=2bb7a0b;hp=a7c2e070843c45b4f357687c81cebb083a9d02e7;hpb=db4b61223e0d8b34079d3b190fb3e3644b0b4866;p=Lucu.git diff --git a/Network/HTTP/Lucu/Postprocess.hs b/Network/HTTP/Lucu/Postprocess.hs index a7c2e07..4950a0b 100644 --- a/Network/HTTP/Lucu/Postprocess.hs +++ b/Network/HTTP/Lucu/Postprocess.hs @@ -1,7 +1,7 @@ {-# LANGUAGE - BangPatterns - , DoAndIfThenElse + DoAndIfThenElse , OverloadedStrings + , RecordWildCards , UnicodeSyntax #-} module Network.HTTP.Lucu.Postprocess @@ -15,7 +15,6 @@ import Control.Monad import Control.Monad.Unicode import Data.Ascii (Ascii, CIAscii) import qualified Data.Ascii as A -import Data.Maybe import Data.Monoid.Unicode import Data.Time import qualified Data.Time.HTTP as HTTP @@ -30,6 +29,8 @@ import Network.HTTP.Lucu.Response import Prelude.Unicode {- + TODO: Tanslate this memo into English. It doesn't make sense to + non-Japanese speakers. * Response が未設定なら、200 OK にする。 @@ -63,53 +64,57 @@ import Prelude.Unicode -} postprocess ∷ Interaction → STM () -postprocess !itr - = do reqM ← readItr itrRequest id itr - res ← readItr itrResponse id itr +postprocess (Interaction {..}) + = do res ← readTVar itrResponse let sc = resStatus res unless (any (\ p → p sc) [isSuccessful, isRedirection, isError]) $ abortSTM InternalServerError [] $ Just - $ A.toText ( "The status code is not good for a final status of a response: " - ⊕ printStatusCode sc ) + $ A.toText + $ A.fromAsciiBuilder + $ A.toAsciiBuilder "The status code is not good for a final status of a response: " + ⊕ printStatusCode sc when (sc ≡ MethodNotAllowed ∧ getHeader "Allow" res ≡ Nothing) $ abortSTM InternalServerError [] $ Just - $ A.toText ( "The status was " - ⊕ printStatusCode sc - ⊕ " but no Allow header." ) + $ A.toText + $ A.fromAsciiBuilder + $ A.toAsciiBuilder "The status was " + ⊕ printStatusCode sc + ⊕ A.toAsciiBuilder " but no Allow header." when (sc ≢ NotModified ∧ isRedirection sc ∧ getHeader "Location" res ≡ Nothing) $ abortSTM InternalServerError [] $ Just - $ A.toText ( "The status code was " - ⊕ printStatusCode sc - ⊕ " but no Location header." ) + $ A.toText + $ A.fromAsciiBuilder + $ A.toAsciiBuilder "The status code was " + ⊕ printStatusCode sc + ⊕ A.toAsciiBuilder " but no Location header." - when (reqM ≢ Nothing) relyOnRequest + reqM ← readTVar itrRequest + case reqM of + Just req → postprocessWithRequest sc req + Nothing → return () -- itrResponse の内容は relyOnRequest によって變へられてゐる可 -- 能性が高い。 - do oldRes ← readItr itrResponse id itr + do oldRes ← readTVar itrResponse newRes ← unsafeIOToSTM - $ completeUnconditionalHeaders (itrConfig itr) oldRes - writeItr itrResponse newRes itr + $ completeUnconditionalHeaders itrConfig oldRes + writeTVar itrResponse newRes where - relyOnRequest ∷ STM () - relyOnRequest - = do status ← readItr itrResponse resStatus itr - req ← readItr itrRequest fromJust itr - - let reqVer = reqVersion req - canHaveBody = if reqMethod req ≡ HEAD then + postprocessWithRequest ∷ StatusCode → Request → STM () + postprocessWithRequest sc (Request {..}) + = do let canHaveBody = if reqMethod ≡ HEAD then False else - not (isInformational status ∨ - status ≡ NoContent ∨ - status ≡ ResetContent ∨ - status ≡ NotModified ) + (¬) (isInformational sc ∨ + sc ≡ NoContent ∨ + sc ≡ ResetContent ∨ + sc ≡ NotModified ) updateRes $ deleteHeader "Content-Length" updateRes $ deleteHeader "Transfer-Encoding" @@ -119,36 +124,42 @@ postprocess !itr $ updateRes $ setHeader "Content-Type" defaultPageContentType if canHaveBody then - when (reqVer ≡ HttpVersion 1 1) + when (reqVersion ≡ HttpVersion 1 1) $ do updateRes $ setHeader "Transfer-Encoding" "chunked" - writeItr itrWillChunkBody True itr + writeTVar itrWillChunkBody True else -- body 関連のヘッダを削除。但し HEAD なら Content-* は殘す - when (reqMethod req ≢ HEAD) + when (reqMethod ≢ HEAD) $ do updateRes $ deleteHeader "Content-Type" updateRes $ deleteHeader "Etag" updateRes $ deleteHeader "Last-Modified" - conn ← readHeader "Connection" + conn ← readCIHeader "Connection" case conn of Nothing → return () - Just value → when (A.toCIAscii value ≡ "close") - $ writeItr itrWillClose True itr + Just value → when (value ≡ "close") + $ writeTVar itrWillClose True - willClose ← readItr itrWillClose id itr + willClose ← readTVar itrWillClose when willClose $ updateRes $ setHeader "Connection" "close" - when (reqMethod req ≡ HEAD ∨ not canHaveBody) - $ writeTVar (itrWillDiscardBody itr) True + when (reqMethod ≡ HEAD ∨ not canHaveBody) + $ writeTVar itrWillDiscardBody True readHeader ∷ CIAscii → STM (Maybe Ascii) {-# INLINE readHeader #-} - readHeader k = readItr itrResponse (getHeader k) itr + readHeader k = getHeader k <$> readTVar itrResponse + + readCIHeader ∷ CIAscii → STM (Maybe CIAscii) + {-# INLINE readCIHeader #-} + readCIHeader k = getCIHeader k <$> readTVar itrResponse updateRes ∷ (Response → Response) → STM () {-# INLINE updateRes #-} - updateRes f = updateItr itrResponse f itr + updateRes f + = do old ← readTVar itrResponse + writeTVar itrResponse (f old) completeUnconditionalHeaders ∷ Config → Response → IO Response completeUnconditionalHeaders conf = (compDate =≪) ∘ compServer