quic 0.1.7 → 0.1.8
raw patch · 17 files changed
+211/−70 lines, 17 files
Files
- ChangeLog.md +5/−0
- Network/QUIC/Connection/State.hs +13/−0
- Network/QUIC/Connection/Stream.hs +66/−18
- Network/QUIC/Connection/StreamTable.hs +16/−11
- Network/QUIC/Connection/Types.hs +17/−10
- Network/QUIC/Crypto/Nite.hs +2/−1
- Network/QUIC/Handshake.hs +2/−2
- Network/QUIC/IO.hs +25/−8
- Network/QUIC/Imports.hs +3/−2
- Network/QUIC/Receiver.hs +31/−6
- Network/QUIC/Stream.hs +1/−0
- Network/QUIC/Stream/Reass.hs +9/−6
- Network/QUIC/Types/Frame.hs +6/−0
- quic.cabal +1/−1
- test/FrameSpec.hs +2/−3
- test/TransportError.hs +10/−0
- util/ClientX.hs +2/−2
ChangeLog.md view
@@ -1,3 +1,8 @@+## 0.1.8++- Announcing MaxStreams properly.+- Terminating a connection if the peer violates flow controls.+ ## 0.1.7 - Using System.Timeout.timeout.
Network/QUIC/Connection/State.hs view
@@ -19,6 +19,7 @@ , addRxMaxData , getRxMaxData , getRxDataWindow+ , checkRxMaxData , addTxBytes , getTxBytes , addRxBytes@@ -128,6 +129,18 @@ getRxDataWindow :: Connection -> IO Int getRxDataWindow Connection{..} = flowWindow <$> readIORef flowRx++----------------------------------------------------------------++checkRxMaxData :: Connection -> Int -> IO Bool+checkRxMaxData Connection{..} len = do+ received <- readIORef flowBytesRx+ maxData <- flowMaxData <$> readIORef flowRx+ if received + len < maxData then do+ modifyIORef' flowBytesRx (+ len)+ return True+ else+ return False ----------------------------------------------------------------
Network/QUIC/Connection/Stream.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BinaryLiterals #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -5,16 +6,20 @@ getMyStreamId , waitMyNewStreamId , waitMyNewUniStreamId- , setMyMaxStreams- , setMyUniMaxStreams- , getPeerMaxStreams- , setPeerMaxStreams+ , setTxMaxStreams+ , setTxUniMaxStreams+ , checkRxMaxStreams+ , updatePeerStreamId+ , checkStreamIdRoom ) where import UnliftIO.STM +import Network.QUIC.Connection.Misc import Network.QUIC.Connection.Types+import Network.QUIC.Connector import Network.QUIC.Imports+import Network.QUIC.Parameters import Network.QUIC.Types getMyStreamId :: Connection -> IO Int@@ -31,27 +36,70 @@ get :: TVar Concurrency -> IO Int get tvar = atomically $ do conc@Concurrency{..} <- readTVar tvar- checkSTM (currentStream < maxStreams * 4 + streamType)+ let streamType = currentStream .&. 0b11+ StreamIdBase base = maxStreams+ checkSTM (currentStream < base * 4 + streamType) let currentStream' = currentStream + 4 writeTVar tvar conc { currentStream = currentStream' } return currentStream -setMyMaxStreams :: Connection -> Int -> IO ()-setMyMaxStreams Connection{..} = set myStreamId+-- From "Peer", but set it to "My".+-- So, using "Tx".+setTxMaxStreams :: Connection -> Int -> IO ()+setTxMaxStreams Connection{..} = set myStreamId -setMyUniMaxStreams :: Connection -> Int -> IO ()-setMyUniMaxStreams Connection{..} = set myUniStreamId+setTxUniMaxStreams :: Connection -> Int -> IO ()+setTxUniMaxStreams Connection{..} = set myUniStreamId set :: TVar Concurrency -> Int -> IO ()-set tvar mx = atomically $ modifyTVar tvar $ \c -> c { maxStreams = mx }+set tvar mx = atomically $ modifyTVar tvar $ \c -> c { maxStreams = StreamIdBase mx } -setPeerMaxStreams :: Connection -> Int -> IO ()-setPeerMaxStreams Connection{..} n =- atomicModifyIORef'' peerStreamId $ \c -> c { maxStreams = n }+updatePeerStreamId :: Connection -> StreamId -> IO ()+updatePeerStreamId conn sid = do+ when ((isClient conn && isServerInitiatedBidirectional sid)+ || (isServer conn && isClientInitiatedBidirectional sid)) $ do+ atomicModifyIORef'' (peerStreamId conn) check+ when ((isClient conn && isServerInitiatedUnidirectional sid)+ || (isServer conn && isClientInitiatedUnidirectional sid)) $ do+ atomicModifyIORef'' (peerUniStreamId conn) check+ where+ check conc@Concurrency{..}+ | currentStream < sid = conc { currentStream = sid }+ | otherwise = conc -getPeerMaxStreams :: Connection -> IO Int-getPeerMaxStreams Connection{..} = atomicModifyIORef' peerStreamId inc+checkRxMaxStreams :: Connection -> StreamId -> IO Bool+checkRxMaxStreams conn@Connection{..} sid = do+ Concurrency{..} <- if isClient conn then readForClient else readForServer+ let StreamIdBase base = maxStreams+ ok = sid < base * 4 + streamType+ return ok where- inc c = (c { maxStreams = next}, next)- where- next = maxStreams c + 1+ streamType = sid .&. 0b11+ readForClient = case streamType of+ 0 -> readTVarIO myStreamId+ 1 -> readIORef peerStreamId+ 2 -> readTVarIO myUniStreamId+ 3 -> readIORef peerUniStreamId+ _ -> error "never reach"+ readForServer = case streamType of+ 0 -> readIORef peerStreamId+ 1 -> readTVarIO myStreamId+ 2 -> readIORef peerUniStreamId+ 3 -> readTVarIO myUniStreamId+ _ -> error "never reach"++checkStreamIdRoom :: Connection -> Direction -> IO (Maybe Int)+checkStreamIdRoom conn dir = do+ let ref | dir == Bidirectional = peerStreamId conn+ | otherwise = peerUniStreamId conn+ atomicModifyIORef' ref check+ where+ check conc@Concurrency{..} =+ let StreamIdBase base = maxStreams+ initialStreams = initialMaxStreamsBidi $ getMyParameters conn+ cbase = currentStream !>>. 2+ in if (base - cbase < (initialStreams !>>. 3)) then+ let base' = base + initialStreams+ in (conc { maxStreams = StreamIdBase base' }, Just base')+ else+ (conc, Nothing)
Network/QUIC/Connection/StreamTable.hs view
@@ -32,12 +32,16 @@ addStream :: Connection -> StreamId -> IO Stream addStream conn@Connection{..} sid = do strm <- newStream conn sid- peerParams <- getPeerParameters conn- let txMaxStreamData | isClient conn = clientInitial sid peerParams- | otherwise = serverInitial sid peerParams- setTxMaxStreamData strm txMaxStreamData- let rxMaxStreamData = initialRxMaxStreamData conn sid- setRxMaxStreamData strm rxMaxStreamData+ if isClient conn then do+ let clientParams = getMyParameters conn+ setRxMaxStreamData strm $ clientInitial sid clientParams+ serverParams <- getPeerParameters conn+ setTxMaxStreamData strm $ serverInitial sid serverParams+ else do+ let serverParams = getMyParameters conn+ setRxMaxStreamData strm $ serverInitial sid serverParams+ clientParams <- getPeerParameters conn+ setTxMaxStreamData strm $ clientInitial sid clientParams atomicModifyIORef'' streamTable $ insertStream sid strm return strm @@ -54,15 +58,16 @@ clientInitial :: StreamId -> Parameters -> Int clientInitial sid params- | isClientInitiatedBidirectional sid = initialMaxStreamDataBidiRemote params- | isServerInitiatedBidirectional sid = initialMaxStreamDataBidiLocal params- -- intentionally not using isClientInitiatedUnidirectional+ | isClientInitiatedBidirectional sid = initialMaxStreamDataBidiLocal params+ | isServerInitiatedBidirectional sid = initialMaxStreamDataBidiRemote params+ -- intentionally not using isServerInitiatedUnidirectional | otherwise = initialMaxStreamDataUni params serverInitial :: StreamId -> Parameters -> Int serverInitial sid params- | isServerInitiatedBidirectional sid = initialMaxStreamDataBidiRemote params- | isClientInitiatedBidirectional sid = initialMaxStreamDataBidiLocal params+ | isServerInitiatedBidirectional sid = initialMaxStreamDataBidiLocal params+ | isClientInitiatedBidirectional sid = initialMaxStreamDataBidiRemote params+ -- intentionally not using isClientInitiatedUnidirectional | otherwise = initialMaxStreamDataUni params ----------------------------------------------------------------
Network/QUIC/Connection/Types.hs view
@@ -151,17 +151,19 @@ ---------------------------------------------------------------- +newtype StreamIdBase = StreamIdBase { fromStreamIdBase :: Int }+ deriving (Eq, Show)+ data Concurrency = Concurrency {- currentStream :: Int- , streamType :: Int- , maxStreams :: Int+ currentStream :: StreamId+ , maxStreams :: StreamIdBase } newConcurrency :: Role -> Direction -> Int -> Concurrency-newConcurrency rl dir n = Concurrency typ typ n+newConcurrency rl dir n = Concurrency ini $ StreamIdBase n where bidi = dir == Bidirectional- typ | rl == Client = if bidi then 0 else 2+ ini | rl == Client = if bidi then 0 else 2 | otherwise = if bidi then 1 else 3 ----------------------------------------------------------------@@ -206,15 +208,17 @@ -- State , peerPacketNumber :: IORef PacketNumber -- for RTT1 , streamTable :: IORef StreamTable- , myStreamId :: TVar Concurrency- , myUniStreamId :: TVar Concurrency- , peerStreamId :: IORef Concurrency+ , myStreamId :: TVar Concurrency -- C:0 S:1+ , myUniStreamId :: TVar Concurrency -- C:2 S:3+ , peerStreamId :: IORef Concurrency -- C:1 S:0+ , peerUniStreamId :: IORef Concurrency -- C:3 S:2 , flowTx :: TVar Flow , flowRx :: IORef Flow+ , flowBytesRx :: IORef Int , migrationState :: TVar MigrationState , minIdleTimeout :: IORef Microseconds- , bytesTx :: TVar Int- , bytesRx :: TVar Int+ , bytesTx :: TVar Int -- TVar for anti amplification+ , bytesRx :: TVar Int -- TVar for anti amplification , addressValidated :: TVar Bool -- TLS , pendingQ :: Array EncryptionLevel (TVar [ReceivedPacket])@@ -302,8 +306,10 @@ <*> newTVarIO (newConcurrency rl Bidirectional 0) <*> newTVarIO (newConcurrency rl Unidirectional 0) <*> newIORef peerConcurrency+ <*> newIORef peerUniConcurrency <*> newTVarIO defaultFlow <*> newIORef defaultFlow { flowMaxData = initialMaxData myparams }+ <*> newIORef 0 <*> newTVarIO NonMigration <*> newIORef (milliToMicro $ maxIdleTimeout myparams) <*> newTVarIO 0@@ -336,6 +342,7 @@ peer | isclient = Server | otherwise = Client peerConcurrency = newConcurrency peer Bidirectional (initialMaxStreamsBidi myparams)+ peerUniConcurrency = newConcurrency peer Unidirectional (initialMaxStreamsUni myparams) defaultTrafficSecrets :: (ClientTrafficSecret a, ServerTrafficSecret a) defaultTrafficSecrets = (ClientTrafficSecret "", ServerTrafficSecret "")
Network/QUIC/Crypto/Nite.hs view
@@ -22,6 +22,7 @@ import qualified Data.ByteString.Internal as BS import Foreign.ForeignPtr (withForeignPtr, newForeignPtr_) import Foreign.Marshal.Alloc (mallocBytes)+import Foreign.Marshal.Utils (copyBytes) import Foreign.Ptr (Ptr, plusPtr, nullPtr) import Foreign.Storable (peek, poke) import Network.TLS hiding (Version)@@ -118,7 +119,7 @@ let src0 = p0 `plusPtr` off0 let src1 = p1 `plusPtr` off1 let diff = len0 - len1- BS.memcpy dst src0 diff+ copyBytes dst src0 diff loop (dst `plusPtr` diff) (src0 `plusPtr` diff) src1 len1 where loop :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
Network/QUIC/Handshake.hs view
@@ -265,8 +265,8 @@ setTxMaxData conn $ initialMaxData params setMinIdleTimeout conn $ milliToMicro $ maxIdleTimeout params setMaxAckDaley (connLDCC conn) $ milliToMicro $ maxAckDelay params- setMyMaxStreams conn $ initialMaxStreamsBidi params- setMyUniMaxStreams conn $ initialMaxStreamsUni params+ setTxMaxStreams conn $ initialMaxStreamsBidi params+ setTxUniMaxStreams conn $ initialMaxStreamsUni params serverVersionNegotiation Nothing = return () serverVersionNegotiation (Just peerVerInfo) = do
Network/QUIC/IO.hs view
@@ -16,12 +16,14 @@ -- | Creating a bidirectional stream. stream :: Connection -> IO Stream stream conn = do+ -- FLOW CONTROL: MAX_STREAMS: send: respecting peer's limit sid <- waitMyNewStreamId conn addStream conn sid -- | Creating a unidirectional stream. unidirectionalStream :: Connection -> IO Stream unidirectionalStream conn = do+ -- FLOW CONTROL: MAX_STREAMS: send: respecting peer's limit sid <- waitMyNewUniStreamId conn addStream conn sid @@ -60,6 +62,8 @@ conn = streamConnection s flowControl dats len wait = do -- 1-RTT+ -- FLOW CONTROL: MAX_STREAM_DATA: send: respecting peer's limit+ -- FLOW CONTROL: MAX_DATA: send: respecting peer's limit eblocked <- checkBlocked s len wait case eblocked of Right n@@ -145,8 +149,21 @@ delStream conn s when ((isClient conn && isServerInitiatedBidirectional sid) || (isServer conn && isClientInitiatedBidirectional sid)) $ do- n <- getPeerMaxStreams conn- putOutput conn $ OutControl RTT1Level [MaxStreams Unidirectional n] $ return ()+ -- FLOW CONTROL: MAX_STREAMS: recv: announcing my limit properly+ checkMaxStreams conn Bidirectional+ when ((isClient conn && isServerInitiatedUnidirectional sid)+ || (isServer conn && isClientInitiatedUnidirectional sid)) $ do+ -- FLOW CONTROL: MAX_STREAMS: recv: announcing my limit properly+ checkMaxStreams conn Unidirectional+ where+ checkMaxStreams conn dir = do+ mx <- checkStreamIdRoom conn dir+ case mx of+ Nothing -> return ()+ Just nms -> do+ sendFrames conn RTT1Level [MaxStreams dir nms]+ fire conn (Microseconds 50000) $+ sendFrames conn RTT1Level [MaxStreams dir nms] -- | Accepting a stream initiated by the peer. acceptStream :: Connection -> IO Stream@@ -166,20 +183,20 @@ window <- getRxStreamWindow s let sid = streamId s initialWindow = initialRxMaxStreamData conn sid+ -- FLOW CONTROL: MAX_STREAM_DATA: recv: announcing my limit properly when (window <= (initialWindow !>>. 1)) $ do newMax <- addRxMaxStreamData s initialWindow sendFrames conn RTT1Level [MaxStreamData sid newMax]- fire conn (Microseconds 50000) $ do- newMax' <- getRxMaxStreamData s- sendFrames conn RTT1Level [MaxStreamData sid newMax']+ fire conn (Microseconds 50000) $+ sendFrames conn RTT1Level [MaxStreamData sid newMax]+ -- FLOW CONTROL: MAX_DATA: recv: announcing my limit properly cwindow <- getRxDataWindow conn let cinitialWindow = initialMaxData $ getMyParameters conn when (cwindow <= (cinitialWindow !>>. 1)) $ do newMax <- addRxMaxData conn cinitialWindow sendFrames conn RTT1Level [MaxData newMax]- fire conn (Microseconds 50000) $ do- newMax' <- getRxMaxData conn- sendFrames conn RTT1Level [MaxData newMax']+ fire conn (Microseconds 50000) $+ sendFrames conn RTT1Level [MaxData newMax] return bs -- | Closing a stream with an error code.
Network/QUIC/Imports.hs view
@@ -33,7 +33,7 @@ import Data.Array.IO import Data.Bits import Data.ByteString.Builder (Builder)-import Data.ByteString.Internal (ByteString(..), memcpy)+import Data.ByteString.Internal (ByteString(..)) import Data.ByteString.Short.Internal (ShortByteString(..)) import Data.Foldable import Data.IORef@@ -43,6 +43,7 @@ import Data.Ord import Data.Word import Foreign.ForeignPtr+import Foreign.Marshal.Utils (copyBytes) import Foreign.Ptr import Network.ByteOrder import Network.QUIC.Utils@@ -68,5 +69,5 @@ copyBS :: Buffer -> ByteString -> IO Int copyBS dst (PS fptr off len) = withForeignPtr fptr $ \src0 -> do let src = src0 `plusPtr` off- memcpy dst src len+ copyBytes dst src len return len
Network/QUIC/Receiver.hs view
@@ -248,6 +248,10 @@ closeConnection ProtocolViolation "NEW_TOKEN for server or in 1-RTT" when (isClient conn) $ setNewToken conn token processFrame conn RTT0Level (StreamF sid off (dat:_) fin) = do+ when (off == 0) $ updatePeerStreamId conn sid+ -- FLOW CONTROL: MAX_STREAMS: recv: rejecting if over my limit+ ok <- checkRxMaxStreams conn sid+ unless ok $ closeConnection StreamLimitError "stream id is too large" when (isSendOnly conn sid) $ closeConnection StreamStateError "send-only stream" mstrm <- findStream conn sid@@ -255,14 +259,28 @@ strm <- maybe (createStream conn sid) return mstrm let len = BS.length dat rx = RxStreamData dat off len fin- ok <- putRxStreamData strm rx- unless ok $ closeConnection FlowControlError "Flow control error in 0-RTT"+ fc <- putRxStreamData strm rx+ case fc of+ -- FLOW CONTROL: MAX_STREAM_DATA: recv: rejecting if over my limit+ OverLimit -> closeConnection FlowControlError "Flow control error for stream in 0-RTT"+ Duplicated -> return ()+ Reassembled -> do+ ok' <- checkRxMaxData conn len+ -- FLOW CONTROL: MAX_DATA: send: respecting peer's limit+ unless ok' $ closeConnection FlowControlError "Flow control error for connection in 0-RTT" processFrame conn RTT1Level (StreamF sid _ [""] False) = do+ -- FLOW CONTROL: MAX_STREAMS: recv: rejecting if over my limit+ ok <- checkRxMaxStreams conn sid+ unless ok $ closeConnection StreamLimitError "stream id is too large" when (isSendOnly conn sid) $ closeConnection StreamStateError "send-only stream" mstrm <- findStream conn sid guardStream conn sid mstrm processFrame conn RTT1Level (StreamF sid off (dat:_) fin) = do+ when (off == 0) $ updatePeerStreamId conn sid+ -- FLOW CONTROL: MAX_STREAMS: recv: rejecting if over my limit+ ok <- checkRxMaxStreams conn sid+ unless ok $ closeConnection StreamLimitError "stream id is too large" when (isSendOnly conn sid) $ closeConnection StreamStateError "send-only stream" mstrm <- findStream conn sid@@ -270,8 +288,15 @@ strm <- maybe (createStream conn sid) return mstrm let len = BS.length dat rx = RxStreamData dat off len fin- ok <- putRxStreamData strm rx- unless ok $ closeConnection FlowControlError "Flow control error in 1-RTT"+ fc <- putRxStreamData strm rx+ case fc of+ -- FLOW CONTROL: MAX_STREAM_DATA: recv: rejecting if over my limit+ OverLimit -> closeConnection FlowControlError "Flow control error for stream in 1-RTT"+ Duplicated -> return ()+ Reassembled -> do+ ok' <- checkRxMaxData conn len+ -- FLOW CONTROL: MAX_DATA: send: respecting peer's limit+ unless ok' $ closeConnection FlowControlError "Flow control error for connection in 1-RTT" processFrame conn lvl (MaxData n) = do when (lvl == InitialLevel || lvl == HandshakeLevel) $ closeConnection ProtocolViolation "MAX_DATA in Initial or Handshake"@@ -293,9 +318,9 @@ when (n > 2^(60 :: Int)) $ closeConnection FrameEncodingError "Too large MAX_STREAMS" if dir == Bidirectional then- setMyMaxStreams conn n+ setTxMaxStreams conn n else- setMyUniMaxStreams conn n+ setTxUniMaxStreams conn n processFrame _conn _lvl DataBlocked{} = return () processFrame _conn _lvl (StreamDataBlocked _sid _) = return () processFrame _conn lvl (StreamsBlocked _dir n) = do
Network/QUIC/Stream.hs view
@@ -33,6 +33,7 @@ -- * Reass , takeRecvStreamQwithSize , putRxStreamData+ , FlowCntl(..) , tryReassemble -- * Table , StreamTable
Network/QUIC/Stream/Reass.hs view
@@ -4,6 +4,7 @@ module Network.QUIC.Stream.Reass ( takeRecvStreamQwithSize , putRxStreamData+ , FlowCntl(..) , tryReassemble ) where @@ -87,14 +88,16 @@ ---------------------------------------------------------------- ---------------------------------------------------------------- -putRxStreamData :: Stream -> RxStreamData -> IO Bool-putRxStreamData s rx@(RxStreamData dat off _ _) = do+data FlowCntl = OverLimit | Duplicated | Reassembled++putRxStreamData :: Stream -> RxStreamData -> IO FlowCntl+putRxStreamData s rx@(RxStreamData _ off len _) = do lim <- getRxMaxStreamData s- if BS.length dat + off > lim then- return False+ if len + off > lim then+ return OverLimit else do- _ <- tryReassemble s rx put putFin- return True+ dup <- tryReassemble s rx put putFin+ return $ if dup then Duplicated else Reassembled where put "" = return () put d = putRecvStreamQ s d
Network/QUIC/Types/Frame.hs view
@@ -69,6 +69,12 @@ isServerInitiated :: StreamId -> Bool isServerInitiated sid = (0b1 .&. sid) == 1 +isBidirectional :: StreamId -> Bool+isBidirectional sid = (0b10 .&. sid) == 0++isUnidirectional :: StreamId -> Bool+isUnidirectional sid = (0b10 .&. sid) == 2+ type Delay = Milliseconds type Fin = Bool
quic.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: quic-version: 0.1.7+version: 0.1.8 license: BSD3 license-file: LICENSE maintainer: kazu@iij.ad.jp
test/FrameSpec.hs view
@@ -1,9 +1,8 @@ module FrameSpec where -import Control.Monad-import Data.ByteString.Internal (memset) import Data.Word import Foreign.Marshal.Alloc+import Foreign.Marshal.Utils (fillBytes) import Foreign.Ptr import Foreign.Storable import Test.Hspec@@ -19,7 +18,7 @@ E.bracket (mallocBytes siz) free $ \beg -> do let (+.) = plusPtr end = beg +. siz- void $ memset beg 0 $ fromIntegral siz+ fillBytes beg 0 $ fromIntegral siz countZero beg end `shouldReturn` siz countZero (beg +. 1) end `shouldReturn` (siz - 1) countZero (beg +. 2) end `shouldReturn` (siz - 2)
test/TransportError.hs view
@@ -43,6 +43,9 @@ it "MUST send FLOW_CONTROL_ERROR if a STREAM frame with a large offset is received [Transport 4.1]" $ \_ -> do let cc = addHook cc0 $ setOnPlainCreated largeOffset runCnoOp cc ms `shouldThrow` transportErrorsIn [FlowControlError]+ it "MUST send STREAM_LIMIT_ERROR if a stream ID exceeding the limit" $ \_ -> do+ let cc = addHook cc0 $ setOnPlainCreated largeStreamId+ runCnoOp cc ms `shouldThrow` transportErrorsIn [StreamLimitError] it "MUST send TRANSPORT_PARAMETER_ERROR if initial_source_connection_id is missing [Transport 7.3]" $ \_ -> do let cc = addHook cc0 $ setOnTransportParametersCreated dropInitialSourceConnectionId runCnoOp cc ms `shouldThrow` transportErrorsIn [TransportParameterError]@@ -228,6 +231,13 @@ | otherwise = plain where fake = StreamF 0 100000000 ["GET /\r\n"] True++largeStreamId :: EncryptionLevel -> Plain -> Plain+largeStreamId lvl plain+ | lvl == RTT1Level = plain { plainFrames = fake : plainFrames plain }+ | otherwise = plain+ where+ fake = StreamF 1000000000 0 ["GET /\r\n"] True unknownFrame :: EncryptionLevel -> Plain -> Plain unknownFrame lvl plain
util/ClientX.hs view
@@ -34,7 +34,7 @@ loop n = do auxDebug "GET" get- threadDelay 1000000+ threadDelay 100000 loop (n - 1) get = do s <- stream conn@@ -63,7 +63,7 @@ loop n hdrblk = do auxDebug "GET" get hdrblk- threadDelay 1000000+ threadDelay 100000 loop (n - 1) hdrblk get hdrblk = do s <- stream conn