warp 3.2.11.1 → 3.2.11.2
raw patch · 5 files changed
+45/−19 lines, 5 files
Files
- ChangeLog.md +5/−0
- Network/Wai/Handler/Warp/Request.hs +19/−7
- Network/Wai/Handler/Warp/Run.hs +13/−4
- test/RequestSpec.hs +7/−7
- warp.cabal +1/−1
ChangeLog.md view
@@ -1,3 +1,8 @@+## 3.2.11.2++* Don't throw exceptions when closing a keep-alive connection+ [#618](https://github.com/yesodweb/wai/issues/618)+ ## 3.2.11.1 * Move exception handling to top of thread (fixes
Network/Wai/Handler/Warp/Request.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-} {-# OPTIONS_GHC -fno-warn-deprecations #-} module Network.Wai.Handler.Warp.Request (@@ -8,12 +9,14 @@ , headerLines , pauseTimeoutKey , getFileInfoKey+ , NoKeepAliveRequest (..) ) where import qualified Control.Concurrent as Conc (yield)-import Control.Exception (throwIO)+import Control.Exception (throwIO, Exception) import Data.Array ((!)) import Data.ByteString (ByteString)+import Data.Typeable (Typeable) import qualified Data.ByteString as S import qualified Data.ByteString.Unsafe as SU import qualified Data.CaseInsensitive as CI@@ -46,7 +49,8 @@ -- | Receiving a HTTP request from 'Connection' and parsing its header -- to create 'Request'.-recvRequest :: Settings+recvRequest :: Bool -- ^ first request on this connection?+ -> Settings -> Connection -> InternalInfo1 -> SockAddr -- ^ Peer's address.@@ -61,8 +65,8 @@ -- 'IndexedHeader' of HTTP request for internal use, -- Body producing action used for flushing the request body -recvRequest settings conn ii1 addr src = do- hdrlines <- headerLines src+recvRequest firstRequest settings conn ii1 addr src = do+ hdrlines <- headerLines firstRequest src (method, unparsedPath, path, query, httpversion, hdr) <- parseHeaderLines hdrlines let idxhdr = indexRequestHeader hdr expect = idxhdr ! fromEnum ReqExpect@@ -103,12 +107,20 @@ ---------------------------------------------------------------- -headerLines :: Source -> IO [ByteString]-headerLines src = do+headerLines :: Bool -> Source -> IO [ByteString]+headerLines firstRequest src = do bs <- readSource src if S.null bs- then throwIO ConnectionClosedByPeer+ -- When we're working on a keep-alive connection and trying to+ -- get the second or later request, we don't want to treat the+ -- lack of data as a real exception. See the http1 function in+ -- the Run module for more details.+ then if firstRequest then throwIO ConnectionClosedByPeer else throwIO NoKeepAliveRequest else push src (THStatus 0 id id) bs++data NoKeepAliveRequest = NoKeepAliveRequest+ deriving (Show, Typeable)+instance Exception NoKeepAliveRequest ----------------------------------------------------------------
Network/Wai/Handler/Warp/Run.hs view
@@ -341,7 +341,7 @@ writeIORef istatus True leftoverSource src bs addr <- getProxyProtocolAddr src- http1 addr istatus src `E.catch` \e -> do+ http1 True addr istatus src `E.catch` \e -> do sendErrorResponse addr istatus e throwIO (e :: SomeException) where@@ -402,8 +402,8 @@ errorResponse e = settingsOnExceptionResponse settings e - http1 addr istatus src = do- (req', mremainingRef, idxhdr, nextBodyFlush, ii) <- recvRequest settings conn ii1 addr src+ http1 firstRequest addr istatus src = do+ (req', mremainingRef, idxhdr, nextBodyFlush, ii) <- recvRequest firstRequest settings conn ii1 addr src let req = req' { isSecure = isTransportSecure transport } keepAlive <- processRequest istatus src req mremainingRef idxhdr nextBodyFlush ii `E.catch` \e -> do@@ -412,7 +412,16 @@ settingsOnException settings (Just req) e -- Don't throw the error again to prevent calling settingsOnException twice. return False- when keepAlive $ http1 addr istatus src++ -- When doing a keep-alive connection, the other side may just+ -- close the connection. We don't want to treat that as an+ -- exceptional situation, so we pass in False to http1 (which+ -- in turn passes in False to recvRequest), indicating that+ -- this is not the first request. If, when trying to read the+ -- request headers, no data is available, recvRequest will+ -- throw a NoKeepAliveRequest exception, which we catch here+ -- and ignore. See: https://github.com/yesodweb/wai/issues/618+ when keepAlive $ http1 False addr istatus src `E.catch` \NoKeepAliveRequest -> return () processRequest istatus src req mremainingRef idxhdr nextBodyFlush ii = do -- Let the application run for as long as it wants
test/RequestSpec.hs view
@@ -63,29 +63,29 @@ describe "headerLines" $ do it "can handle a nomarl case" $ do src <- mkSourceFunc ["Status: 200\r\nContent-Type: text/plain\r\n\r\n"] >>= mkSource- x <- headerLines src+ x <- headerLines True src x `shouldBe` ["Status: 200", "Content-Type: text/plain"] it "can handle a nasty case (1)" $ do src <- mkSourceFunc ["Status: 200", "\r\nContent-Type: text/plain", "\r\n\r\n"] >>= mkSource- x <- headerLines src+ x <- headerLines True src x `shouldBe` ["Status: 200", "Content-Type: text/plain"] it "can handle a nasty case (1)" $ do src <- mkSourceFunc ["Status: 200", "\r", "\nContent-Type: text/plain", "\r", "\n\r\n"] >>= mkSource- x <- headerLines src+ x <- headerLines True src x `shouldBe` ["Status: 200", "Content-Type: text/plain"] it "can handle a nasty case (1)" $ do src <- mkSourceFunc ["Status: 200", "\r", "\n", "Content-Type: text/plain", "\r", "\n", "\r", "\n"] >>= mkSource- x <- headerLines src+ x <- headerLines True src x `shouldBe` ["Status: 200", "Content-Type: text/plain"] it "can handle an illegal case (1)" $ do src <- mkSourceFunc ["\nStatus:", "\n 200", "\nContent-Type: text/plain", "\r\n\r\n"] >>= mkSource- x <- headerLines src+ x <- headerLines True src x `shouldBe` []- y <- headerLines src+ y <- headerLines True src y `shouldBe` ["Status: 200", "Content-Type: text/plain"] where@@ -111,7 +111,7 @@ writeIORef ref z return y src' <- mkSource src- res <- headerLines src'+ res <- headerLines True src' return (res, src') consumeLen :: Int -> Source -> IO S8.ByteString
warp.cabal view
@@ -1,5 +1,5 @@ Name: warp-Version: 3.2.11.1+Version: 3.2.11.2 Synopsis: A fast, light-weight web server for WAI applications. License: MIT License-file: LICENSE