@@ -1,6 +1,7 @@
11{-# LANGUAGE BangPatterns #-}
22{-# LANGUAGE OverloadedStrings #-}
33{-# LANGUAGE CPP #-}
4+{-# LANGUAGE DeriveDataTypeable #-}
45{-# OPTIONS_GHC -fno-warn-deprecations #-}
56
67module Network.Wai.Handler.Warp.Request (
@@ -8,12 +9,14 @@ module Network.Wai.Handler.Warp.Request (
89 , headerLines
910 , pauseTimeoutKey
1011 , getFileInfoKey
12+ , NoKeepAliveRequest (..)
1113 ) where
1214
1315import qualified Control.Concurrent as Conc (yield)
14−import Control.Exception (throwIO)
16+import Control.Exception (throwIO, Exception)
1517import Data.Array ((!))
1618import Data.ByteString (ByteString)
19+import Data.Typeable (Typeable)
1720import qualified Data.ByteString as S
1821import qualified Data.ByteString.Unsafe as SU
1922import qualified Data.CaseInsensitive as CI
@@ -46,7 +49,8 @@ maxTotalHeaderLength = 50 * 1024
4649
4750-- | Receiving a HTTP request from 'Connection' and parsing its header
4851-- to create 'Request'.
49−recvRequest :: Settings
52+recvRequest :: Bool -- ^ first request on this connection?
53+ -> Settings
5054 -> Connection
5155 -> InternalInfo1
5256 -> SockAddr -- ^ Peer's address.
@@ -61,8 +65,8 @@ recvRequest :: Settings
6165 -- 'IndexedHeader' of HTTP request for internal use,
6266 -- Body producing action used for flushing the request body
6367
64−recvRequest settings conn ii1 addr src = do
65− hdrlines <- headerLines src
68+recvRequest firstRequest settings conn ii1 addr src = do
69+ hdrlines <- headerLines firstRequest src
6670 (method, unparsedPath, path, query, httpversion, hdr) <- parseHeaderLines hdrlines
6771 let idxhdr = indexRequestHeader hdr
6872 expect = idxhdr ! fromEnum ReqExpect
@@ -103,13 +107,21 @@ recvRequest settings conn ii1 addr src = do
103107
104108----------------------------------------------------------------
105109
106−headerLines :: Source -> IO [ByteString]
107−headerLines src = do
110+headerLines :: Bool -> Source -> IO [ByteString]
111+headerLines firstRequest src = do
108112 bs <- readSource src
109113 if S.null bs
110− then throwIO ConnectionClosedByPeer
114+ -- When we're working on a keep-alive connection and trying to
115+ -- get the second or later request, we don't want to treat the
116+ -- lack of data as a real exception. See the http1 function in
117+ -- the Run module for more details.
118+ then if firstRequest then throwIO ConnectionClosedByPeer else throwIO NoKeepAliveRequest
111119 else push src (THStatus 0 id id) bs
112120
121+data NoKeepAliveRequest = NoKeepAliveRequest
122+ deriving (Show, Typeable)
123+instance Exception NoKeepAliveRequest
124+
113125----------------------------------------------------------------
114126
115127handleExpect :: Connection