packages feed

http2 5.4.11 → 5.4.12

raw patch · 4 files changed

+64/−8 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # ChangeLog for http2 +## 5.4.12++* Close a connection's streams before waiting for its threads.+  [#232](https://github.com/kazu-yamamoto/http2/pull/232)+ ## 5.4.11  * `allocSimpleConfigWith` is `allocSimpleConfig'` with an `STM` action beside
Network/HTTP2/H2/Context.hs view
@@ -28,18 +28,22 @@  ---------------------------------------------------------------- --- | Telling a connection's threads to stop and seeing them out before the---   cleanup, which closes the streams they are still writing to.+-- | Telling a connection's threads to stop, and seeing them out before+--   returning to a caller which tears the connection down under them. --+-- The cleanup comes first: it closes the streams, which is how a thread+-- blocked on a request body is told the peer is gone.  Waiting for the+-- threads before it would be waiting for what the cleanup has to say.+-- -- The wait is capped because one of the threads waited for runs the--- application's handler: an application which swallows the asynchronous--- exception would otherwise keep this from ever returning.+-- application's handler: an application which never stops would otherwise+-- keep this from ever returning.  It is a 'E.finally' so that the threads+-- are seen out whatever the cleanup does. stopAfterAndWait     :: T.ThreadManager -> IO a -> (Maybe E.SomeException -> IO ()) -> IO a stopAfterAndWait mgr action cleanup =-    T.stopAfter mgr action $ \res -> do-        void $ timeout stopTimeout $ T.waitUntilAllGone mgr-        cleanup res+    T.stopAfter mgr action $ \res ->+        cleanup res `E.finally` void (timeout stopTimeout $ T.waitUntilAllGone mgr)  -- | How long the threads are given to end after they have been told to. --   Unwinding takes milliseconds; this is for one that does not stop.
http2.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.0 name:               http2-version:            5.4.11+version:            5.4.12 license:            BSD3 license-file:       LICENSE maintainer:         Kazu Yamamoto <kazu@iij.ad.jp>@@ -312,6 +312,7 @@         network-byte-order,         network-run >= 0.7 && <0.8,         random,+        time-manager >=0.5 && <0.6,         typed-process  test-suite spec2
test/HTTP2/ServerSpec.hs view
@@ -36,6 +36,7 @@ import System.IO import System.IO.Unsafe import System.Random+import System.ThreadManager (KilledByThreadManager (..)) import System.Timeout (timeout) import Test.Hspec @@ -138,6 +139,16 @@                 runAttack cancelInFlight                 timeout 1000000 (takeMVar doneVar) `shouldReturn` Just () +        it "tells a handler waiting on a thread of its own that the peer is gone" $ do+            -- The handler swallows the manager's kill and goes on waiting for+            -- a thread which only the request body can tell, which is what+            -- grapesy does (#231).+            doneVar <- newEmptyMVar+            withServer (runServerWaitingHandler doneVar) $ do+                threadDelay 10000+                openStreamAndDisconnect+                timeout 2000000 (takeMVar doneVar) `shouldReturn` Just True+         it "survives a padded HEADERS whose padding covers the priority fields" $             withServer runServer $ do                 threadDelay 10000@@ -783,6 +794,41 @@         threadDelay 200000         _ <- sendResponse responseHello []         putMVar doneVar ()++-- | A server whose handler leaves the work to a thread of its own and goes on+-- waiting for it when the manager kills it, as grapesy's does.  Nothing but+-- the request body tells that thread that the peer is gone.+runServerWaitingHandler :: MVar Bool -> ServerSettings -> IO ()+runServerWaitingHandler doneVar set =+    runTCPServerWithSettings set (Just host) port runHTTP2Server+  where+    runHTTP2Server s =+        E.bracket+            (allocSimpleConfig s 32768)+            freeSimpleConfig+            (\conf -> run defaultServerConfig conf waitingServer)+    waitingServer req _aux _sendResponse = do+        told <- newEmptyMVar+        let readAll = do+                bs <- getRequestBodyChunk req+                if B.null bs then return False else readAll+            wasTold :: Either E.SomeException Bool -> Bool+            wasTold = either (const True) id+        _ <- forkIO $ E.try readAll >>= putMVar told . wasTold+        takeMVarIgnoringKill told >>= putMVar doneVar++-- | Taking an 'MVar', ignoring the manager's kill as grapesy's handler does.+takeMVarIgnoringKill :: MVar a -> IO a+takeMVarIgnoringKill var =+    takeMVar var `E.catch` \(KilledByThreadManager _) -> takeMVarIgnoringKill var++-- | Open a stream the server waits for a body on, then drop the connection.+openStreamAndDisconnect :: IO ()+openStreamAndDisconnect = runTCPClient host port $ \s -> do+    sendAll s connectionPreface+    sendAll s $ encodeFrame (EncodeInfo defaultFlags 0 Nothing) $ SettingsFrame []+    sendAll s $ openStreamFrame 1+    threadDelay 100000  runFakeServer :: MVar ByteString -> ServerSettings -> IO () runFakeServer prefaceVar set = do