@@ -7,17 +7,20 @@ module Network.Wai.HTTP2
7 , Responder
7 , Responder
9 , promiseHeaders
9 , promiseHeaders
10− , writeBuilder
10+ , promoteApplication
11− , writeFilePart
11+ , responder
14import Data.ByteString (ByteString)
17import Data.ByteString (ByteString)
15−import qualified Data.ByteString.Lazy as L
17import Data.ByteString.Builder (Builder)
19import Data.ByteString.Builder (Builder)
18import qualified Network.HTTP.Types as H
20import qualified Network.HTTP.Types as H
20−import Network.Wai.Internal (FilePart, Request)
22+import Network.Wai (Application)
23+import Network.Wai.Internal (FilePart, Request, Response(..), ResponseReceived(..))
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
41−-- | Given the write function of a stream body, write the given 'Builder'.
42−writeBuilder :: (Chunk -> IO ()) -> Builder -> IO ()
43−writeBuilder = (. BuilderChunk)
45−-- | Given the write function of a stream body, write part or all of the given
47−writeFilePart :: (Chunk -> IO ()) -> FilePath -> Maybe FilePart -> IO ()
48−writeFilePart = (.: FileChunk)
49− where f .: g = curry $ f . uncurry g
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
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
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
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
82+-- | Create a response body consisting of a single builder.
83+streamBuilder :: Builder -> Body ()
84+streamBuilder builder write _ = write $ BuilderChunk builder
86+-- | Equivalent to 'Body' but only streaming 'Builder's.
88+-- @'Network.Wai.StreamingBody' ~ SimpleBody ()@.
89+type SimpleBody a = BodyOf Builder a
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
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
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