@@ -1,16 +1,13 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE NamedFieldPuns #-}
2+{-# LANGUAGE NamedFieldPuns, RecordWildCards #-}
4module Network.Wai.Handler.Warp.HTTP2.HPACK where
4module Network.Wai.Handler.Warp.HTTP2.HPACK where
6import Control.Arrow (first)
6import Control.Arrow (first)
7import qualified Control.Exception as E
7import qualified Control.Exception as E
8−import qualified Data.ByteString as B
9−import Data.ByteString.Builder (Builder)
10import qualified Data.ByteString.Char8 as B8
8import qualified Data.ByteString.Char8 as B8
11import Data.CaseInsensitive (foldedCase)
9import Data.CaseInsensitive (foldedCase)
12−import Data.IORef (readIORef, writeIORef)
10+import Network.HPACK hiding (Buffer)
14import qualified Network.HTTP.Types as H
11import qualified Network.HTTP.Types as H
15import Network.HTTP2
12import Network.HTTP2
16import Network.Wai.Handler.Warp.HTTP2.Types
13import Network.Wai.Handler.Warp.HTTP2.Types
@@ -22,39 +19,34 @@ import Network.Wai.Handler.Warp.Types
23-- >>> :set -XOverloadedStrings
20-- >>> :set -XOverloadedStrings
22+strategy :: EncodeStrategy
23+strategy = EncodeStrategy { compressionAlgo = Linear, useHuffman = False }
25-- Set-Cookie: contains only one cookie value.
25-- Set-Cookie: contains only one cookie value.
26-- So, we don't need to split it.
26-- So, we don't need to split it.
27+hpackEncodeHeader :: Context -> Buffer -> BufSize
27−hpackEncodeHeader :: Context -> InternalInfo -> S.Settings
28+ -> InternalInfo -> S.Settings
28 -> H.Status -> H.ResponseHeaders
29 -> H.Status -> H.ResponseHeaders
29− -> IO Builder
30+ -> IO (HeaderList, Int)
30−hpackEncodeHeader ctx ii settings s h = do
31+hpackEncodeHeader Context{..} buf siz ii settings s hdr0 = do
31− hdr1 <- addServerAndDate h
32+ hdr1 <- addServerAndDate hdr0
32− let hdr2 = (":status", status) : map (first foldedCase) hdr1
33+ let hs = (":status", status) : map (first foldedCase) hdr1
33− hpackEncodeRawHeaders ctx hdr2
34+ encodeHeaderBuffer buf siz strategy True encodeDynamicTable hs
35 status = B8.pack $ show $ H.statusCode s
36 status = B8.pack $ show $ H.statusCode s
36 dc = dateCacher ii
37 dc = dateCacher ii
37− rspidxhdr = indexResponseHeader h
38+ rspidxhdr = indexResponseHeader hdr0
38 defServer = S.settingsServerName settings
39 defServer = S.settingsServerName settings
39 addServerAndDate = addDate dc rspidxhdr . addServer defServer rspidxhdr
40 addServerAndDate = addDate dc rspidxhdr . addServer defServer rspidxhdr
41−hpackEncodeCIHeaders :: Context -> [H.Header] -> IO Builder
42+hpackEncodeHeaderLoop :: Context -> Buffer -> BufSize -> HeaderList
42−hpackEncodeCIHeaders ctx = hpackEncodeRawHeaders ctx . map (first foldedCase)
43+ -> IO (HeaderList, Int)
43−
44+hpackEncodeHeaderLoop Context{..} buf siz hs =
44−hpackEncodeRawHeaders :: Context -> [(B.ByteString, B.ByteString)] -> IO Builder
45+ encodeHeaderBuffer buf siz strategy False encodeDynamicTable hs
45−hpackEncodeRawHeaders Context{encodeDynamicTable} hdr = do
46− ehdrtbl <- readIORef encodeDynamicTable
47− (ehdrtbl', builder) <- encodeHeaderBuilder defaultEncodeStrategy ehdrtbl hdr
48− writeIORef encodeDynamicTable ehdrtbl'
51----------------------------------------------------------------
47----------------------------------------------------------------
53hpackDecodeHeader :: HeaderBlockFragment -> Context -> IO HeaderList
49hpackDecodeHeader :: HeaderBlockFragment -> Context -> IO HeaderList
54−hpackDecodeHeader hdrblk Context{decodeDynamicTable} = do
50+hpackDecodeHeader hdrblk Context{..} =
55− hdrtbl <- readIORef decodeDynamicTable
51+ decodeHeader decodeDynamicTable hdrblk `E.catch` \(E.SomeException _) ->
56− (hdrtbl', hdr) <- decodeHeader hdrtbl hdrblk `E.onException` cleanup
57− writeIORef decodeDynamicTable hdrtbl'
60− cleanup = E.throwIO $ ConnectionError CompressionError "cannot decompress the header"
52+ E.throwIO $ ConnectionError CompressionError "cannot decompress the header"