module Network.HTTP2.Server.API where import Data.ByteString.Builder (Builder) import Data.IORef (IORef) import qualified Network.HTTP.Types as H import qualified System.TimeManager as T import Imports import Network.HPACK import Network.HTTP2 -- | HTTP/2 server configuration. data Config = Config { confWriteBuffer :: Buffer , confBufferSize :: BufferSize , confSendAll :: ByteString -> IO () , confReadN :: Int -> IO ByteString , confPositionReadMaker :: PositionReadMaker } ---------------------------------------------------------------- -- | HTTP\/2 server takes a HTTP request, should -- generate a HTTP response and push promises, then -- should give them to the sending function. -- The sending function would throw exceptions so that -- they can be logged. type Server = Request -> Aux -> (Response -> [PushPromise] -> IO ()) -> IO () -- | HTTP request. data Request = Request { requestHeaders :: HeaderTable -- ^ Accessor for request headers. , requestBodySize :: Maybe Int -- ^ Accessor for body length specified in content-length:. , requestBody :: IO ByteString -- ^ Accessor for body. , requestTrailers_ :: IORef (Maybe HeaderTable) } -- | Additional information. data Aux = Aux { -- | Time handle for the worker processing this request and response. auxTimeHandle :: T.Handle } -- | HTTP response. data Response = Response { responseStatus :: H.Status -- ^ Accessor for response status. , responseHeaders :: H.ResponseHeaders -- ^ Accessor for response header. , responseBody :: ResponseBody -- ^ Accessor for response body. , responseTrailers :: TrailersMaker -- ^ Accessor for response trailers maker. } -- | HTTP response body. data ResponseBody = RspNoBody -- | Streaming body takes a write action and a flush action. | RspStreaming ((Builder -> IO ()) -> IO () -> IO ()) | RspBuilder Builder | RspFile FileSpec -- | Trailers maker. A chunks of the response body is passed -- with 'Just'. The maker should update internal state -- with the 'ByteString' and return the next trailers maker. -- When response body reaches its end, -- 'Nothing' is passed and the maker should generate -- trailers. An example: -- -- > {-# LANGUAGE BangPatterns #-} -- > import Data.ByteString (ByteString) -- > import qualified Data.ByteString.Char8 as C8 -- > import Crypto.Hash (Context, SHA1) -- cryptonite -- > import qualified Crypto.Hash as CH -- > -- > -- Strictness is important for Context. -- > trailersMaker :: Context SHA1 -> Maybe ByteString -> IO NextTrailersMaker -- > trailersMaker ctx Nothing = return $ Trailers [("X-SHA1", sha1)] -- > where -- > !sha1 = C8.pack $ show $ CH.hashFinalize ctx -- > trailersMaker ctx (Just bs) = return $ NextTrailersMaker $ trailersMaker ctx' -- > where -- > !ctx' = CH.hashUpdate ctx bs -- -- Usage example: -- -- > let h2rsp = responseFile ... -- > maker = trailersMaker (CH.hashInit :: Context SHA1) -- > h2rsp' = setResponseTrailersMaker h2rsp maker -- type TrailersMaker = Maybe ByteString -> IO NextTrailersMaker -- | Either the next trailers maker or final trailers. data NextTrailersMaker = NextTrailersMaker !TrailersMaker | Trailers H.ResponseHeaders -- | HTTP/2 push promise or sever push. -- Pseudo REQUEST headers in push promise is automatically generated. -- Then, a server push is sent according to 'promiseResponse'. data PushPromise = PushPromise { -- | Accessor for a URL path in a push promise (a virtual request from a server). -- E.g. \"\/style\/default.css\". promiseRequestPath :: ByteString -- | Accessor for response actually pushed from a server. , promiseResponse :: Response -- | Accessor for response weight. , promiseWeight :: Weight } ---------------------------------------------------------------- -- | File specification. data FileSpec = FileSpec FilePath FileOffset ByteCount deriving (Eq, Show) -- | Offset for file. type FileOffset = Int64 -- | How many bytes to read type ByteCount = Int64 ---------------------------------------------------------------- -- | Position read for files. type PositionRead = FileOffset -> ByteCount -> Buffer -> IO ByteCount -- | Manipulating a file resource. data Sentinel = -- | Closing a file resource. Its refresher is automatiaclly generated by -- the internal timer. Closer (IO ()) -- | Refreshing a file resource while reading. -- Closing the file must be done by its own timer or something. | Refresher (IO ()) -- | Making a position read and its closer. type PositionReadMaker = FilePath -> IO (PositionRead, Sentinel)