1 module Network.HTTP.Lucu.ResponseWriter
2 ( responseWriter -- Handle -> InteractionQueue -> IO ()
6 import qualified Data.ByteString.Lazy.Char8 as B
7 import Data.ByteString.Lazy.Char8 (ByteString)
8 import Control.Concurrent.STM
9 import Control.Exception
12 import qualified Data.Sequence as S
13 import Data.Sequence (Seq, ViewR(..))
14 import Network.HTTP.Lucu.Interaction
15 import Network.HTTP.Lucu.Response
16 import Prelude hiding (catch)
23 responseWriter :: Handle -> InteractionQueue -> IO ()
24 responseWriter h tQueue
25 = catch awaitSomethingToWrite $ \ exc ->
27 IOException _ -> return ()
30 awaitSomethingToWrite :: IO ()
35 queue <- readTVar tQueue
38 let _ :> itr = S.viewr queue
40 -- GettingBody 状態にあり、Continue が期待され
41 -- てゐて、それがまだ送信前なのであれば、
43 state <- readItr itr itrState id
45 if state == GettingBody then
46 writeContinueIfNecessary itr
48 if state >= DecidingBody then
49 writeHeaderOrBodyIfNecessary itr
54 writeContinueIfNecessary :: Interaction -> STM (IO ())
55 writeContinueIfNecessary itr
56 = do expectedContinue <- readItr itr itrExpectedContinue id
57 if expectedContinue then
59 do wroteContinue <- readItr itr itrWroteContinue id
64 return $ writeContinue itr
68 writeHeaderOrBodyIfNecessary :: Interaction -> STM (IO ())
69 writeHeaderOrBodyIfNecessary itr
70 -- DecidingBody 以降の状態にあり、まだヘッダを出力する前であ
71 -- れば、ヘッダを出力する。ヘッダ出力後であり、bodyToSend が
72 -- 空でなければ、それを出力する。空である時は、もし状態が
74 = do wroteHeader <- readItr itr itrWroteHeader id
76 if not wroteHeader then
77 return $ writeHeader itr
79 do bodyToSend <- readItr itr itrBodyToSend id
81 if B.null bodyToSend then
82 do state <- readItr itr itrState id
89 return $ writeBodyChunk itr
91 writeContinue :: Interaction -> IO ()
92 writeContinue itr = fail "FIXME: not implemented"
94 writeHeader :: Interaction -> IO ()
96 = do res <- atomically $ do writeItr itr itrWroteHeader True
97 readItr itr itrResponse id
98 hPutResponse h (fromJust res)
100 awaitSomethingToWrite
102 writeBodyChunk :: Interaction -> IO ()
104 = do willDiscardBody <- atomically $ readItr itr itrWillDiscardBody id
105 willChunkBody <- atomically $ readItr itr itrWillChunkBody id
106 chunk <- atomically $ do chunk <- readItr itr itrBodyToSend id
107 writeItr itr itrBodyToSend B.empty
109 unless willDiscardBody
110 $ do if willChunkBody then
111 do hPrintf h "%x\r\n" (toInteger $ B.length chunk)
117 awaitSomethingToWrite
119 finishBodyChunk :: Interaction -> IO ()
121 = do willDiscardBody <- atomically $ readItr itr itrWillDiscardBody id
122 willChunkBody <- atomically $ readItr itr itrWillChunkBody id
123 when (not willDiscardBody && willChunkBody)
124 $ hPutStr h "0\r\n" >> hFlush h
126 finalize :: Interaction -> IO ()
128 = do finishBodyChunk itr
129 willClose <- atomically $ do queue <- readTVar tQueue
131 let (remaining :> _) = S.viewr queue
132 writeTVar tQueue remaining
134 readItr itr itrWillClose id
138 awaitSomethingToWrite