on master help sign in
log and conditional request.
301ed56Kazu Yamamoto
warp/Network/Wai/Handler/Warp/HTTP2.hs+1−1
@@ -30,7 +30,7 @@ http2 conn ii addr transport settings readN app = do
30 ctx <- newContext
30 ctx <- newContext
31 -- Workers & Manager
31 -- Workers & Manager
32 mgr <- start
32 mgr <- start
33− let responder = response ctx mgr
33+ let responder = response ii settings ctx mgr
34 action = worker ctx settings tm app responder
34 action = worker ctx settings tm app responder
35 setAction mgr action
35 setAction mgr action
36 -- fixme: hard coding: 10
36 -- fixme: hard coding: 10
warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+3−1
@@ -214,7 +214,9 @@ frameSender ctx@Context{outputQ,connectionWindow}
214 -- the context would be switched to the receiver,
214 -- the context would be switched to the receiver,
215 -- resulting the inconsistency of concurrency.
215 -- resulting the inconsistency of concurrency.
216 case mnext of
216 case mnext of
217− CFinish -> closed ctx strm Finished
217+ CFinish -> do closed ctx strm Finished
218+ logger <- readIORef $ streamLogger strm
219+ logger
218 _ -> return ()
220 _ -> return ()
219 flushN total
221 flushN total
220 atomically $ do
222 atomically $ do
warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+2
@@ -179,6 +179,7 @@ data Stream = Stream {
179 , streamBodyLength :: IORef Int
179 , streamBodyLength :: IORef Int
180 , streamWindow :: TVar WindowSize
180 , streamWindow :: TVar WindowSize
181 , streamPrecedence :: IORef Precedence
181 , streamPrecedence :: IORef Precedence
182+ , streamLogger :: IORef (IO ())
182 }
183 }
183
184
184instance Show Stream where
185instance Show Stream where
@@ -190,6 +191,7 @@ newStream sid win = Stream sid <$> newIORef Idle
190 <*> newIORef 0
191 <*> newIORef 0
191 <*> newTVarIO win
192 <*> newTVarIO win
192 <*> newIORef defaultPrecedence
193 <*> newIORef defaultPrecedence
194+ <*> newIORef (return ())
193
195
194----------------------------------------------------------------
196----------------------------------------------------------------
195
197
warp/Network/Wai/Handler/Warp/HTTP2/Worker.hs+89−36
@@ -2,6 +2,8 @@
2{-# LANGUAGE NamedFieldPuns #-}
2{-# LANGUAGE NamedFieldPuns #-}
3{-# LANGUAGE PatternGuards #-}
3{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE CPP #-}
4{-# LANGUAGE CPP #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE OverloadedStrings #-}
5
7
6module Network.Wai.Handler.Warp.HTTP2.Worker (
8module Network.Wai.Handler.Warp.HTTP2.Worker (
7 Responder
9 Responder
@@ -17,18 +19,23 @@ import Control.Concurrent.STM
17import Control.Exception (Exception, SomeException(..), AsyncException(..))
19import Control.Exception (Exception, SomeException(..), AsyncException(..))
18import qualified Control.Exception as E
20import qualified Control.Exception as E
19import Control.Monad (void, when)
21import Control.Monad (void, when)
22+import Data.ByteString.Builder (byteString)
20import Data.Typeable
23import Data.Typeable
21import qualified Network.HTTP.Types as H
24import qualified Network.HTTP.Types as H
22import Network.HTTP2
25import Network.HTTP2
23import Network.HTTP2.Priority
26import Network.HTTP2.Priority
24import Network.Wai
27import Network.Wai
28+import Network.Wai.Handler.Warp.File
29+import Network.Wai.Handler.Warp.FileInfoCache
25import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
30import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
26import Network.Wai.Handler.Warp.HTTP2.Manager
31import Network.Wai.Handler.Warp.HTTP2.Manager
27import Network.Wai.Handler.Warp.HTTP2.Types
32import Network.Wai.Handler.Warp.HTTP2.Types
33+import Network.Wai.Handler.Warp.Header
28import Network.Wai.Handler.Warp.IORef
34import Network.Wai.Handler.Warp.IORef
29import qualified Network.Wai.Handler.Warp.Response as R
35import qualified Network.Wai.Handler.Warp.Response as R
30import qualified Network.Wai.Handler.Warp.Settings as S
36import qualified Network.Wai.Handler.Warp.Settings as S
31import qualified Network.Wai.Handler.Warp.Timeout as T
37import qualified Network.Wai.Handler.Warp.Timeout as T
38+import Network.Wai.Handler.Warp.Types
32import Network.Wai.Internal (Response(..), ResponseReceived(..), ResponseReceived(..))
39import Network.Wai.Internal (Response(..), ResponseReceived(..), ResponseReceived(..))
33
40
34----------------------------------------------------------------
41----------------------------------------------------------------
@@ -42,42 +49,88 @@ type Responder = ThreadContinue -> T.Handle -> Stream -> Request ->
42-- | This function is passed to workers.
49-- | This function is passed to workers.
43-- They also pass 'Response's from 'Application's to this function.
50-- They also pass 'Response's from 'Application's to this function.
44-- This function enqueues commands for the HTTP/2 sender.
51-- This function enqueues commands for the HTTP/2 sender.
45−response :: Context -> Manager -> Responder
52+response :: InternalInfo -> S.Settings -> Context -> Manager -> Responder
46−response Context{outputQ} mgr tconf th strm req rsp = do
53+response ii settings Context{outputQ} mgr tconf th strm req rsp
47− case rsp of
54+ | R.hasBody s0 = case rsp of
48− ResponseStream _ _ strmbdy -> do
55+ ResponseStream _ _ strmbdy
56+ | isHead -> responseNoBody s0 hs0
57+ | otherwise -> responseStreaming strmbdy
58+ ResponseBuilder _ _ b
59+ | isHead -> responseNoBody s0 hs0
60+ | otherwise -> responseBuilderBody s0 hs0 b
61+ ResponseFile _ _ p mp -> responseFileXXX p mp
62+ ResponseRaw _ _ -> error "HTTP/2 does not support ResponseRaw"
63+ | otherwise = responseNoBody s0 hs0
64+ where
65+ isHead = requestMethod req == H.methodHead
66+ s0 = responseStatus rsp
67+ hs0 = responseHeaders rsp
68+ logger = S.settingsLogger settings req
69+
70+ responseNoBody s hs = responseBuilderBody s hs mempty
71+
72+ responseBuilderBody s hs bdy = do
73+ writeIORef (streamLogger strm) (logger s Nothing)
74+ setThreadContinue tconf True
75+ let rsp' = ResponseBuilder s hs bdy
76+ out = OResponse strm rsp' (Oneshot True)
77+ enqueueOrSpawnTemporaryWaiter strm outputQ out
78+ return ResponseReceived
79+
80+ responseFileXXX path Nothing = do
81+ efinfo <- E.try $ fileInfo ii path
82+ case efinfo of
83+ Left (_ex :: E.IOException) -> response404
84+ Right finfo -> case conditionalRequest finfo hs0 (indexRequestHeader (requestHeaders req)) of
85+ WithoutBody s -> responseNoBody s hs0
86+ WithBody s hs beg len -> responseFile2XX s hs path (Just (FilePart beg len (fileInfoSize finfo)))
87+
88+ responseFileXXX path mpart = responseFile2XX s0 hs0 path mpart
89+
90+ responseFile2XX s hs path mpart
91+ | isHead = responseNoBody s hs
92+ | otherwise = do
93+ writeIORef (streamLogger strm) (logger s (filePartByteCount <$> mpart))
94+ setThreadContinue tconf True
95+ let rsp' = ResponseFile s hs path mpart
96+ out = OResponse strm rsp' (Oneshot True)
97+ enqueueOrSpawnTemporaryWaiter strm outputQ out
98+ return ResponseReceived
99+
100+ response404 = responseBuilderBody s hs body
101+ where
102+ s = H.notFound404
103+ hs = R.replaceHeader H.hContentType "text/plain; charset=utf-8" hs0
104+ body = byteString "File not found"
105+
106+ responseStreaming strmbdy = do
107+ writeIORef (streamLogger strm) (logger s0 Nothing)
49− -- We must not exit this WAI application.
108+ -- We must not exit this WAI application.
50− -- If the application exits, streaming would be also closed.
109+ -- If the application exits, streaming would be also closed.
51− -- So, this work occupies this thread.
110+ -- So, this work occupies this thread.
52− --
111+ --
53− -- We need to increase the number of workers.
112+ -- We need to increase the number of workers.
54− myThreadId >>= replaceWithAction mgr
113+ myThreadId >>= replaceWithAction mgr
55− -- After this work, this thread stops to decease
114+ -- After this work, this thread stops to decease
56− -- the number of workers.
115+ -- the number of workers.
57− setThreadContinue tconf False
116+ setThreadContinue tconf False
58− -- Since 'StreamingBody' is loop, we cannot control it.
117+ -- Since 'StreamingBody' is loop, we cannot control it.
59− -- So, let's serialize 'Builder' with a designated queue.
118+ -- So, let's serialize 'Builder' with a designated queue.
60− sq <- newTBQueueIO 10 -- fixme: hard coding: 10
119+ sq <- newTBQueueIO 10 -- fixme: hard coding: 10
61− tvar <- newTVarIO SyncNone
120+ tvar <- newTVarIO SyncNone
62− let out = OResponse strm rsp (Persist sq tvar)
121+ let out = OResponse strm rsp (Persist sq tvar)
63− -- Since we must not enqueue an empty queue to the priority
122+ -- Since we must not enqueue an empty queue to the priority
64− -- queue, we spawn a thread to ensure that the designated
123+ -- queue, we spawn a thread to ensure that the designated
65− -- queue is not empty.
124+ -- queue is not empty.
66− void $ forkIO $ waiter tvar sq outputQ
125+ void $ forkIO $ waiter tvar sq outputQ
67− atomically $ writeTVar tvar (SyncNext out)
126+ atomically $ writeTVar tvar (SyncNext out)
68− let push b = do
127+ let push b = do
69− atomically $ writeTBQueue sq (SBuilder b)
128+ atomically $ writeTBQueue sq (SBuilder b)
70− T.tickle th
129+ T.tickle th
71− flush = atomically $ writeTBQueue sq SFlush
130+ flush = atomically $ writeTBQueue sq SFlush
72− strmbdy push flush
131+ _ <- strmbdy push flush
73− atomically $ writeTBQueue sq SFinish
132+ atomically $ writeTBQueue sq SFinish
74− _ -> do
75− setThreadContinue tconf True
76− let hasBody = requestMethod req /= H.methodHead
77− && R.hasBody (responseStatus rsp)
78− out = OResponse strm rsp (Oneshot hasBody)
79− enqueueOrSpawnTemporaryWaiter strm outputQ out
80− return ResponseReceived
133+ return ResponseReceived
81
134
82data Break = Break deriving (Show, Typeable)
135data Break = Break deriving (Show, Typeable)
83
136
warp/Network/Wai/Handler/Warp/Response.hs+1
@@ -11,6 +11,7 @@ module Network.Wai.Handler.Warp.Response (
11 , addDate
11 , addDate
12 , addServer
12 , addServer
13 , hasBody
13 , hasBody
14+ , replaceHeader
14 ) where
15 ) where
15
16
16#ifndef MIN_VERSION_base
17#ifndef MIN_VERSION_base