Files
simplexmq/src/Simplex/Messaging/Transport/HTTP2.hs
T
Evgeny ffecd4a17a parameterize transport by peer type (client/server) (#1545)
* parameterize transport by peer type (client/server)

* LogDebug level when test is retried

* support "flipped" HTTP2, fix test retry to avoid retrying pending tests

* move sync to the end of the tests
2025-05-24 14:34:22 +01:00

84 lines
2.7 KiB
Haskell

{-# LANGUAGE NamedFieldPuns #-}
module Simplex.Messaging.Transport.HTTP2 where
import qualified Control.Exception as E
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.Default (def)
import Data.Maybe (fromMaybe)
import Foreign (mallocBytes)
import Network.HPACK (BufferSize)
import Network.HTTP2.Client (Config (..), defaultPositionReadMaker, freeSimpleConfig)
import qualified Network.HTTP2.Client as HC
import qualified Network.HTTP2.Server as HS
import Network.Socket (SockAddr (..))
import qualified Network.TLS as T
import qualified Network.TLS.Extra as TE
import Simplex.Messaging.Transport (TLS, Transport (cGet, cPut))
import Simplex.Messaging.Transport.Buffer
import qualified System.TimeManager as TI
defaultHTTP2BufferSize :: BufferSize
defaultHTTP2BufferSize = 32768
withHTTP2 :: BufferSize -> (Config -> IO a) -> IO () -> TLS p -> IO a
withHTTP2 sz run fin c = E.bracket (allocHTTP2Config c sz) (\cfg -> freeSimpleConfig cfg `E.finally` fin) run
allocHTTP2Config :: TLS p -> BufferSize -> IO Config
allocHTTP2Config c sz = do
buf <- mallocBytes sz
tm <- TI.initialize $ 30 * 1000000
pure
Config
{ confWriteBuffer = buf,
confBufferSize = sz,
confSendAll = cPut c,
confReadN = cGet c,
confPositionReadMaker = defaultPositionReadMaker,
confTimeoutManager = tm,
confMySockAddr = SockAddrInet 0 0,
confPeerSockAddr = SockAddrInet 0 0
}
http2TLSParams :: T.Supported
http2TLSParams =
def
{ T.supportedVersions = [T.TLS13, T.TLS12],
T.supportedCiphers = TE.ciphersuite_strong_det,
T.supportedSecureRenegotiation = False
}
data HTTP2Body = HTTP2Body
{ bodyHead :: ByteString,
bodySize :: Int,
bodyPart :: Maybe (Int -> IO ByteString),
bodyBuffer :: TBuffer
}
class HTTP2BodyChunk a where
getBodyChunk :: a -> IO ByteString
getBodySize :: a -> Maybe Int
instance HTTP2BodyChunk HC.Response where
getBodyChunk = HC.getResponseBodyChunk
{-# INLINE getBodyChunk #-}
getBodySize = HC.responseBodySize
{-# INLINE getBodySize #-}
instance HTTP2BodyChunk HS.Request where
getBodyChunk = HS.getRequestBodyChunk
{-# INLINE getBodyChunk #-}
getBodySize = HS.requestBodySize
{-# INLINE getBodySize #-}
getHTTP2Body :: HTTP2BodyChunk a => a -> Int -> IO HTTP2Body
getHTTP2Body r n = do
bodyBuffer <- newTBuffer
let getPart n' = getBuffered bodyBuffer n' Nothing $ getBodyChunk r
bodyHead <- getPart n
let bodySize = fromMaybe 0 $ getBodySize r
-- TODO check bodySize once it is set
bodyPart = if B.length bodyHead == n then Just getPart else Nothing
pure HTTP2Body {bodyHead, bodySize, bodyPart, bodyBuffer}