packages feed

warp 3.4.11 → 3.4.12

raw patch · 4 files changed

+86/−3 lines, 4 files

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # ChangeLog for warp +## 3.4.12++* Respond with `Connection: close` header if connection is to be closed after a request.+   [#958](https://github.com/yesodweb/wai/pull/958)+ ## 3.4.11  * Expose a way to access the open connection `Counter` with `makeSettingsAndCounter`,
Network/Wai/Handler/Warp/Response.hs view
@@ -120,7 +120,7 @@     -> IO Bool     -- ^ Returing True if the connection is persistent. sendResponse settings conn ii th req reqidxhdr src response = do-    hs <- addAltSvc settings <$> addServerAndDate hs0+    hs <- addConnection . addAltSvc settings <$> addServerAndDate hs0     if hasBody s         then do             -- The response to HEAD does not have body.@@ -148,6 +148,9 @@     s = responseStatus response     hs0 = sanitizeHeaders $ responseHeaders response     rspidxhdr = indexResponseHeader hs0+    addConnection hs = if (hasBody s && not ret) || (not (hasBody s) && not isPersist)+                       then (H.hConnection, "close") : hs+                       else hs     getdate = getDate ii     addServerAndDate = addDate getdate rspidxhdr . addServer defServer rspidxhdr     (isPersist, isChunked0) = infoFromRequest req reqidxhdr
+ test/ConnectionSpec.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings #-}++module ConnectionSpec (spec) where++import Network.HTTP.Types+import Network.Wai+import Network.Wai.Handler.Warp+import RunSpec (withApp, withMySocket, msWrite, msRead)+import Test.Hspec+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as S8++spec :: Spec+spec = describe "Connection header" $ do+        it "sends Connection: close when response implies close (HTTP/1.0 Keep-Alive, no Content-Length)" $ do+            let app _ f = f $ responseLBS status200 [] "foo"+            withApp defaultSettings app $ withMySocket $ \ms -> do+                -- HTTP/1.0 defaults to close. We ask for Keep-Alive.+                -- But we provide no Content-Length in response.+                -- So Warp should decide to close (because it can't keep alive without length or chunking),+                -- and MUST send "Connection: close" to inform the client.+                msWrite ms "GET / HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n"+                +                -- We expect the connection to be closed by the server, so reading a large amount +                -- should return whatever was sent and then finish.+                response <- msRead ms 4096+                +                let headers = parseHeaders response+                lookup "Connection" headers `shouldBe` Just "close"+    +        describe "HTTP/1.1 Connection: close behavior" $ do+            it "sends Connection: close for HEAD request without Content-Length" $ do+                -- Response has no Content-Length and is not chunked (HEAD implies no body).+                -- In HTTP/1.1 this requires closing the connection to delimit the response (or rather, lack of persistence info).+                let app _ f = f $ responseBuilder status200 [] "foo"+                withApp defaultSettings app $ withMySocket $ \ms -> do+                    msWrite ms "HEAD / HTTP/1.1\r\nHost: localhost\r\n\r\n"+                    response <- msRead ms 4096+                    let headers = parseHeaders response+                    lookup "Connection" headers `shouldBe` Just "close"+    +            it "sends Connection: close when request has Connection: close (200 OK)" $ do+                let app _ f = f $ responseLBS status200 [] "foo"+                withApp defaultSettings app $ withMySocket $ \ms -> do+                    msWrite ms "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"+                    response <- msRead ms 4096+                    let headers = parseHeaders response+                    lookup "Connection" headers `shouldBe` Just "close"+    +            it "sends Connection: close when request has Connection: close (204 No Content)" $ do+                let app _ f = f $ responseLBS status204 [] ""+                withApp defaultSettings app $ withMySocket $ \ms -> do+                    msWrite ms "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"+                    response <- msRead ms 4096+                    let headers = parseHeaders response+                    lookup "Connection" headers `shouldBe` Just "close"+    +            it "sends Connection: close when request has Connection: close (500 Internal Server Error)" $ do+                let app _ f = f $ responseLBS status500 [] "error"+                withApp defaultSettings app $ withMySocket $ \ms -> do+                    msWrite ms "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"+                    response <- msRead ms 4096+                    let headers = parseHeaders response+                    lookup "Connection" headers `shouldBe` Just "close"+parseHeaders :: ByteString -> [(ByteString, ByteString)]+parseHeaders bs = +    let lines = S8.lines bs+        -- Drop status line+        headerLines = takeWhile (not . S8.null . S8.filter (/= '\r')) $ drop 1 lines+        parseLine line = +            let (k, v) = S8.break (== ':') line+                v' = S8.takeWhile (/= '\r') v+            in (k, S8.dropWhile (== ' ') $ S8.drop 1 v')+    in map parseLine headerLines
warp.cabal view
@@ -1,6 +1,6 @@ cabal-version:      >=1.10 name:               warp-version:            3.4.11+version:            3.4.12 license:            MIT license-file:       LICENSE maintainer:         michael@snoyman.com@@ -114,7 +114,7 @@         stm >=2.3,         streaming-commons >=0.1.10,         text,-        time-manager >=0.2 && <0.3,+        time-manager >=0.2 && <0.4,         vault >=0.3,         wai >=3.2.4 && <3.3,         word8@@ -179,6 +179,7 @@     hs-source-dirs:     test .     other-modules:         ConduitSpec+        ConnectionSpec         ExceptionSpec         FdCacheSpec         FileSpec