-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | HTTP/2 library -- -- HTTP/2 library including frames, priority queues, HPACK, client and -- server. @package http2 @version 4.2.2 module Network.HPACK.Token -- | Internal representation for header keys. data Token Token :: Int -> Bool -> Bool -> CI ByteString -> Token -- | Index for value table [tokenIx] :: Token -> Int -- | should be indexed in HPACK [shouldBeIndexed] :: Token -> Bool -- | is this a pseudo header key? [isPseudo] :: Token -> Bool -- | Case insensitive header key [tokenKey] :: Token -> CI ByteString -- | Extracting a case insensitive header key from a token. tokenCIKey :: Token -> ByteString -- | Extracting a folded header key from a token. tokenFoldedKey :: Token -> ByteString -- | Making a token from a header key. -- --
-- >>> toToken ":authority" == tokenAuthority
-- True
--
-- >>> toToken "foo"
-- Token {tokenIx = 73, shouldBeIndexed = True, isPseudo = False, tokenKey = "foo"}
--
-- >>> toToken ":bar"
-- Token {tokenIx = 73, shouldBeIndexed = True, isPseudo = True, tokenKey = ":bar"}
--
toToken :: ByteString -> Token
-- | Minimum token index.
minTokenIx :: Int
-- | Maximun token index defined in the static table.
maxStaticTokenIx :: Int
-- | Maximum token index.
maxTokenIx :: Int
-- | Token index for tokenCookie.
cookieTokenIx :: Int
-- | Is this token ix to be held in the place holder?
isMaxTokenIx :: Int -> Bool
-- | Is this token ix for Cookie?
isCookieTokenIx :: Int -> Bool
-- | Is this token ix for a header not defined in the static table?
isStaticTokenIx :: Int -> Bool
-- | Is this token for a header not defined in the static table?
isStaticToken :: Token -> Bool
tokenAuthority :: Token
tokenMethod :: Token
tokenPath :: Token
tokenScheme :: Token
tokenStatus :: Token
tokenAcceptCharset :: Token
tokenAcceptEncoding :: Token
tokenAcceptLanguage :: Token
tokenAcceptRanges :: Token
tokenAccept :: Token
tokenAccessControlAllowOrigin :: Token
tokenAge :: Token
tokenAllow :: Token
tokenAuthorization :: Token
tokenCacheControl :: Token
tokenContentDisposition :: Token
tokenContentEncoding :: Token
tokenContentLanguage :: Token
tokenContentLength :: Token
tokenContentLocation :: Token
tokenContentRange :: Token
tokenContentType :: Token
tokenCookie :: Token
tokenDate :: Token
tokenEtag :: Token
tokenExpect :: Token
tokenExpires :: Token
tokenFrom :: Token
tokenHost :: Token
tokenIfMatch :: Token
tokenIfModifiedSince :: Token
tokenIfNoneMatch :: Token
tokenIfRange :: Token
tokenIfUnmodifiedSince :: Token
tokenLastModified :: Token
tokenLink :: Token
tokenLocation :: Token
tokenMaxForwards :: Token
tokenProxyAuthenticate :: Token
tokenProxyAuthorization :: Token
tokenRange :: Token
tokenReferer :: Token
tokenRefresh :: Token
tokenRetryAfter :: Token
tokenServer :: Token
tokenSetCookie :: Token
tokenStrictTransportSecurity :: Token
tokenTransferEncoding :: Token
tokenUserAgent :: Token
tokenVary :: Token
tokenVia :: Token
tokenWwwAuthenticate :: Token
-- | A place holder to hold header keys not defined in the static table. |
-- For Warp
tokenConnection :: Token
tokenTE :: Token
tokenMax :: Token
-- | For QPACK
tokenAccessControlAllowCredentials :: Token
tokenAccessControlAllowHeaders :: Token
tokenAccessControlAllowMethods :: Token
tokenAccessControlExposeHeaders :: Token
tokenAccessControlRequestHeaders :: Token
tokenAccessControlRequestMethod :: Token
tokenAltSvc :: Token
tokenContentSecurityPolicy :: Token
tokenEarlyData :: Token
tokenExpectCt :: Token
tokenForwarded :: Token
tokenOrigin :: Token
tokenPurpose :: Token
tokenTimingAllowOrigin :: Token
tokenUpgradeInsecureRequests :: Token
tokenXContentTypeOptions :: Token
tokenXForwardedFor :: Token
tokenXFrameOptions :: Token
tokenXXssProtection :: Token
instance GHC.Show.Show Network.HPACK.Token.Token
instance GHC.Classes.Eq Network.HPACK.Token.Token
module Network.HPACK.Internal
-- | Integer encoding with a write buffer.
encodeI :: WriteBuffer -> (Word8 -> Word8) -> Int -> Int -> IO ()
-- | Encoding integer with a temporary buffer whose size is 4096. No prefix
-- is set.
--
-- -- >>> BS.unpack <$> encodeInteger 5 10 -- [10] -- -- >>> BS.unpack <$> encodeInteger 5 1337 -- [31,154,10] -- -- >>> BS.unpack <$> encodeInteger 8 42 -- [42] --encodeInteger :: Int -> Int -> IO ByteString -- | Integer decoding with a read buffer. The first argument is N of -- prefix. decodeI :: Int -> Word8 -> ReadBuffer -> IO Int -- | Integer decoding. The first argument is N of prefix. -- --
-- >>> decodeInteger 5 10 $ BS.empty -- 10 -- -- >>> decodeInteger 5 31 $ BS.pack [154,10] -- 1337 -- -- >>> decodeInteger 8 42 $ BS.empty -- 42 --decodeInteger :: Int -> Word8 -> ByteString -> IO Int -- | String encoding. The algorithm based on copy avoidance and selection -- of better result of huffman or raw. encodeS :: WriteBuffer -> Bool -> (Word8 -> Word8) -> (Word8 -> Word8) -> Int -> ByteString -> IO () -- | String encoding (7+) with a temporary buffer whose size is 4096. encodeString :: Bool -> ByteString -> IO ByteString -- | Converting to HeaderList. -- --
-- >>> defaultDynamicTableSize -- 4096 --defaultDynamicTableSize :: Int -- | Creating DynamicTable for encoding. newDynamicTableForEncoding :: Size -> IO DynamicTable -- | Creating DynamicTable for decoding. newDynamicTableForDecoding :: Size -> Size -> IO DynamicTable -- | Creating DynamicTable for encoding, performing the action and -- clearing the DynamicTable. withDynamicTableForEncoding :: Size -> (DynamicTable -> IO a) -> IO a -- | Creating DynamicTable for decoding, performing the action and -- clearing the DynamicTable. withDynamicTableForDecoding :: Size -> Size -> (DynamicTable -> IO a) -> IO a -- | When SETTINGS_HEADER_TABLE_SIZE is received from a peer, its value -- should be set by this function. setLimitForEncoding :: Size -> DynamicTable -> IO () -- | Compression algorithms for HPACK encoding. data CompressionAlgo -- | No compression Naive :: CompressionAlgo -- | Using indices in the static table only Static :: CompressionAlgo -- | Using indices Linear :: CompressionAlgo -- | Strategy for HPACK encoding. data EncodeStrategy EncodeStrategy :: CompressionAlgo -> Bool -> EncodeStrategy -- | Which compression algorithm is used. [compressionAlgo] :: EncodeStrategy -> CompressionAlgo -- | Whether or not to use Huffman encoding for strings. [useHuffman] :: EncodeStrategy -> Bool -- | Default EncodeStrategy. -- --
-- >>> defaultEncodeStrategy
-- EncodeStrategy {compressionAlgo = Linear, useHuffman = False}
--
defaultEncodeStrategy :: EncodeStrategy
-- | Errors for decoder.
data DecodeError
-- | Index is out of range
IndexOverrun :: Index -> DecodeError
-- | Eos appears in the middle of huffman string
EosInTheMiddle :: DecodeError
-- | Non-eos appears in the end of huffman string
IllegalEos :: DecodeError
-- | Eos of huffman string is more than 7 bits
TooLongEos :: DecodeError
-- | A peer set the dynamic table size less than 32
TooSmallTableSize :: DecodeError
-- | A peer tried to change the dynamic table size over the limit
TooLargeTableSize :: DecodeError
-- | Table size update at the non-beginning
IllegalTableSizeUpdate :: DecodeError
HeaderBlockTruncated :: DecodeError
IllegalHeaderName :: DecodeError
TooLargeHeader :: DecodeError
-- | Buffer overrun exception.
data BufferOverrun
-- | The buffer size is not enough
BufferOverrun :: BufferOverrun
-- | Header list.
type HeaderList = [Header]
-- | Header.
type Header = (HeaderName, HeaderValue)
-- | Header name.
type HeaderName = ByteString
-- | Header value.
type HeaderValue = ByteString
-- | TokenBased header list.
type TokenHeaderList = [TokenHeader]
-- | TokenBased header.
type TokenHeader = (Token, HeaderValue)
-- | An array to get HeaderValue quickly. getHeaderValue
-- should be used. Internally, the key is tokenIx.
type ValueTable = Array Int (Maybe HeaderValue)
-- | A pair of token list and value table.
type HeaderTable = (TokenHeaderList, ValueTable)
-- | Accessing HeaderValue with Token.
getHeaderValue :: Token -> ValueTable -> Maybe HeaderValue
-- | Converting a header list of the http-types style to
-- TokenHeaderList and ValueTable.
toHeaderTable :: [(CI HeaderName, HeaderValue)] -> IO HeaderTable
-- | Size in bytes.
type Size = Int
-- | Index for table.
type Index = Int
-- | A pointer to Word8.
type Buffer = Ptr Word8
-- | Size of a buffer.
type BufferSize = Int
-- | Retrieve the original string-like value.
original :: CI s -> s
-- | Retrieve the case folded string-like value. (Also see
-- foldCase).
foldedCase :: CI s -> s
-- | Make the given string-like value case insensitive.
mk :: FoldCase s => s -> CI s
-- | Framing in HTTP/2(https://www.rfc-editor.org/rfc/rfc9113).
module Network.HTTP2.Frame
-- | The data type for HTTP/2 frames.
data Frame
Frame :: FrameHeader -> FramePayload -> Frame
[frameHeader] :: Frame -> FrameHeader
[framePayload] :: Frame -> FramePayload
-- | The data type for HTTP/2 frame headers.
data FrameHeader
FrameHeader :: Int -> FrameFlags -> StreamId -> FrameHeader
[payloadLength] :: FrameHeader -> Int
[flags] :: FrameHeader -> FrameFlags
[streamId] :: FrameHeader -> StreamId
-- | The data type for HTTP/2 frame payloads.
data FramePayload
DataFrame :: ByteString -> FramePayload
HeadersFrame :: Maybe Priority -> HeaderBlockFragment -> FramePayload
PriorityFrame :: Priority -> FramePayload
RSTStreamFrame :: ErrorCode -> FramePayload
SettingsFrame :: SettingsList -> FramePayload
PushPromiseFrame :: StreamId -> HeaderBlockFragment -> FramePayload
PingFrame :: ByteString -> FramePayload
GoAwayFrame :: StreamId -> ErrorCode -> ByteString -> FramePayload
WindowUpdateFrame :: WindowSize -> FramePayload
ContinuationFrame :: HeaderBlockFragment -> FramePayload
UnknownFrame :: FrameType -> ByteString -> FramePayload
-- | The type for fragments of a header encoded with HPACK.
type HeaderBlockFragment = ByteString
-- | The type for padding in payloads.
type Padding = ByteString
-- | Checking if padding is defined in this frame type.
--
-- -- >>> isPaddingDefined $ DataFrame "" -- True -- -- >>> isPaddingDefined $ PingFrame "" -- False --isPaddingDefined :: FramePayload -> Bool -- | Encoding an HTTP/2 frame to ByteString. This function is not -- efficient enough for high performace program because of the -- concatenation of ByteString. -- --
-- >>> encodeFrame (encodeInfo id 1) (DataFrame "body") -- "\NUL\NUL\EOT\NUL\NUL\NUL\NUL\NUL\SOHbody" --encodeFrame :: EncodeInfo -> FramePayload -> ByteString -- | Encoding an HTTP/2 frame to [ByteString]. This is suitable for -- sendMany. encodeFrameChunks :: EncodeInfo -> FramePayload -> [ByteString] -- | Encoding an HTTP/2 frame header. The frame header must be completed. encodeFrameHeader :: FrameType -> FrameHeader -> ByteString -- | Writing an encoded HTTP/2 frame header to the buffer. The length of -- the buffer must be larger than or equal to 9 bytes. encodeFrameHeaderBuf :: FrameType -> FrameHeader -> Ptr Word8 -> IO () -- | Encoding an HTTP/2 frame payload. This returns a complete frame header -- and chunks of payload. encodeFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, [ByteString]) -- | Auxiliary information for frame encoding. data EncodeInfo EncodeInfo :: FrameFlags -> StreamId -> Maybe Padding -> EncodeInfo -- | Flags to be set in a frame header [encodeFlags] :: EncodeInfo -> FrameFlags -- | Stream id to be set in a frame header [encodeStreamId] :: EncodeInfo -> StreamId -- | Padding if any. In the case where this value is set but the priority -- flag is not set, this value gets preference over the priority flag. -- So, if this value is set, the priority flag is also set. [encodePadding] :: EncodeInfo -> Maybe Padding -- | A smart builder of EncodeInfo. -- --
-- >>> encodeInfo setAck 0
-- EncodeInfo {encodeFlags = 1, encodeStreamId = 0, encodePadding = Nothing}
--
encodeInfo :: (FrameFlags -> FrameFlags) -> Int -> EncodeInfo
-- | Decoding an HTTP/2 frame to ByteString. The second argument
-- must be include the entire of frame. So, this function is not useful
-- for real applications but useful for testing.
decodeFrame :: Settings -> ByteString -> Either FrameDecodeError Frame
-- | Decoding an HTTP/2 frame header. Must supply 9 bytes.
decodeFrameHeader :: ByteString -> (FrameType, FrameHeader)
-- | Checking a frame header and reporting an error if any.
--
-- -- >>> checkFrameHeader defaultSettings (FrameData,(FrameHeader 100 0 0)) -- Left (FrameDecodeError ProtocolError 0 "cannot used in control stream") --checkFrameHeader :: Settings -> (FrameType, FrameHeader) -> Either FrameDecodeError (FrameType, FrameHeader) data FrameDecodeError FrameDecodeError :: ErrorCode -> StreamId -> ShortByteString -> FrameDecodeError -- | Decoding an HTTP/2 frame payload. This function is considered to -- return a frame payload decoder according to a frame type. decodeFramePayload :: FrameType -> FramePayloadDecoder -- | The type for frame payload decoder. type FramePayloadDecoder = FrameHeader -> ByteString -> Either FrameDecodeError FramePayload -- | Frame payload decoder for DATA frame. decodeDataFrame :: FramePayloadDecoder -- | Frame payload decoder for HEADERS frame. decodeHeadersFrame :: FramePayloadDecoder -- | Frame payload decoder for PRIORITY frame. decodePriorityFrame :: FramePayloadDecoder -- | Frame payload decoder for RST_STREAM frame. decodeRSTStreamFrame :: FramePayloadDecoder -- | Frame payload decoder for SETTINGS frame. decodeSettingsFrame :: FramePayloadDecoder -- | Frame payload decoder for PUSH_PROMISE frame. decodePushPromiseFrame :: FramePayloadDecoder -- | Frame payload decoder for PING frame. decodePingFrame :: FramePayloadDecoder -- | Frame payload decoder for GOAWAY frame. decodeGoAwayFrame :: FramePayloadDecoder -- | Frame payload decoder for WINDOW_UPDATE frame. decodeWindowUpdateFrame :: FramePayloadDecoder -- | Frame payload decoder for CONTINUATION frame. decodeContinuationFrame :: FramePayloadDecoder -- | The type for raw frame type. newtype FrameType FrameType :: Word8 -> FrameType pattern FrameData :: FrameType pattern FrameHeaders :: FrameType pattern FramePriority :: FrameType pattern FrameRSTStream :: FrameType pattern FrameSettings :: FrameType pattern FramePushPromise :: FrameType pattern FramePing :: FrameType pattern FrameGoAway :: FrameType pattern FrameWindowUpdate :: FrameType pattern FrameContinuation :: FrameType -- | Converting FrameType to Word8. -- --
-- >>> fromFrameType FrameData -- 0 -- -- >>> fromFrameType FrameContinuation -- 9 --fromFrameType :: FrameType -> Word8 toFrameType :: Word8 -> FrameType minFrameType :: FrameType maxFrameType :: FrameType -- | Getting FrameType from FramePayload. -- --
-- >>> framePayloadToFrameType (DataFrame "body") -- FrameData --framePayloadToFrameType :: FramePayload -> FrameType -- | Type for stream priority. Deprecated in RFC 9113 but provided for -- FrameHeaders. data Priority Priority :: Bool -> StreamId -> Weight -> Priority [exclusive] :: Priority -> Bool [streamDependency] :: Priority -> StreamId [weight] :: Priority -> Weight -- | The type for weight in priority. Its values are from 1 to 256. -- Deprecated in RFC 9113. type Weight = Int -- | The type for stream identifier type StreamId = Int -- | Checking if the stream identifier for control. -- --
-- >>> isControl 0 -- True -- -- >>> isControl 1 -- False --isControl :: StreamId -> Bool -- | Checking if the stream identifier is from a client. -- --
-- >>> isClientInitiated 0 -- False -- -- >>> isClientInitiated 1 -- True --isClientInitiated :: StreamId -> Bool -- | Checking if the stream identifier is from a server. -- --
-- >>> isServerInitiated 0 -- False -- -- >>> isServerInitiated 2 -- True --isServerInitiated :: StreamId -> Bool -- | Checking if the exclusive flag is set. testExclusive :: StreamId -> Bool -- | Setting the exclusive flag. setExclusive :: StreamId -> StreamId -- | Clearing the exclusive flag. clearExclusive :: StreamId -> StreamId -- | The type for flags. type FrameFlags = Word8 -- | The initial value of flags. No flags are set. -- --
-- >>> defaultFlags -- 0 --defaultFlags :: FrameFlags -- | Checking if the END_STREAM flag is set. >>> testEndStream 0x1 -- True testEndStream :: FrameFlags -> Bool -- | Checking if the ACK flag is set. >>> testAck 0x1 True testAck :: FrameFlags -> Bool -- | Checking if the END_HEADERS flag is set. -- --
-- >>> testEndHeader 0x4 -- True --testEndHeader :: FrameFlags -> Bool -- | Checking if the PADDED flag is set. -- --
-- >>> testPadded 0x8 -- True --testPadded :: FrameFlags -> Bool -- | Checking if the PRIORITY flag is set. -- --
-- >>> testPriority 0x20 -- True --testPriority :: FrameFlags -> Bool -- | Setting the END_STREAM flag. -- --
-- >>> setEndStream 0 -- 1 --setEndStream :: FrameFlags -> FrameFlags -- | Setting the ACK flag. -- --
-- >>> setAck 0 -- 1 --setAck :: FrameFlags -> FrameFlags -- | Setting the END_HEADERS flag. -- --
-- >>> setEndHeader 0 -- 4 --setEndHeader :: FrameFlags -> FrameFlags -- | Setting the PADDED flag. -- --
-- >>> setPadded 0 -- 8 --setPadded :: FrameFlags -> FrameFlags -- | Setting the PRIORITY flag. -- --
-- >>> setPriority 0 -- 32 --setPriority :: FrameFlags -> FrameFlags -- | Association list of SETTINGS. type SettingsList = [(SettingsKey, SettingsValue)] -- | The type for SETTINGS key. newtype SettingsKey SettingsKey :: Word16 -> SettingsKey pattern SettingsHeaderTableSize :: SettingsKey pattern SettingsEnablePush :: SettingsKey pattern SettingsMaxConcurrentStreams :: SettingsKey pattern SettingsInitialWindowSize :: SettingsKey pattern SettingsMaxFrameSize :: SettingsKey pattern SettingsMaxHeaderBlockSize :: SettingsKey -- | The type for raw SETTINGS value. type SettingsValue = Int fromSettingsKey :: SettingsKey -> Word16 toSettingsKey :: Word16 -> SettingsKey -- | Cooked version of settings. This is suitable to be stored in a HTTP/2 -- context. data Settings Settings :: Int -> Bool -> Maybe Int -> WindowSize -> Int -> Maybe Int -> Settings [headerTableSize] :: Settings -> Int [enablePush] :: Settings -> Bool [maxConcurrentStreams] :: Settings -> Maybe Int [initialWindowSize] :: Settings -> WindowSize [maxFrameSize] :: Settings -> Int [maxHeaderListSize] :: Settings -> Maybe Int -- | The default settings. -- --
-- >>> defaultSettings
-- Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Nothing, initialWindowSize = 65535, maxFrameSize = 16384, maxHeaderListSize = Nothing}
--
defaultSettings :: Settings
-- | Updating settings.
--
--
-- >>> updateSettings defaultSettings [(SettingsEnablePush,0),(SettingsMaxHeaderBlockSize,200)]
-- Settings {headerTableSize = 4096, enablePush = False, maxConcurrentStreams = Nothing, initialWindowSize = 65535, maxFrameSize = 16384, maxHeaderListSize = Just 200}
--
updateSettings :: Settings -> SettingsList -> Settings
-- | The default payload length of HTTP/2 payload.
--
-- -- >>> defaultPayloadLength -- 16384 --defaultPayloadLength :: Int -- | The maximum payload length of HTTP/2 payload. -- --
-- >>> maxPayloadLength -- 16777215 --maxPayloadLength :: Int -- | The type for window size. type WindowSize = Int -- | The default initial window size. -- --
-- >>> defaultWindowSize -- 65535 --defaultWindowSize :: WindowSize -- | The maximum window size. -- --
-- >>> maxWindowSize -- 2147483647 --maxWindowSize :: WindowSize -- | Checking if a window size exceeds the maximum window size. -- --
-- >>> isWindowOverflow 10 -- False -- -- >>> isWindowOverflow maxWindowSize -- False -- -- >>> isWindowOverflow (maxWindowSize + 1) -- True --isWindowOverflow :: WindowSize -> Bool -- | The type for raw error code. newtype ErrorCode ErrorCode :: Word32 -> ErrorCode -- | The type for error code. See -- https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes. pattern NoError :: ErrorCode pattern ProtocolError :: ErrorCode pattern InternalError :: ErrorCode pattern FlowControlError :: ErrorCode pattern SettingsTimeout :: ErrorCode pattern StreamClosed :: ErrorCode pattern FrameSizeError :: ErrorCode pattern RefusedStream :: ErrorCode pattern Cancel :: ErrorCode pattern CompressionError :: ErrorCode pattern ConnectError :: ErrorCode pattern EnhanceYourCalm :: ErrorCode pattern InadequateSecurity :: ErrorCode pattern HTTP11Required :: ErrorCode fromErrorCode :: ErrorCode -> Word32 toErrorCode :: Word32 -> ErrorCode -- | The preface of HTTP/2. -- --
-- >>> connectionPreface -- "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" --connectionPreface :: ByteString -- | Length of the preface. -- --
-- >>> connectionPrefaceLength -- 24 --connectionPrefaceLength :: Int -- | The length of HTTP/2 frame header. -- --
-- >>> frameHeaderLength -- 9 --frameHeaderLength :: Int -- | Default concurrency. -- --
-- >>> recommendedConcurrency -- 100 --recommendedConcurrency :: Int type ErrorCodeId = ErrorCode type SettingsKeyId = SettingsKey type FrameTypeId = FrameType module Network.HTTP2.Client.Internal -- | Request from client. newtype Request Request :: OutObj -> Request -- | Response from server. newtype Response Response :: InpObj -> Response -- | HTTP/2 client library. -- -- Example: -- --
-- {-# LANGUAGE OverloadedStrings #-}
--
-- module Main where
--
-- import Control.Concurrent.Async
-- import qualified Control.Exception as E
-- import qualified Data.ByteString.Char8 as C8
-- import Network.HTTP.Types
-- import Network.Run.TCP (runTCPClient) -- network-run
--
-- import Network.HTTP2.Client
--
-- serverName :: String
-- serverName = "127.0.0.1"
--
-- main :: IO ()
-- main = runTCPClient serverName "80" $ runHTTP2Client serverName
-- where
-- cliconf host = ClientConfig "http" (C8.pack host) 20
-- runHTTP2Client host s = E.bracket (allocSimpleConfig s 4096)
-- freeSimpleConfig
-- (\conf -> run (cliconf host) conf client)
-- client sendRequest = do
-- let req0 = requestNoBody methodGet "/" []
-- client0 = sendRequest req0 $ \rsp -> do
-- print rsp
-- getResponseBodyChunk rsp >>= C8.putStrLn
-- req1 = requestNoBody methodGet "/foo" []
-- client1 = sendRequest req1 $ \rsp -> do
-- print rsp
-- getResponseBodyChunk rsp >>= C8.putStrLn
-- ex <- E.try $ concurrently_ client0 client1
-- case ex of
-- Left e -> print (e :: HTTP2Error)
-- Right () -> putStrLn "OK"
--
module Network.HTTP2.Client
-- | Running HTTP/2 client.
run :: ClientConfig -> Config -> Client a -> IO a
-- | "http" or "https".
type Scheme = ByteString
-- | Authority.
type Authority = ByteString
-- | Client configuration
data ClientConfig
ClientConfig :: Scheme -> Authority -> Int -> ClientConfig
-- | https or http
[scheme] :: ClientConfig -> Scheme
-- | Server name
[authority] :: ClientConfig -> Authority
-- | How many pushed responses are contained in the cache
[cacheLimit] :: ClientConfig -> Int
-- | HTTP/2 configuration.
data Config
Config :: Buffer -> BufferSize -> (ByteString -> IO ()) -> (Int -> IO ByteString) -> PositionReadMaker -> Manager -> SockAddr -> SockAddr -> Config
-- | This is used only by frameSender. This MUST be freed after frameSender
-- is terminated.
[confWriteBuffer] :: Config -> Buffer
-- | The size of the write buffer. We assume that the read buffer is the
-- same size. So, this value is announced via SETTINGS_MAX_FRAME_SIZE to
-- the peer.
[confBufferSize] :: Config -> BufferSize
[confSendAll] :: Config -> ByteString -> IO ()
[confReadN] :: Config -> Int -> IO ByteString
[confPositionReadMaker] :: Config -> PositionReadMaker
[confTimeoutManager] :: Config -> Manager
-- | This is copied into Aux, if exist, on server.
[confMySockAddr] :: Config -> SockAddr
-- | This is copied into Aux, if exist, on server.
[confPeerSockAddr] :: Config -> SockAddr
-- | Making simple configuration whose IO is not efficient. A write buffer
-- is allocated internally.
allocSimpleConfig :: Socket -> BufferSize -> IO Config
-- | Deallocating the resource of the simple configuration.
freeSimpleConfig :: Config -> IO ()
-- | Client type.
type Client a = (forall b. Request -> (Response -> IO b) -> IO b) -> IO a
-- | Request from client.
data Request
-- | Creating request without body.
requestNoBody :: Method -> Path -> RequestHeaders -> Request
-- | Creating request with file.
requestFile :: Method -> Path -> RequestHeaders -> FileSpec -> Request
-- | Creating request with streaming.
requestStreaming :: Method -> Path -> RequestHeaders -> ((Builder -> IO ()) -> IO () -> IO ()) -> Request
-- | Like requestStreaming, but run the action with exceptions
-- masked
requestStreamingUnmask :: Method -> Path -> RequestHeaders -> ((forall x. IO x -> IO x) -> (Builder -> IO ()) -> IO () -> IO ()) -> Request
-- | Creating request with builder.
requestBuilder :: Method -> Path -> RequestHeaders -> Builder -> Request
-- | 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 -> NextTrailersMaker Trailers :: [Header] -> NextTrailersMaker -- | TrailersMake to create no trailers. defaultTrailersMaker :: TrailersMaker -- | Setting TrailersMaker to Response. setRequestTrailersMaker :: Request -> TrailersMaker -> Request -- | Response from server. data Response -- | Getting the status of a response. responseStatus :: Response -> Maybe Status -- | Getting the headers from a response. responseHeaders :: Response -> HeaderTable -- | Getting the body size from a response. responseBodySize :: Response -> Maybe Int -- | Reading a chunk of the response body. An empty ByteString -- returned when finished. getResponseBodyChunk :: Response -> IO ByteString -- | Reading response trailers. This function must be called after -- getResponseBodyChunk returns an empty. getResponseTrailers :: Response -> IO (Maybe HeaderTable) -- | HTTP method (flat string type). type Method = ByteString -- | Path. type Path = ByteString -- | File specification. data FileSpec FileSpec :: FilePath -> FileOffset -> ByteCount -> FileSpec -- | Offset for file. type FileOffset = Int64 -- | How many bytes to read type ByteCount = Int64 -- | The connection error or the stream error. Stream errors are treated as -- connection errors since there are no good recovery ways. -- ErrorCode in connection errors should be the highest stream -- identifier but in this implementation it identifies the stream that -- caused this error. data HTTP2Error ConnectionIsClosed :: HTTP2Error ConnectionErrorIsReceived :: ErrorCode -> StreamId -> ReasonPhrase -> HTTP2Error ConnectionErrorIsSent :: ErrorCode -> StreamId -> ReasonPhrase -> HTTP2Error StreamErrorIsReceived :: ErrorCode -> StreamId -> HTTP2Error StreamErrorIsSent :: ErrorCode -> StreamId -> ReasonPhrase -> HTTP2Error BadThingHappen :: SomeException -> HTTP2Error GoAwayIsSent :: HTTP2Error -- | The type for raw error code. newtype ErrorCode ErrorCode :: Word32 -> ErrorCode -- | The type for error code. See -- https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes. pattern NoError :: ErrorCode pattern ProtocolError :: ErrorCode pattern InternalError :: ErrorCode pattern FlowControlError :: ErrorCode pattern SettingsTimeout :: ErrorCode pattern StreamClosed :: ErrorCode pattern FrameSizeError :: ErrorCode pattern RefusedStream :: ErrorCode pattern Cancel :: ErrorCode pattern CompressionError :: ErrorCode pattern ConnectError :: ErrorCode pattern EnhanceYourCalm :: ErrorCode pattern InadequateSecurity :: ErrorCode pattern HTTP11Required :: ErrorCode -- | Naive implementation for readN. defaultReadN :: Socket -> IORef (Maybe ByteString) -> Int -> IO ByteString -- | Making a position read and its closer. type PositionReadMaker = FilePath -> IO (PositionRead, Sentinel) -- | 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 () -> Sentinel -- | Refreshing a file resource while reading. Closing the file must be -- done by its own timer or something. Refresher :: IO () -> Sentinel -- | Position read based on Handle. defaultPositionReadMaker :: PositionReadMaker module Network.HTTP2.Internal -- | 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 () -> Sentinel -- | Refreshing a file resource while reading. Closing the file must be -- done by its own timer or something. Refresher :: IO () -> Sentinel -- | Making a position read and its closer. type PositionReadMaker = FilePath -> IO (PositionRead, Sentinel) -- | Position read based on Handle. defaultPositionReadMaker :: PositionReadMaker -- | "http" or "https". type Scheme = ByteString -- | Authority. type Authority = ByteString -- | Path. type Path = ByteString -- | Input object data InpObj InpObj :: HeaderTable -> Maybe Int -> InpBody -> IORef (Maybe HeaderTable) -> InpObj -- | Accessor for headers. [inpObjHeaders] :: InpObj -> HeaderTable -- | Accessor for body length specified in content-length:. [inpObjBodySize] :: InpObj -> Maybe Int -- | Accessor for body. [inpObjBody] :: InpObj -> InpBody -- | Accessor for trailers. [inpObjTrailers] :: InpObj -> IORef (Maybe HeaderTable) type InpBody = IO ByteString -- | Output object data OutObj OutObj :: [Header] -> OutBody -> TrailersMaker -> OutObj -- | Accessor for header. [outObjHeaders] :: OutObj -> [Header] -- | Accessor for outObj body. [outObjBody] :: OutObj -> OutBody -- | Accessor for trailers maker. [outObjTrailers] :: OutObj -> TrailersMaker data OutBody OutBodyNone :: OutBody -- | Streaming body takes a write action and a flush action. OutBodyStreaming :: ((Builder -> IO ()) -> IO () -> IO ()) -> OutBody -- | Like OutBodyStreaming, but with a callback to unmask expections -- -- This is used in the client: we spawn the new thread for the request -- body with exceptions masked, and provide the body of -- OutBodyStreamingUnmask with a callback to unmask them again -- (typically after installing an exception handler). -- -- We do NOT support this in the server, as here the scope of the -- thread that is spawned for the server is the entire handler, not just -- the response streaming body. -- -- TODO: The analogous change for the server-side would be to provide a -- similar unmask callback as the first argument in the -- Server type alias. OutBodyStreamingUnmask :: ((forall x. IO x -> IO x) -> (Builder -> IO ()) -> IO () -> IO ()) -> OutBody OutBodyBuilder :: Builder -> OutBody OutBodyFile :: FileSpec -> OutBody -- | File specification. data FileSpec FileSpec :: FilePath -> FileOffset -> ByteCount -> FileSpec data Next Next :: BytesFilled -> Bool -> Maybe DynaNext -> Next type BytesFilled = Int type DynaNext = Buffer -> BufferSize -> WindowSize -> IO Next data StreamingChunk StreamingFinished :: IO () -> StreamingChunk StreamingFlush :: StreamingChunk StreamingBuilder :: Builder -> StreamingChunk fillBuilderBodyGetNext :: Builder -> DynaNext fillFileBodyGetNext :: PositionRead -> FileOffset -> ByteCount -> IO () -> DynaNext fillStreamBodyGetNext :: IO (Maybe StreamingChunk) -> DynaNext -- | 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 -- | Either the next trailers maker or final trailers. data NextTrailersMaker NextTrailersMaker :: TrailersMaker -> NextTrailersMaker Trailers :: [Header] -> NextTrailersMaker -- | Running trailers-maker. -- --
-- bufferIO buf siz $ \bs -> tlrmkr (Just bs) --runTrailersMaker :: TrailersMaker -> Buffer -> Int -> IO NextTrailersMaker -- | Manager to manage the thread and the timer. data Manager -- | Action to be spawned by the manager. type Action = IO () -- | Starting a thread manager. Its action is initially set to 'return ()' -- and should be set by setAction. This allows that the action can -- include the manager itself. start :: Manager -> IO Manager -- | Setting the action to be spawned. setAction :: Manager -> Action -> IO () -- | Stopping the manager. stopAfter :: Manager -> IO a -> (Either SomeException a -> IO b) -> IO b -- | Spawning the action. spawnAction :: Manager -> IO () -- | Fork managed thread -- -- This guarantees that the thread ID is added to the manager's queue -- before the thread starts, and is removed again when the thread -- terminates (normally or abnormally). forkManaged :: Manager -> IO () -> IO () -- | Like forkManaged, but run action with exceptions masked forkManagedUnmask :: Manager -> ((forall x. IO x -> IO x) -> IO ()) -> IO () -- | Killing the IO action of the second argument on timeout. timeoutKillThread :: Manager -> (Handle -> IO a) -> IO a -- | Registering closer for a resource and returning a timer refresher. timeoutClose :: Manager -> IO () -> IO (IO ()) data KilledByHttp2ThreadManager KilledByHttp2ThreadManager :: Maybe SomeException -> KilledByHttp2ThreadManager incCounter :: Manager -> IO () decCounter :: Manager -> IO () waitCounter0 :: Manager -> IO () module Network.HTTP2.Server.Internal -- | Request from client. newtype Request Request :: InpObj -> Request -- | Response from server. newtype Response Response :: OutObj -> Response -- | Additional information. data Aux Aux :: Handle -> SockAddr -> SockAddr -> Aux -- | Time handle for the worker processing this request and response. [auxTimeHandle] :: Aux -> Handle -- | Local socket address copied from Config. [auxMySockAddr] :: Aux -> SockAddr -- | Remove socket address copied from Config. [auxPeerSockAddr] :: Aux -> SockAddr -- | HTTP/2 server library. -- -- Example: -- --
-- {-# LANGUAGE OverloadedStrings #-}
-- module Main (main) where
--
-- import qualified Control.Exception as E
-- import Data.ByteString.Builder (byteString)
-- import Network.HTTP.Types (ok200)
-- import Network.Run.TCP (runTCPServer) -- network-run
--
-- import Network.HTTP2.Server
--
-- main :: IO ()
-- main = runTCPServer Nothing "80" runHTTP2Server
-- where
-- runHTTP2Server s = E.bracket (allocSimpleConfig s 4096)
-- freeSimpleConfig
-- (\config -> run config server)
-- server _req _aux sendResponse = sendResponse response []
-- where
-- response = responseBuilder ok200 header body
-- header = [("Content-Type", "text/plain")]
-- body = byteString "Hello, world!\n"
--
module Network.HTTP2.Server
-- | Running HTTP/2 server.
run :: Config -> Server -> IO ()
-- | HTTP/2 configuration.
data Config
Config :: Buffer -> BufferSize -> (ByteString -> IO ()) -> (Int -> IO ByteString) -> PositionReadMaker -> Manager -> SockAddr -> SockAddr -> Config
-- | This is used only by frameSender. This MUST be freed after frameSender
-- is terminated.
[confWriteBuffer] :: Config -> Buffer
-- | The size of the write buffer. We assume that the read buffer is the
-- same size. So, this value is announced via SETTINGS_MAX_FRAME_SIZE to
-- the peer.
[confBufferSize] :: Config -> BufferSize
[confSendAll] :: Config -> ByteString -> IO ()
[confReadN] :: Config -> Int -> IO ByteString
[confPositionReadMaker] :: Config -> PositionReadMaker
[confTimeoutManager] :: Config -> Manager
-- | This is copied into Aux, if exist, on server.
[confMySockAddr] :: Config -> SockAddr
-- | This is copied into Aux, if exist, on server.
[confPeerSockAddr] :: Config -> SockAddr
-- | Making simple configuration whose IO is not efficient. A write buffer
-- is allocated internally.
allocSimpleConfig :: Socket -> BufferSize -> IO Config
-- | Deallocating the resource of the simple configuration.
freeSimpleConfig :: Config -> IO ()
-- | Server type. 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 ()
-- | Request from client.
data Request
-- | Getting the method from a request.
requestMethod :: Request -> Maybe Method
-- | Getting the path from a request.
requestPath :: Request -> Maybe Path
-- | Getting the authority from a request.
requestAuthority :: Request -> Maybe Authority
-- | Getting the scheme from a request.
requestScheme :: Request -> Maybe Scheme
-- | Getting the headers from a request.
requestHeaders :: Request -> HeaderTable
-- | Getting the body size from a request.
requestBodySize :: Request -> Maybe Int
-- | Reading a chunk of the request body. An empty ByteString
-- returned when finished.
getRequestBodyChunk :: Request -> IO ByteString
-- | Reading request trailers. This function must be called after
-- getRequestBodyChunk returns an empty.
getRequestTrailers :: Request -> IO (Maybe HeaderTable)
-- | Additional information.
data Aux
-- | Time handle for the worker processing this request and response.
auxTimeHandle :: Aux -> Handle
-- | Local socket address copied from Config.
auxMySockAddr :: Aux -> SockAddr
-- | Remove socket address copied from Config.
auxPeerSockAddr :: Aux -> SockAddr
-- | Response from server.
data Response
-- | Creating response without body.
responseNoBody :: Status -> ResponseHeaders -> Response
-- | Creating response with file.
responseFile :: Status -> ResponseHeaders -> FileSpec -> Response
-- | Creating response with streaming.
responseStreaming :: Status -> ResponseHeaders -> ((Builder -> IO ()) -> IO () -> IO ()) -> Response
-- | Creating response with builder.
responseBuilder :: Status -> ResponseHeaders -> Builder -> Response
-- | Getter for response body size. This value is available for file body.
responseBodySize :: Response -> Maybe Int
-- | 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 -> NextTrailersMaker Trailers :: [Header] -> NextTrailersMaker -- | TrailersMake to create no trailers. defaultTrailersMaker :: TrailersMaker -- | Setting TrailersMaker to Response. setResponseTrailersMaker :: Response -> TrailersMaker -> Response -- | 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 -- | Creating push promise. The third argument is traditional, not used. pushPromise :: ByteString -> Response -> Weight -> PushPromise -- | Accessor for a URL path in a push promise (a virtual request from a -- server). E.g. "/style/default.css". promiseRequestPath :: PushPromise -> ByteString -- | Accessor for response actually pushed from a server. promiseResponse :: PushPromise -> Response -- | Path. type Path = ByteString -- | Authority. type Authority = ByteString -- | "http" or "https". type Scheme = ByteString -- | File specification. data FileSpec FileSpec :: FilePath -> FileOffset -> ByteCount -> FileSpec -- | Offset for file. type FileOffset = Int64 -- | How many bytes to read type ByteCount = Int64 -- | Naive implementation for readN. defaultReadN :: Socket -> IORef (Maybe ByteString) -> Int -> IO ByteString -- | Making a position read and its closer. type PositionReadMaker = FilePath -> IO (PositionRead, Sentinel) -- | 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 () -> Sentinel -- | Refreshing a file resource while reading. Closing the file must be -- done by its own timer or something. Refresher :: IO () -> Sentinel -- | Position read based on Handle. defaultPositionReadMaker :: PositionReadMaker