on master help sign in
Merge branch 'new-hpack'
commitea43ec0483818f31dbd4ac1fef9f885fee7889fa authorKazu Yamamoto <kazu@iij.ad.jp> dateMon 22 Feb 2016, 11:39 (11 years ago) parent3f4ca586920e7a
4 files changed+41−62
warp/Network/Wai/Handler/Warp/HTTP2/HPACK.hs+20−28 warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+14−27 warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+5−5 warp/warp.cabal+2−2
warp/Network/Wai/Handler/Warp/HTTP2/HPACK.hs+20−28
@@ -1,16 +1,13 @@
11{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE NamedFieldPuns #-}
2+{-# LANGUAGE NamedFieldPuns, RecordWildCards #-}
33
44module Network.Wai.Handler.Warp.HTTP2.HPACK where
55
66import Control.Arrow (first)
77import qualified Control.Exception as E
8−import qualified Data.ByteString as B
9−import Data.ByteString.Builder (Builder)
108import qualified Data.ByteString.Char8 as B8
119import Data.CaseInsensitive (foldedCase)
12−import Data.IORef (readIORef, writeIORef)
13−import Network.HPACK
10+import Network.HPACK hiding (Buffer)
1411import qualified Network.HTTP.Types as H
1512import Network.HTTP2
1613import Network.Wai.Handler.Warp.HTTP2.Types
@@ -22,39 +19,34 @@ import Network.Wai.Handler.Warp.Types
2219-- $setup
2320-- >>> :set -XOverloadedStrings
2421
22+strategy :: EncodeStrategy
23+strategy = EncodeStrategy { compressionAlgo = Linear, useHuffman = False }
24+
2525-- Set-Cookie: contains only one cookie value.
2626-- So, we don't need to split it.
27−hpackEncodeHeader :: Context -> InternalInfo -> S.Settings
27+hpackEncodeHeader :: Context -> Buffer -> BufSize
28+ -> InternalInfo -> S.Settings
2829 -> H.Status -> H.ResponseHeaders
29− -> IO Builder
30−hpackEncodeHeader ctx ii settings s h = do
31− hdr1 <- addServerAndDate h
32− let hdr2 = (":status", status) : map (first foldedCase) hdr1
33− hpackEncodeRawHeaders ctx hdr2
30+ -> IO (HeaderList, Int)
31+hpackEncodeHeader Context{..} buf siz ii settings s hdr0 = do
32+ hdr1 <- addServerAndDate hdr0
33+ let hs = (":status", status) : map (first foldedCase) hdr1
34+ encodeHeaderBuffer buf siz strategy True encodeDynamicTable hs
3435 where
3536 status = B8.pack $ show $ H.statusCode s
3637 dc = dateCacher ii
37− rspidxhdr = indexResponseHeader h
38+ rspidxhdr = indexResponseHeader hdr0
3839 defServer = S.settingsServerName settings
3940 addServerAndDate = addDate dc rspidxhdr . addServer defServer rspidxhdr
4041
41−hpackEncodeCIHeaders :: Context -> [H.Header] -> IO Builder
42−hpackEncodeCIHeaders ctx = hpackEncodeRawHeaders ctx . map (first foldedCase)
43−
44−hpackEncodeRawHeaders :: Context -> [(B.ByteString, B.ByteString)] -> IO Builder
45−hpackEncodeRawHeaders Context{encodeDynamicTable} hdr = do
46− ehdrtbl <- readIORef encodeDynamicTable
47− (ehdrtbl', builder) <- encodeHeaderBuilder defaultEncodeStrategy ehdrtbl hdr
48− writeIORef encodeDynamicTable ehdrtbl'
49− return builder
42+hpackEncodeHeaderLoop :: Context -> Buffer -> BufSize -> HeaderList
43+ -> IO (HeaderList, Int)
44+hpackEncodeHeaderLoop Context{..} buf siz hs =
45+ encodeHeaderBuffer buf siz strategy False encodeDynamicTable hs
5046
5147----------------------------------------------------------------
5248
5349hpackDecodeHeader :: HeaderBlockFragment -> Context -> IO HeaderList
54−hpackDecodeHeader hdrblk Context{decodeDynamicTable} = do
55− hdrtbl <- readIORef decodeDynamicTable
56− (hdrtbl', hdr) <- decodeHeader hdrtbl hdrblk `E.onException` cleanup
57− writeIORef decodeDynamicTable hdrtbl'
58− return hdr
59− where
60− cleanup = E.throwIO $ ConnectionError CompressionError "cannot decompress the header"
50+hpackDecodeHeader hdrblk Context{..} =
51+ decodeHeader decodeDynamicTable hdrblk `E.catch` \(E.SomeException _) ->
52+ E.throwIO $ ConnectionError CompressionError "cannot decompress the header"
warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+14−27
@@ -105,9 +105,7 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
105105 connSendAll frame
106106 case lookup SettingsHeaderTableSize alist of
107107 Nothing -> return ()
108− Just siz -> do
109− dyntbl <- readIORef encodeDynamicTable
110− setLimitForEncoding siz dyntbl
108+ Just siz -> setLimitForEncoding siz encodeDynamicTable
111109 return True
112110
113111 output (ONext strm curr mtbq) off0 lim = do
@@ -195,43 +193,32 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
195193 headerContinue sid rspn endOfStream off = do
196194 let !s = rspnStatus rspn
197195 !h = rspnHeaders rspn
198− builder <- hpackEncodeHeader ctx ii settings s h
199196 let !offkv = off + frameHeaderLength
200197 let !bufkv = connWriteBuffer `plusPtr` offkv
201198 !limkv = connBufferSize - offkv
202− (kvlen, signal) <- B.runBuilder builder bufkv limkv
203− let flag0 = case signal of
204− B.Done -> setEndHeader defaultFlags
205− _ -> defaultFlags
199+ (hs,kvlen) <- hpackEncodeHeader ctx bufkv limkv ii settings s h
200+ let flag0 = case hs of
201+ [] -> setEndHeader defaultFlags
202+ _ -> defaultFlags
206203 flag = if endOfStream then setEndStream flag0 else flag0
207204 let buf = connWriteBuffer `plusPtr` off
208205 fillFrameHeader FrameHeaders kvlen sid flag buf
209− continue sid kvlen signal
206+ continue sid kvlen hs
210207
211208 bufHeaderPayload = connWriteBuffer `plusPtr` frameHeaderLength
212209 headerPayloadLim = connBufferSize - frameHeaderLength
213210
214− continue _ kvlen B.Done = return kvlen
215− continue sid kvlen (B.More _ writer) = do
211+ continue _ kvlen [] = return kvlen
212+ continue sid kvlen hs = do
216213 flushN $ kvlen + frameHeaderLength
217214 -- Now off is 0
218− (kvlen', signal') <- writer bufHeaderPayload headerPayloadLim
219− let flag = case signal' of
220− B.Done -> setEndHeader defaultFlags
221− _ -> defaultFlags
215+ (hs', kvlen') <- hpackEncodeHeaderLoop ctx bufHeaderPayload headerPayloadLim hs
216+ when (hs == hs') $ E.throwIO $ ConnectionError CompressionError "cannot compress the header"
217+ let flag = case hs' of
218+ [] -> setEndHeader defaultFlags
219+ _ -> defaultFlags
222220 fillFrameHeader FrameContinuation kvlen' sid flag connWriteBuffer
223− continue sid kvlen' signal'
224− continue sid kvlen (B.Chunk bs writer) = do
225− flushN $ kvlen + frameHeaderLength
226− -- Now off is 0
227− let (bs1,bs2) = BS.splitAt headerPayloadLim bs
228− kvlen' = BS.length bs1
229− void $ copy bufHeaderPayload bs1
230− fillFrameHeader FrameContinuation kvlen' sid defaultFlags connWriteBuffer
231− if bs2 == "" then
232− continue sid kvlen' (B.More 0 writer)
233− else
234− continue sid kvlen' (B.Chunk bs2 writer)
221+ continue sid kvlen' hs'
235222
236223 -- Re-enqueue the stream in the output queue.
237224 maybeEnqueueNext :: Stream -> Maybe (TBQueue Sequence) -> Maybe DynaNext -> IO ()
warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+5−5
@@ -24,7 +24,7 @@ import Network.Wai.Handler.Warp.Types
2424
2525import Network.HTTP2
2626import Network.HTTP2.Priority
27−import Network.HPACK
27+import Network.HPACK hiding (Buffer)
2828
2929----------------------------------------------------------------
3030
@@ -109,8 +109,8 @@ data Context = Context {
109109 , inputQ :: !(TQueue Input)
110110 , outputQ :: !(PriorityTree Output)
111111 , controlQ :: !(TQueue Control)
112− , encodeDynamicTable :: !(IORef DynamicTable)
113− , decodeDynamicTable :: !(IORef DynamicTable)
112+ , encodeDynamicTable :: !DynamicTable
113+ , decodeDynamicTable :: !DynamicTable
114114 , connectionWindow :: !(TVar WindowSize)
115115 }
116116
@@ -127,8 +127,8 @@ newContext = Context <$> newIORef defaultSettings
127127 <*> newTQueueIO
128128 <*> newPriorityTree
129129 <*> newTQueueIO
130− <*> (newDynamicTableForEncoding defaultDynamicTableSize >>= newIORef)
131− <*> (newDynamicTableForDecoding defaultDynamicTableSize >>= newIORef)
130+ <*> newDynamicTableForEncoding defaultDynamicTableSize
131+ <*> newDynamicTableForDecoding defaultDynamicTableSize 4096
132132 <*> newTVarIO defaultInitialWindowSize
133133
134134clearContext :: Context -> IO ()
warp/warp.cabal+2−2
@@ -43,7 +43,7 @@ Library
4343 , ghc-prim
4444 , http-types >= 0.8.5
4545 , iproute >= 1.3.1
46− , http2 >= 1.4 && < 1.5
46+ , http2 >= 1.5 && < 1.6
4747 , simple-sendfile >= 0.2.7 && < 0.3
4848 , unix-compat >= 0.2
4949 , wai >= 3.2 && < 3.3
@@ -163,7 +163,7 @@ Test-Suite spec
163163 , directory
164164 , process
165165 , containers
166− , http2 >= 1.4 && < 1.5
166+ , http2 >= 1.5 && < 1.6
167167 , word8
168168 , hashable
169169 , http-date