]> gitweb @ CieloNegro.org - Lucu.git/blobdiff - Network/HTTP/Lucu/Postprocess.hs
changed everything like a maniac
[Lucu.git] / Network / HTTP / Lucu / Postprocess.hs
index 989ad164707ca9afb99f94f55dcc69fe2840e658..732c47a809002e39e08e522f2b5681e508b9143b 100644 (file)
@@ -1,6 +1,7 @@
 {-# LANGUAGE
-    BangPatterns
+    DoAndIfThenElse
   , OverloadedStrings
+  , RecordWildCards
   , UnicodeSyntax
   #-}
 module Network.HTTP.Lucu.Postprocess
@@ -9,29 +10,27 @@ module Network.HTTP.Lucu.Postprocess
     )
     where
 import Control.Applicative
-import           Control.Concurrent.STM
-import           Control.Monad
+import Control.Concurrent.STM
+import Control.Monad
 import Control.Monad.Unicode
 import Data.Ascii (Ascii, CIAscii)
 import qualified Data.Ascii as A
-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 Data.Monoid.Unicode
+import Data.Time
 import qualified Data.Time.HTTP as HTTP
-import           GHC.Conc (unsafeIOToSTM)
-import           Network.HTTP.Lucu.Abortion
-import           Network.HTTP.Lucu.Config
-import           Network.HTTP.Lucu.Headers
-import           Network.HTTP.Lucu.HttpVersion
-import           Network.HTTP.Lucu.Interaction
-import           Network.HTTP.Lucu.Request
-import           Network.HTTP.Lucu.Response
+import GHC.Conc (unsafeIOToSTM)
+import Network.HTTP.Lucu.Abortion
+import Network.HTTP.Lucu.Config
+import Network.HTTP.Lucu.Headers
+import Network.HTTP.Lucu.HttpVersion
+import Network.HTTP.Lucu.Interaction
+import Network.HTTP.Lucu.Request
+import Network.HTTP.Lucu.Response
 import Prelude.Unicode
-import           System.IO.Unsafe
 
 {-
+  TODO: Tanslate this memo into English. It doesn't make sense to
+  non-Japanese speakers.
   
   * Response が未設定なら、200 OK にする。
 
@@ -65,46 +64,56 @@ import           System.IO.Unsafe
 -}
 
 postprocess ∷ Interaction → STM ()
-postprocess !itr
-    = do reqM ← readItr itr itrRequest id
-         res  ← readItr itr itrResponse id
+postprocess (Interaction {..})
+    = do res  ← readTVar itrResponse
          let sc = resStatus res
 
          unless (any (\ p → p sc) [isSuccessful, isRedirection, isError])
-                  $ abortSTM InternalServerError []
-                        $ Just ("The status code is not good for a final status: "
-                                ++ show sc)
-
-         when (sc ≡ MethodNotAllowed ∧ getHeader (C8.pack "Allow") res ≡ Nothing)
-                  $ abortSTM InternalServerError []
-                        $ Just ("The status was " ++ show sc ++ " but no Allow header.")
-
-         when (sc /= NotModified ∧ isRedirection sc ∧ getHeader (C8.pack "Location") res ≡ Nothing)
-                  $ abortSTM InternalServerError []
-                        $ Just ("The status code was " ++ show sc ++ " but no Location header.")
-
-         when (reqM /= Nothing) relyOnRequest
+             $ abortSTM InternalServerError []
+             $ Just
+             $ 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
+             $ 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
+             $ A.fromAsciiBuilder
+             $ A.toAsciiBuilder "The status code was "
+             ⊕ printStatusCode sc
+             ⊕ A.toAsciiBuilder " but no Location header."
+
+         case itrRequest of
+           Just req → postprocessWithRequest sc req
+           Nothing  → return ()
 
          -- itrResponse の内容は relyOnRequest によって變へられてゐる可
          -- 能性が高い。
-         do oldRes ← readItr itr itrResponse id
+         do oldRes ← readTVar itrResponse
             newRes ← unsafeIOToSTM
-                     $ completeUnconditionalHeaders (itrConfig itr) oldRes
-            writeItr itr itrResponse newRes
+                     $ completeUnconditionalHeaders itrConfig oldRes
+            writeTVar itrResponse newRes
     where
-      relyOnRequest ∷ STM ()
-      relyOnRequest
-          = do status ← readItr itr itrResponse resStatus
-               req    ← readItr itr itrRequest fromJust
-
-               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"
@@ -114,34 +123,42 @@ postprocess !itr
                         $ updateRes $ setHeader "Content-Type" defaultPageContentType
 
                if canHaveBody then
-                   when (reqVer ≡ HttpVersion 1 1)
-                            $ do updateRes $ setHeader "Transfer-Encoding" "chunked"
-                                 writeItr itr itrWillChunkBody True
-                 else
+                   when (reqVersion ≡ HttpVersion 1 1)
+                       $ do updateRes $ setHeader "Transfer-Encoding" "chunked"
+                            writeTVar itrWillChunkBody True
+               else
                    -- body 関連のヘッダを削除。但し HEAD なら Content-* は殘す
-                   when (reqMethod req /= HEAD)
-                            $ do updateRes $ deleteHeader "Content-Type"
-                                 updateRes $ deleteHeader "Etag"
-                                 updateRes $ deleteHeader "Last-Modified"
+                   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 itr itrWillClose True
+                 Just value → when (value ≡ "close")
+                                  $ writeTVar itrWillClose True
 
-               willClose ← readItr itr itrWillClose id
+               willClose ← readTVar itrWillClose
                when willClose
-                        $ updateRes $ setHeader "Connection" "close"
+                   $ 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)
-      readHeader = readItr itr itrResponse ∘ getHeader
+      {-# INLINE readHeader #-}
+      readHeader k = getHeader k <$> readTVar itrResponse
+
+      readCIHeader ∷ CIAscii → STM (Maybe CIAscii)
+      {-# INLINE readCIHeader #-}
+      readCIHeader k = getCIHeader k <$> readTVar itrResponse
 
       updateRes ∷ (Response → Response) → STM ()
-      updateRes = updateItr itr itrResponse
+      {-# INLINE updateRes #-}
+      updateRes f
+          = do old ← readTVar itrResponse
+               writeTVar itrResponse (f old)
 
 completeUnconditionalHeaders ∷ Config → Response → IO Response
 completeUnconditionalHeaders conf = (compDate =≪) ∘ compServer
@@ -158,4 +175,4 @@ completeUnconditionalHeaders conf = (compDate =≪) ∘ compServer
                 Just _  → return res'
 
 getCurrentDate ∷ IO Ascii
-getCurrentDate = HTTP.format <$> getCurrentTime
+getCurrentDate = HTTP.toAscii <$> getCurrentTime