X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Lucu.git;a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FPostprocess.hs;h=d3659cc78905f89082d70824b5e0f621ab316fb9;hp=6e8a5e6753b5bafdf6bbebc2448b76730e07afd3;hb=3d017dd65ddede9a11c5b7a34a91e04340e67bc4;hpb=e1e74c8f81ccbc57bf5a09987b0a9dd42648f020 diff --git a/Network/HTTP/Lucu/Postprocess.hs b/Network/HTTP/Lucu/Postprocess.hs index 6e8a5e6..d3659cc 100644 --- a/Network/HTTP/Lucu/Postprocess.hs +++ b/Network/HTTP/Lucu/Postprocess.hs @@ -6,10 +6,11 @@ module Network.HTTP.Lucu.Postprocess import Control.Concurrent.STM import Control.Monad -import Data.ByteString.Base (ByteString) -import qualified Data.ByteString.Char8 as C8 +import qualified Data.ByteString as Strict (ByteString) +import qualified Data.ByteString.Char8 as C8 hiding (ByteString) import Data.IORef import Data.Maybe +import Data.Time import GHC.Conc (unsafeIOToSTM) import Network.HTTP.Lucu.Abortion import Network.HTTP.Lucu.Config @@ -19,7 +20,6 @@ import Network.HTTP.Lucu.Interaction import Network.HTTP.Lucu.RFC1123DateTime import Network.HTTP.Lucu.Request import Network.HTTP.Lucu.Response -import System.Time import System.IO.Unsafe {- @@ -75,8 +75,7 @@ postprocess itr $ abortSTM InternalServerError [] $ Just ("The status code was " ++ show sc ++ " but no Location header.") - when (reqM /= Nothing) - $ relyOnRequest itr + when (reqM /= Nothing) relyOnRequest -- itrResponse の内容は relyOnRequest によって變へられてゐる可 -- 能性が高い。 @@ -85,10 +84,9 @@ postprocess itr $ completeUnconditionalHeaders (itrConfig itr) oldRes writeItr itr itrResponse newRes where - relyOnRequest :: Interaction -> STM () - relyOnRequest itr - = itr `seq` - do status <- readItr itr itrResponse resStatus + relyOnRequest :: STM () + relyOnRequest + = do status <- readItr itr itrResponse resStatus req <- readItr itr itrRequest fromJust let reqVer = reqVersion req @@ -100,25 +98,25 @@ postprocess itr status == ResetContent || status == NotModified ) - updateRes itr $! deleteHeader (C8.pack "Content-Length") - updateRes itr $! deleteHeader (C8.pack "Transfer-Encoding") + updateRes $! deleteHeader (C8.pack "Content-Length") + updateRes $! deleteHeader (C8.pack "Transfer-Encoding") - cType <- readHeader itr (C8.pack "Content-Type") + cType <- readHeader (C8.pack "Content-Type") when (cType == Nothing) - $ updateRes itr $ setHeader (C8.pack "Content-Type") defaultPageContentType + $ updateRes $ setHeader (C8.pack "Content-Type") defaultPageContentType if canHaveBody then when (reqVer == HttpVersion 1 1) - $ do updateRes itr $! setHeader (C8.pack "Transfer-Encoding") (C8.pack "chunked") + $ do updateRes $! setHeader (C8.pack "Transfer-Encoding") (C8.pack "chunked") writeItr itr itrWillChunkBody True else -- body 関連のヘッダを削除。但し HEAD なら Content-* は殘す when (reqMethod req /= HEAD) - $ do updateRes itr $! deleteHeader (C8.pack "Content-Type") - updateRes itr $! deleteHeader (C8.pack "Etag") - updateRes itr $! deleteHeader (C8.pack "Last-Modified") + $ do updateRes $! deleteHeader (C8.pack "Content-Type") + updateRes $! deleteHeader (C8.pack "Etag") + updateRes $! deleteHeader (C8.pack "Last-Modified") - conn <- readHeader itr (C8.pack "Connection") + conn <- readHeader (C8.pack "Connection") case conn of Nothing -> return () Just value -> if value `noCaseEq` C8.pack "close" then @@ -128,19 +126,19 @@ postprocess itr willClose <- readItr itr itrWillClose id when willClose - $ updateRes itr $! setHeader (C8.pack "Connection") (C8.pack "close") + $ updateRes $! setHeader (C8.pack "Connection") (C8.pack "close") when (reqMethod req == HEAD || not canHaveBody) $ writeTVar (itrWillDiscardBody itr) True - readHeader :: Interaction -> ByteString -> STM (Maybe ByteString) - readHeader itr name - = itr `seq` name `seq` + readHeader :: Strict.ByteString -> STM (Maybe Strict.ByteString) + readHeader name + = name `seq` readItr itr itrResponse $ getHeader name - updateRes :: Interaction -> (Response -> Response) -> STM () - updateRes itr updator - = itr `seq` updator `seq` + updateRes :: (Response -> Response) -> STM () + updateRes updator + = updator `seq` updateItr itr itrResponse updator @@ -149,30 +147,37 @@ completeUnconditionalHeaders conf res = conf `seq` res `seq` return res >>= compServer >>= compDate >>= return where - compServer res - = case getHeader (C8.pack "Server") res of - Nothing -> return $ setHeader (C8.pack "Server") (cnfServerSoftware conf) res - Just _ -> return res + compServer res' + = case getHeader (C8.pack "Server") res' of + Nothing -> return $ setHeader (C8.pack "Server") (cnfServerSoftware conf) res' + Just _ -> return res' - compDate res - = case getHeader (C8.pack "Date") res of + compDate res' + = case getHeader (C8.pack "Date") res' of Nothing -> do date <- getCurrentDate - return $ setHeader (C8.pack "Date") date res - Just _ -> return res + return $ setHeader (C8.pack "Date") date res' + Just _ -> return res' -cache :: IORef (ClockTime, ByteString) +cache :: IORef (UTCTime, Strict.ByteString) cache = unsafePerformIO $ - newIORef (TOD 0 0, undefined) + newIORef (UTCTime (ModifiedJulianDay 0) 0, undefined) {-# NOINLINE cache #-} -getCurrentDate :: IO ByteString -getCurrentDate = do now@(TOD curSec _) <- getClockTime - (TOD cachedSec _, cachedStr) <- readIORef cache +getCurrentDate :: IO Strict.ByteString +getCurrentDate = do now <- getCurrentTime + (cachedTime, cachedStr) <- readIORef cache - if curSec == cachedSec then + if now `mostlyEq` cachedTime then return cachedStr else do let dateStr = C8.pack $ formatHTTPDateTime now writeIORef cache (now, dateStr) - return dateStr \ No newline at end of file + return dateStr + where + mostlyEq :: UTCTime -> UTCTime -> Bool + mostlyEq a b + = if utctDay a == utctDay b then + fromEnum (utctDayTime a) == fromEnum (utctDayTime b) + else + False