{-# LANGUAGE RankNTypes #-} module Network.HTTP.Semantics.Types ( -- * Request/response as input InpObj (..), InpBody, -- * Request/response as output OutObj (..), OutBody (..), OutBodyIface (..), -- * Trailers maker TrailersMaker, defaultTrailersMaker, NextTrailersMaker (..), -- * File spec FileOffset, ByteCount, FileSpec (..), -- * Types Scheme, Authority, Path, ) where import Control.Exception (SomeException) import Data.ByteString.Builder (Builder) import Data.IORef import Data.Int (Int64) import Network.ByteOrder import qualified Network.HTTP.Types as H import Network.HTTP.Semantics.Header import Network.HTTP.Semantics.Trailer ---------------------------------------------------------------- -- | "http" or "https". type Scheme = ByteString -- | Authority. type Authority = String -- | Path. type Path = ByteString ---------------------------------------------------------------- type InpBody = IO (ByteString, Bool) data OutBody = OutBodyNone | -- | Streaming body takes a write action and a flush action. OutBodyStreaming ((Builder -> IO ()) -> IO () -> IO ()) | -- | Generalization of 'OutBodyStreaming'. OutBodyStreamingIface (OutBodyIface -> IO ()) | OutBodyBuilder Builder | OutBodyFile FileSpec data OutBodyIface = OutBodyIface { OutBodyIface -> forall x. IO x -> IO x outBodyUnmask :: (forall x. IO x -> IO x) -- ^ Unmask exceptions in the thread spawned for the request body -- -- This is used in the client: we spawn the new thread for the request body -- with exceptions masked, and provide the body of 'OutBodyStreamingIface' -- with a callback to unmask them again (typically after installing an -- exception handler). -- -- Unmasking in the server is a no-op, as here the scope of the thread that -- is spawned for the server is the entire handler, not just the response -- streaming body. , OutBodyIface -> Builder -> IO () outBodyPush :: Builder -> IO () -- ^ Push a new chunk -- -- In @http2@, there is no direct correspondence between chunks and the -- resulting @DATA@ frames sent: the chunks are collected (written to an -- internal write buffer) until we can fill a frame. -- -- See also 'outBodyFlush'. , OutBodyIface -> Builder -> IO () outBodyPushFinal :: Builder -> IO () -- ^ Push the final chunk -- -- Using this function instead of 'outBodyPush' can be used to guarantee -- that the final HTTP2 DATA frame is marked end-of-stream; with -- 'outBodyPush' it may happen that an additional empty DATA frame is used -- for this purpose. Additionally, after calling this function, -- 'outBodyCancel' will be a no-op. , OutBodyIface -> Maybe SomeException -> IO () outBodyCancel :: Maybe SomeException -> IO () -- ^ Cancel the stream -- -- Sends a @RST_STREAM@ to the peer. If cancelling as the result of an -- exception, a 'Just' should be provided which specifies the exception -- which will be stored locally as the reason for cancelling the stream; in -- this case, the error code sent with the @RST_STREAM@ will be -- @INTERNAL_ERROR@ (see -- <https://datatracker.ietf.org/doc/html/rfc7540#section-7>). If 'Nothing' -- is given, the error code will be @CANCEL@. -- -- If there is a partially constructed @DATA@ frame at the time of -- cancellation, this frame is discarded. If this is undesirable, you should -- call 'outBodyFlush' prior to cancelling. , OutBodyIface -> IO () outBodyFlush :: IO () -- ^ Flush -- -- This can be used to emit a DATA frame with the data collected so far -- (using 'outBodyPush'), even if that DATA frame has not yet reached the -- maximum frame size. Calling 'outBodyFlush' unnecessarily can therefore -- result in excessive overhead from frame headers. -- -- If no data is available to send, this is a no-op. } -- | Input object data InpObj = InpObj { InpObj -> TokenHeaderTable inpObjHeaders :: TokenHeaderTable -- ^ Accessor for headers. , InpObj -> Maybe Int inpObjBodySize :: Maybe Int -- ^ Accessor for body length specified in content-length:. , InpObj -> InpBody inpObjBody :: InpBody -- ^ Accessor for body. , InpObj -> IORef (Maybe TokenHeaderTable) inpObjTrailers :: IORef (Maybe TokenHeaderTable) -- ^ Accessor for trailers. } instance Show InpObj where show :: InpObj -> String show (InpObj (TokenHeaderList thl, ValueTable _) Maybe Int _ InpBody _body IORef (Maybe TokenHeaderTable) _tref) = TokenHeaderList -> String forall a. Show a => a -> String show TokenHeaderList thl -- | Output object data OutObj = OutObj { OutObj -> [Header] outObjHeaders :: [H.Header] -- ^ Accessor for header. , OutObj -> OutBody outObjBody :: OutBody -- ^ Accessor for outObj body. , OutObj -> TrailersMaker outObjTrailers :: TrailersMaker -- ^ Accessor for trailers maker. } instance Show OutObj where show :: OutObj -> String show (OutObj [Header] hdr OutBody _ TrailersMaker _) = [Header] -> String forall a. Show a => a -> String show [Header] hdr ---------------------------------------------------------------- -- | Offset for file. type FileOffset = Int64 -- | How many bytes to read type ByteCount = Int64 -- | File specification. data FileSpec = FileSpec FilePath FileOffset ByteCount deriving (FileSpec -> FileSpec -> Bool (FileSpec -> FileSpec -> Bool) -> (FileSpec -> FileSpec -> Bool) -> Eq FileSpec forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: FileSpec -> FileSpec -> Bool == :: FileSpec -> FileSpec -> Bool $c/= :: FileSpec -> FileSpec -> Bool /= :: FileSpec -> FileSpec -> Bool Eq, Int -> FileSpec -> ShowS [FileSpec] -> ShowS FileSpec -> String (Int -> FileSpec -> ShowS) -> (FileSpec -> String) -> ([FileSpec] -> ShowS) -> Show FileSpec forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> FileSpec -> ShowS showsPrec :: Int -> FileSpec -> ShowS $cshow :: FileSpec -> String show :: FileSpec -> String $cshowList :: [FileSpec] -> ShowS showList :: [FileSpec] -> ShowS Show)