http2-3.0.0: Network/HTTP2/Arch/Types.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.HTTP2.Arch.Types where
import Control.Concurrent
import Control.Concurrent.STM
import Control.Exception (SomeException)
import Data.ByteString.Builder (Builder)
import Data.IORef
import Data.IntMap.Strict (IntMap)
import qualified Network.HTTP.Types as H
import Imports
import Network.HPACK
import Network.HTTP2.Arch.File
import Network.HTTP2.Frame
----------------------------------------------------------------
-- | "http" or "https".
type Scheme = ByteString
-- | For so-called "Host:" header.
type Authority = ByteString
-- | Path.
type Path = ByteString
----------------------------------------------------------------
type InpBody = IO ByteString
data OutBody = OutBodyNone
-- | Streaming body takes a write action and a flush action.
| OutBodyStreaming ((Builder -> IO ()) -> IO () -> IO ())
| OutBodyBuilder Builder
| OutBodyFile FileSpec
-- | Input object
data InpObj = InpObj {
inpObjHeaders :: HeaderTable -- ^ Accessor for headers.
, inpObjBodySize :: Maybe Int -- ^ Accessor for body length specified in content-length:.
, inpObjBody :: InpBody -- ^ Accessor for body.
, inpObjTrailers :: IORef (Maybe HeaderTable) -- ^ Accessor for trailers.
}
instance Show InpObj where
show (InpObj (thl,_) _ _body _tref) = show thl
-- | Output object
data OutObj = OutObj {
outObjHeaders :: [H.Header] -- ^ Accessor for header.
, outObjBody :: OutBody -- ^ Accessor for outObj body.
, outObjTrailers :: TrailersMaker -- ^ Accessor for trailers maker.
}
instance Show OutObj where
show (OutObj hdr _ _) = show hdr
-- | 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
-- | TrailersMake to create no trailers.
defaultTrailersMaker :: TrailersMaker
defaultTrailersMaker Nothing = return $ Trailers []
defaultTrailersMaker _ = return $ NextTrailersMaker defaultTrailersMaker
-- | Either the next trailers maker or final trailers.
data NextTrailersMaker = NextTrailersMaker TrailersMaker
| Trailers [H.Header]
----------------------------------------------------------------
-- | File specification.
data FileSpec = FileSpec FilePath FileOffset ByteCount deriving (Eq, Show)
----------------------------------------------------------------
data OpenState =
JustOpened
| Continued [HeaderBlockFragment]
Int -- Total size
Int -- The number of continuation frames
Bool -- End of stream
| NoBody HeaderTable
| HasBody HeaderTable
| Body (TQueue ByteString)
(Maybe Int) -- received Content-Length
-- compared the body length for error checking
(IORef Int) -- actual body length
(IORef (Maybe HeaderTable)) -- trailers
data ClosedCode = Finished
| Killed
| Reset ErrorCodeId
| ResetByMe SomeException
deriving Show
----------------------------------------------------------------
data StreamState =
Idle
| Open OpenState
| HalfClosedRemote
| HalfClosedLocal ClosedCode
| Closed ClosedCode
| Reserved
instance Show StreamState where
show Idle = "Idle"
show Open{} = "Open"
show HalfClosedRemote = "HalfClosedRemote"
show (HalfClosedLocal e) = "HalfClosedLocal: " ++ show e
show (Closed e) = "Closed: " ++ show e
show Reserved = "Reserved"
----------------------------------------------------------------
data Stream = Stream {
streamNumber :: StreamId
, streamState :: IORef StreamState
, streamWindow :: TVar WindowSize
, streamInput :: MVar InpObj -- Client only
}
instance Show Stream where
show s = show (streamNumber s)
----------------------------------------------------------------
newtype StreamTable = StreamTable (IORef (IntMap Stream))
----------------------------------------------------------------
data Input a = Input a InpObj
data Output a = Output {
outputStream :: a
, outputObject :: OutObj
, outputType :: OutputType
, outputStrmQ :: Maybe (TBQueue StreamingChunk)
, outputSentinel :: IO ()
}
data OutputType = OObj
| OWait (IO ())
| OPush TokenHeaderList StreamId -- associated stream id from client
| ONext DynaNext TrailersMaker
----------------------------------------------------------------
type DynaNext = Buffer -> BufferSize -> WindowSize -> IO Next
type BytesFilled = Int
data Next = Next BytesFilled (Maybe DynaNext)
----------------------------------------------------------------
data Control = CFinish
| CGoaway ByteString
| CFrame ByteString
| CSettings ByteString SettingsList
| CSettings0 ByteString ByteString SettingsList
----------------------------------------------------------------
data StreamingChunk = StreamingFinished
| StreamingFlush
| StreamingBuilder Builder