packages feed

quic 0.3.7 → 0.3.8

raw patch · 9 files changed

+88/−3 lines, 9 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Network.QUIC: resetReceived :: Stream -> IO (Maybe ApplicationProtocolError)
+ Network.QUIC.Internal: resetReceived :: Stream -> IO (Maybe ApplicationProtocolError)
+ Network.QUIC.Internal: setResetReceived :: Stream -> ApplicationProtocolError -> IO ()

Files

ChangeLog.md view
@@ -1,5 +1,17 @@ # ChangeLog +## 0.3.8++* Tell a stream that was reset from one that ended.  After a+  RESET_STREAM, `recvStream` returns an empty ByteString, just as it does+  at the end of a stream, and nothing else said which it was.  An+  application protocol may have to know: HTTP/3's QPACK decoder has to+  send a Stream Cancellation for a request stream that was reset+  (RFC 9204 Sec 4.4.2), and a reset that lands between two frames looked+  to it exactly like the end of the request.  `resetReceived` answers the+  error code of the peer's RESET_STREAM, or `Nothing` if there was none.+  [#123](https://github.com/kazu-yamamoto/quic/pull/123)+ ## 0.3.7  * Don't open a closed stream again for a late copy of its data.  A STREAM
Network/QUIC.hs view
@@ -32,6 +32,7 @@      -- * IO     recvStream,+    resetReceived,     sendStream,     sendStreamMany,     sendDatagram,
Network/QUIC/Receiver.hs view
@@ -277,6 +277,9 @@         Nothing -> return ()         Just strm -> do             onResetStreamReceived (connHooks conn) strm aerr+            -- Before the pseudo FIN below, so that whoever reads it can+            -- tell it was not a real one.+            setResetReceived strm aerr             setTxStreamClosed strm             setRxStreamClosed strm             delStream conn strm
Network/QUIC/Stream.hs view
@@ -20,6 +20,8 @@     getRxStreamOffset,     isRxStreamClosed,     setRxStreamClosed,+    resetReceived,+    setResetReceived,     readStreamFlowTx,     addTxStreamData,     setTxMaxStreamData,
Network/QUIC/Stream/Misc.hs view
@@ -9,6 +9,8 @@     getRxStreamOffset,     isRxStreamClosed,     setRxStreamClosed,+    resetReceived,+    setResetReceived,     --     readStreamFlowTx,     addTxStreamData,@@ -25,6 +27,7 @@ import Network.QUIC.Imports import Network.QUIC.Stream.Queue import Network.QUIC.Stream.Types+import Network.QUIC.Types (ApplicationProtocolError)  ---------------------------------------------------------------- @@ -66,6 +69,19 @@     putRecvStreamQ strm ""   where     set (StreamState off _) = StreamState off True++-- | The error code of the RESET_STREAM the peer sent for this stream, if it+--   sent one.+--+-- After a RESET_STREAM, 'recvStream' returns an empty 'ByteString', just as+-- it does at the end of the stream.  This tells the two apart: HTTP/3, for+-- one, has to tell its QPACK encoder about a request whose reset it saw+-- (RFC 9204, section 4.4.2), and had no way to know that it was reset.+resetReceived :: Stream -> IO (Maybe ApplicationProtocolError)+resetReceived Stream{..} = readIORef streamResetRx++setResetReceived :: Stream -> ApplicationProtocolError -> IO ()+setResetReceived Stream{..} aerr = writeIORef streamResetRx $ Just aerr  ---------------------------------------------------------------- 
Network/QUIC/Stream/Types.hs view
@@ -41,6 +41,8 @@     , -- input stream fragments to streamQ, and how many of them       streamReass :: IORef (Int, Skew RxStreamData)     , streamSyncFinTx :: MVar ()+    , streamResetRx :: IORef (Maybe ApplicationProtocolError)+    -- ^ The error code of a RESET_STREAM from the peer     }  instance Show Stream where@@ -56,6 +58,7 @@     streamRecvQ     <- newRecvStreamQ     streamReass     <- newIORef (0, Skew.empty)     streamSyncFinTx <- newEmptyMVar+    streamResetRx   <- newIORef Nothing     return Stream{..} {- FOURMOLU_ENABLE -} 
quic.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.0 name:               quic-version:            0.3.7+version:            0.3.8 license:            BSD3 license-file:       LICENSE maintainer:         kazu@iij.ad.jp
test/Config.hs view
@@ -292,7 +292,12 @@     shouldDelay (DelayServerPacket k) fromC pn = not fromC && pn == k     shouldDelay _ _ _ = False     -- The packets that follow go ahead of the one held back.-    delayIf True send_ = void $ forkIO $ threadDelay 1000000 >> send_+    --+    -- Long enough for the data to be sent again and the stream closed before+    -- it lands, which is what the test is about, and no longer: it was a+    -- second, and a second is two and a half of these tests' worth of+    -- everything else.+    delayIf True send_ = void $ forkIO $ threadDelay delayTime >> send_     delayIf False send_ = send_  chooseALPN :: Version -> [ByteString] -> IO ByteString@@ -328,3 +333,7 @@             Just (s, d)                 | s == sid -> return $ Just d                 | otherwise -> return Nothing++-- | How long 'DelayClientPacket' and 'DelayServerPacket' hold a datagram.+delayTime :: Int+delayTime = 100000
test/IOSpec.hs view
@@ -100,6 +100,8 @@         -- number of bytes sent by the RESET_STREAM sender.         it "sends RESET_STREAM with the bytes sent as final size" $ do             withPipe (DropClientPacket []) $ testResetStreamFinalSize cc sc waitS+        it "tells a stream that was reset from one that ended" $ do+            withPipe (DropClientPacket []) $ testResetReceived cc sc waitS     describe "closed stream" $ do         it "ignores a late copy of the data it received on a stream it opened" $ do             withPipe (DelayServerPacket 300) $ testLateCopy False cc sc waitS@@ -179,7 +181,7 @@         C.run cc $ \conn -> do             exchange conn             -- The copy arrives while we wait.-            threadDelay 1500000+            threadDelay 200000             exchange conn     exchange conn = do         strm <- stream conn@@ -195,6 +197,43 @@         assertEndOfStream strm         sendStream strm (BS.replicate downLen 0)         closeStream strm++-- | After a RESET_STREAM, 'recvStream' returns "" just as at the end of the+-- stream; 'resetReceived' tells the two apart.  The client ends one stream+-- and resets another, and the server looks at both.+testResetReceived :: C.ClientConfig -> ServerConfig -> IO () -> IO ()+testResetReceived cc sc waitS = do+    resultVar <- newEmptyMVar+    E.bracket (forkIO $ server resultVar) killThread $ \_ -> client resultVar+  where+    aerr = ApplicationProtocolError 7++    client resultVar = do+        waitS+        C.run cc $ \conn -> do+            strm0 <- stream conn+            sendStream strm0 "ended"+            shutdownStream strm0+            strm1 <- stream conn+            sendStream strm1 "reset"+            -- Let the data go first.+            threadDelay 100000+            resetStream strm1 aerr+            mres <- Timeout.timeout 5000000 $ takeMVar resultVar+            mres `shouldBe` Just (Nothing, Just aerr)++    server resultVar = run sc $ \conn -> do+        strm0 <- acceptStream conn+        strm1 <- acceptStream conn+        let drain strm = do+                bs <- recvStream strm 1024+                unless (BS.null bs) $ drain strm+        drain strm0+        drain strm1+        r0 <- resetReceived strm0+        r1 <- resetReceived strm1+        putMVar resultVar (r0, r1)+        threadDelay 1000000  testRecvStreamClientStopFirst     :: C.ClientConfig -> ServerConfig -> IO () -> IO ()