on master help sign in
Add and shuffle around HTTP/2 conveniences
7eff4c2Andrew Pritchard
wai/Network/Wai/HTTP2.hs+44−15
@@ -7,17 +7,20 @@ module Network.Wai.HTTP2
7 , Responder
7 , Responder
8 , Trailers
8 , Trailers
9 , promiseHeaders
9 , promiseHeaders
10− , writeBuilder
10+ , promoteApplication
11− , writeFilePart
11+ , responder
12+ , streamFilePart
13+ , streamBuilder
14+ , streamSimple
12 ) where
15 ) where
13
16
14import Data.ByteString (ByteString)
17import Data.ByteString (ByteString)
15−import qualified Data.ByteString.Lazy as L
16
18
17import Data.ByteString.Builder (Builder)
19import Data.ByteString.Builder (Builder)
18import qualified Network.HTTP.Types as H
20import qualified Network.HTTP.Types as H
19
21
20−import Network.Wai.Internal (FilePart, Request)
22+import Network.Wai (Application)
23+import Network.Wai.Internal (FilePart, Request, Response(..), ResponseReceived(..))
21
24
22-- | Headers sent after the end of a data stream, as defined by section 4.1.2 of
25-- | Headers sent after the end of a data stream, as defined by section 4.1.2 of
23-- the HTTP\/1.1 spec (RFC 7230), and section 8.1 of the HTTP\/2 spec.
26-- the HTTP\/1.1 spec (RFC 7230), and section 8.1 of the HTTP\/2 spec.
@@ -38,20 +41,14 @@ type HTTP2Application = Request -> PushFunc -> Responder
38-- | Part of a streaming response -- either a 'Builder' or a range of a file.
41-- | Part of a streaming response -- either a 'Builder' or a range of a file.
39data Chunk = FileChunk FilePath (Maybe FilePart) | BuilderChunk Builder
42data Chunk = FileChunk FilePath (Maybe FilePart) | BuilderChunk Builder
40
43
41−-- | Given the write function of a stream body, write the given 'Builder'.
42−writeBuilder :: (Chunk -> IO ()) -> Builder -> IO ()
43−writeBuilder = (. BuilderChunk)
44−
45−-- | Given the write function of a stream body, write part or all of the given
46−-- file.
47−writeFilePart :: (Chunk -> IO ()) -> FilePath -> Maybe FilePart -> IO ()
48−writeFilePart = (.: FileChunk)
49− where f .: g = curry $ f . uncurry g
50−
51-- | The streaming body of a response. Equivalent to
44-- | The streaming body of a response. Equivalent to
52-- 'Network.Wai.StreamingBody' except that it can also write file ranges and
45-- 'Network.Wai.StreamingBody' except that it can also write file ranges and
53-- return a result of type @a@.
46-- return a result of type @a@.
54−type Body a = (Chunk -> IO ()) -> IO () -> IO a
47+type Body a = BodyOf Chunk a
48+
49+-- | Generalization of 'Body' to arbitrary chunk types; this unifies with
50+-- 'Network.Wai.StreamingBody' with @c ~ Builder@ and @a ~ ()@.
51+type BodyOf c a = (c -> IO ()) -> IO () -> IO a
55
52
56-- | A function given to an 'HTTP2Application' used to send the response. This
53-- | A function given to an 'HTTP2Application' used to send the response. This
57-- is similar to the respond function in 'Network.Wai.Application', but the
54-- is similar to the respond function in 'Network.Wai.Application', but the
@@ -77,3 +74,35 @@ promiseHeaders p =
77 , (":authority", promisedAuthority p)
74 , (":authority", promisedAuthority p)
78 , (":scheme", promisedScheme p)
75 , (":scheme", promisedScheme p)
79 ] ++ promisedHeader p
76 ] ++ promisedHeader p
77+
78+-- | Create a response body consisting of a single range of a file.
79+streamFilePart :: FilePath -> Maybe FilePart -> Body ()
80+streamFilePart path part write _ = write $ FileChunk path part
81+
82+-- | Create a response body consisting of a single builder.
83+streamBuilder :: Builder -> Body ()
84+streamBuilder builder write _ = write $ BuilderChunk builder
85+
86+-- | Equivalent to 'Body' but only streaming 'Builder's.
87+--
88+-- @'Network.Wai.StreamingBody' ~ SimpleBody ()@.
89+type SimpleBody a = BodyOf Builder a
90+
91+-- | Create a response body of a stream of 'Builder's.
92+streamSimple :: SimpleBody a -> Body a
93+streamSimple body write flush = body (write . BuilderChunk) flush
94+
95+-- | Use a normal WAI 'Response' to send the response. Useful if you're
96+-- sharing code between HTTP\/2 applications and HTTP\/1 applications.
97+responder :: Response -> Responder
98+responder response respond = case response of
99+ (ResponseFile s h path part) -> [] <$ respond s h (streamFilePart path part)
100+ (ResponseBuilder s h b) -> [] <$ respond s h (streamBuilder b)
101+ (ResponseStream s h body) -> [] <$ respond s h (streamSimple body)
102+ (ResponseRaw _ fallback) -> responder fallback respond
103+
104+-- | Promote a normal WAI 'Application' to an 'HTTP2Application' by ignoring
105+-- the HTTP/2-specific features.
106+promoteApplication :: Application -> HTTP2Application
107+promoteApplication app req _ respond = [] <$ app req respond'
108+ where respond' r = ResponseReceived <$ responder r respond
warp/Network/Wai/Handler/Warp.hs−2
@@ -94,7 +94,6 @@ module Network.Wai.Handler.Warp (
94 , InvalidRequest (..)
94 , InvalidRequest (..)
95 -- * Utilities
95 -- * Utilities
96 , pauseTimeout
96 , pauseTimeout
97− , promoteApplication
98 -- * Internal
97 -- * Internal
99 -- | The following APIs will be removed in Warp 3.2.0. Please use ones exported from Network.Wai.Handler.Warp.Internal.
98 -- | The following APIs will be removed in Warp 3.2.0. Please use ones exported from Network.Wai.Handler.Warp.Internal.
100
99
@@ -147,7 +146,6 @@ import Network.Wai.Handler.Warp.Buffer
147import Network.Wai.Handler.Warp.Date
146import Network.Wai.Handler.Warp.Date
148import Network.Wai.Handler.Warp.FdCache
147import Network.Wai.Handler.Warp.FdCache
149import Network.Wai.Handler.Warp.Header
148import Network.Wai.Handler.Warp.Header
150−import Network.Wai.Handler.Warp.HTTP2 (promoteApplication)
151import Network.Wai.Handler.Warp.Request
149import Network.Wai.Handler.Warp.Request
152import Network.Wai.Handler.Warp.Response
150import Network.Wai.Handler.Warp.Response
153import Network.Wai.Handler.Warp.Run
151import Network.Wai.Handler.Warp.Run
warp/Network/Wai/Handler/Warp/HTTP2.hs+2−18
@@ -1,13 +1,8 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE RecordWildCards #-}
3
3
4−module Network.Wai.Handler.Warp.HTTP2
4+module Network.Wai.Handler.Warp.HTTP2 (isHTTP2, http2) where
5− ( isHTTP2
6− , http2
7− , promoteApplication
8− ) where
9
5
10−import Control.Applicative ((<$))
11import Control.Concurrent (forkIO, killThread)
6import Control.Concurrent (forkIO, killThread)
12import qualified Control.Exception as E
7import qualified Control.Exception as E
13import Control.Monad (when, unless, replicateM_)
8import Control.Monad (when, unless, replicateM_)
@@ -16,9 +11,7 @@ import Data.ByteString (ByteString)
16import Network.HTTP2
11import Network.HTTP2
17import Network.Socket (SockAddr)
12import Network.Socket (SockAddr)
18
13
19−import Network.Wai (Application, responseToStream)
20−import Network.Wai.HTTP2 (HTTP2Application, Chunk(BuilderChunk))
14+import Network.Wai.HTTP2 (HTTP2Application)
21−import Network.Wai.Internal (ResponseReceived(..))
22import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
15import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
23import Network.Wai.Handler.Warp.HTTP2.Manager
16import Network.Wai.Handler.Warp.HTTP2.Manager
24import Network.Wai.Handler.Warp.HTTP2.Receiver
17import Network.Wai.Handler.Warp.HTTP2.Receiver
@@ -73,12 +66,3 @@ goaway :: Connection -> ErrorCodeId -> ByteString -> IO ()
73goaway Connection{..} etype debugmsg = connSendAll bytestream
66goaway Connection{..} etype debugmsg = connSendAll bytestream
74 where
67 where
75 bytestream = goawayFrame 0 etype debugmsg
68 bytestream = goawayFrame 0 etype debugmsg
76−
77−-- | Promote a normal WAI 'Application' to an 'HTTP2Application' by ignoring
78−-- the HTTP/2-specific features.
79−promoteApplication :: Application -> HTTP2Application
80−promoteApplication app req _ respond = [] <$ app req respond'
81− where
82− respond' r = ResponseReceived <$ (withBody $ respond s h . convBody)
83− where (s, h, withBody) = responseToStream r
84− convBody b = \send flush -> b (send . BuilderChunk) flush
warp/Network/Wai/Handler/Warp/Run.hs+2−2
@@ -21,12 +21,12 @@ import Network (sClose, Socket)
21import Network.Socket (accept, withSocketsDo, SockAddr(SockAddrInet, SockAddrInet6))
21import Network.Socket (accept, withSocketsDo, SockAddr(SockAddrInet, SockAddrInet6))
22import qualified Network.Socket.ByteString as Sock
22import qualified Network.Socket.ByteString as Sock
23import Network.Wai
23import Network.Wai
24−import Network.Wai.HTTP2 (HTTP2Application)
24+import Network.Wai.HTTP2 (HTTP2Application, promoteApplication)
25import Network.Wai.Handler.Warp.Buffer
25import Network.Wai.Handler.Warp.Buffer
26import Network.Wai.Handler.Warp.Counter
26import Network.Wai.Handler.Warp.Counter
27import qualified Network.Wai.Handler.Warp.Date as D
27import qualified Network.Wai.Handler.Warp.Date as D
28import qualified Network.Wai.Handler.Warp.FdCache as F
28import qualified Network.Wai.Handler.Warp.FdCache as F
29−import Network.Wai.Handler.Warp.HTTP2 (http2, isHTTP2, promoteApplication)
29+import Network.Wai.Handler.Warp.HTTP2 (http2, isHTTP2)
30import Network.Wai.Handler.Warp.Header
30import Network.Wai.Handler.Warp.Header
31import Network.Wai.Handler.Warp.ReadInt
31import Network.Wai.Handler.Warp.ReadInt
32import Network.Wai.Handler.Warp.Recv
32import Network.Wai.Handler.Warp.Recv