@@ -9,6 +9,7 @@ module Network.Wai.Handler.Warp.Request (
9 , headerLines
9 , headerLines
10 , pauseTimeoutKey
10 , pauseTimeoutKey
11 , getFileInfoKey
11 , getFileInfoKey
12+ , getClientCertificateKey
12 , NoKeepAliveRequest (..)
13 , NoKeepAliveRequest (..)
@@ -21,6 +22,7 @@ import qualified Data.CaseInsensitive as CI
21import qualified Data.IORef as I
22import qualified Data.IORef as I
22import Data.Typeable (Typeable)
23import Data.Typeable (Typeable)
23import qualified Data.Vault.Lazy as Vault
24import qualified Data.Vault.Lazy as Vault
24import qualified Network.HTTP.Types as H
26import qualified Network.HTTP.Types as H
25import Network.Socket (SockAddr)
27import Network.Socket (SockAddr)
26import Network.Wai
28import Network.Wai
@@ -36,13 +38,7 @@ import Network.Wai.Handler.Warp.Header
36import Network.Wai.Handler.Warp.Imports hiding (readInt, lines)
38import Network.Wai.Handler.Warp.Imports hiding (readInt, lines)
37import Network.Wai.Handler.Warp.ReadInt
39import Network.Wai.Handler.Warp.ReadInt
38import Network.Wai.Handler.Warp.RequestHeader
40import Network.Wai.Handler.Warp.RequestHeader
39−import Network.Wai.Handler.Warp.Settings (Settings, settingsNoParsePath)
41+import Network.Wai.Handler.Warp.Settings (Settings, settingsNoParsePath, settingsMaxTotalHeaderLength)
41−----------------------------------------------------------------
43−-- FIXME come up with good values here
44−maxTotalHeaderLength :: Int
45−maxTotalHeaderLength = 50 * 1024
47----------------------------------------------------------------
43----------------------------------------------------------------
@@ -55,6 +51,7 @@ recvRequest :: Bool -- ^ first request on this connection?
55 -> Timeout.Handle
51 -> Timeout.Handle
56 -> SockAddr -- ^ Peer's address.
52 -> SockAddr -- ^ Peer's address.
57 -> Source -- ^ Where HTTP request comes from.
53 -> Source -- ^ Where HTTP request comes from.
58 -> IO (Request
55 -> IO (Request
59 ,Maybe (I.IORef Int)
56 ,Maybe (I.IORef Int)
60 ,IndexedHeader
57 ,IndexedHeader
@@ -64,8 +61,8 @@ recvRequest :: Bool -- ^ first request on this connection?
64 -- 'IndexedHeader' of HTTP request for internal use,
61 -- 'IndexedHeader' of HTTP request for internal use,
65 -- Body producing action used for flushing the request body
62 -- Body producing action used for flushing the request body
67−recvRequest firstRequest settings conn ii th addr src = do
64+recvRequest firstRequest settings conn ii th addr src transport = do
68− hdrlines <- headerLines firstRequest src
65+ hdrlines <- headerLines (settingsMaxTotalHeaderLength settings) firstRequest src
69 (method, unparsedPath, path, query, httpversion, hdr) <- parseHeaderLines hdrlines
66 (method, unparsedPath, path, query, httpversion, hdr) <- parseHeaderLines hdrlines
70 let idxhdr = indexRequestHeader hdr
67 let idxhdr = indexRequestHeader hdr
71 expect = idxhdr ! fromEnum ReqExpect
68 expect = idxhdr ! fromEnum ReqExpect
@@ -75,6 +72,7 @@ recvRequest firstRequest settings conn ii th addr src = do
75 rawPath = if settingsNoParsePath settings then unparsedPath else path
72 rawPath = if settingsNoParsePath settings then unparsedPath else path
76 vaultValue = Vault.insert pauseTimeoutKey (Timeout.pause th)
73 vaultValue = Vault.insert pauseTimeoutKey (Timeout.pause th)
77 $ Vault.insert getFileInfoKey (getFileInfo ii)
74 $ Vault.insert getFileInfoKey (getFileInfo ii)
75+ $ Vault.insert getClientCertificateKey (tlsClientCertificate transport)
78 Vault.empty
76 Vault.empty
79 (rbody, remainingRef, bodyLength) <- bodyAndSource src cl te
77 (rbody, remainingRef, bodyLength) <- bodyAndSource src cl te
80 -- body producing function which will produce '100-continue', if needed
78 -- body producing function which will produce '100-continue', if needed
@@ -89,7 +87,7 @@ recvRequest firstRequest settings conn ii th addr src = do
89 , rawQueryString = query
87 , rawQueryString = query
90 , queryString = H.parseQuery query
88 , queryString = H.parseQuery query
91 , requestHeaders = hdr
89 , requestHeaders = hdr
92− , isSecure = False
90+ , isSecure = isTransportSecure transport
93 , remoteHost = addr
91 , remoteHost = addr
94 , requestBody = rbody'
92 , requestBody = rbody'
95 , vault = vaultValue
93 , vault = vaultValue
@@ -103,8 +101,8 @@ recvRequest firstRequest settings conn ii th addr src = do
104----------------------------------------------------------------
102----------------------------------------------------------------
106−headerLines :: Bool -> Source -> IO [ByteString]
104+headerLines :: Int -> Bool -> Source -> IO [ByteString]
107−headerLines firstRequest src = do
105+headerLines maxTotalHeaderLength firstRequest src = do
108 bs <- readSource src
106 bs <- readSource src
109 if S.null bs
107 if S.null bs
110 -- When we're working on a keep-alive connection and trying to
108 -- When we're working on a keep-alive connection and trying to
@@ -112,7 +110,7 @@ headerLines firstRequest src = do
112 -- lack of data as a real exception. See the http1 function in
110 -- lack of data as a real exception. See the http1 function in
113 -- the Run module for more details.
111 -- the Run module for more details.
114 then if firstRequest then throwIO ConnectionClosedByPeer else throwIO NoKeepAliveRequest
112 then if firstRequest then throwIO ConnectionClosedByPeer else throwIO NoKeepAliveRequest
115− else push src (THStatus 0 id id) bs
113+ else push maxTotalHeaderLength src (THStatus 0 id id) bs
117data NoKeepAliveRequest = NoKeepAliveRequest
115data NoKeepAliveRequest = NoKeepAliveRequest
118 deriving (Show, Typeable)
116 deriving (Show, Typeable)
@@ -222,8 +220,8 @@ close :: Sink ByteString IO a
222close = throwIO IncompleteHeaders
220close = throwIO IncompleteHeaders
225−push :: Source -> THStatus -> ByteString -> IO [ByteString]
223+push :: Int -> Source -> THStatus -> ByteString -> IO [ByteString]
226−push src (THStatus len lines prepend) bs'
224+push maxTotalHeaderLength src (THStatus len lines prepend) bs'
227 -- Too many bytes
225 -- Too many bytes
228 | len > maxTotalHeaderLength = throwIO OverLargeHeader
226 | len > maxTotalHeaderLength = throwIO OverLargeHeader
229 | otherwise = push' mnl
227 | otherwise = push' mnl
@@ -251,13 +249,13 @@ push src (THStatus len lines prepend) bs'
251 push' Nothing = do
249 push' Nothing = do
252 bst <- readSource' src
250 bst <- readSource' src
253 when (S.null bst) $ throwIO IncompleteHeaders
251 when (S.null bst) $ throwIO IncompleteHeaders
254− push src status bst
252+ push maxTotalHeaderLength src status bst
256 len' = len + bsLen
254 len' = len + bsLen
257 prepend' = S.append bs
255 prepend' = S.append bs
258 status = THStatus len' lines prepend'
256 status = THStatus len' lines prepend'
259 -- Found a newline, but next line continues as a multiline header
257 -- Found a newline, but next line continues as a multiline header
260− push' (Just (end, True)) = push src status rest
258+ push' (Just (end, True)) = push maxTotalHeaderLength src status rest
262 rest = S.drop (end + 1) bs
260 rest = S.drop (end + 1) bs
263 prepend' = S.append (SU.unsafeTake (checkCR bs end) bs)
261 prepend' = S.append (SU.unsafeTake (checkCR bs end) bs)
@@ -276,12 +274,12 @@ push src (THStatus len lines prepend) bs'
276 in if start < bsLen then
274 in if start < bsLen then
277 -- more bytes in this chunk, push again
275 -- more bytes in this chunk, push again
278 let bs'' = SU.unsafeDrop start bs
276 let bs'' = SU.unsafeDrop start bs
279− in push src status bs''
277+ in push maxTotalHeaderLength src status bs''
281 -- no more bytes in this chunk, ask for more
279 -- no more bytes in this chunk, ask for more
282 bst <- readSource' src
280 bst <- readSource' src
283 when (S.null bs) $ throwIO IncompleteHeaders
281 when (S.null bs) $ throwIO IncompleteHeaders
284− push src status bst
282+ push maxTotalHeaderLength src status bst
286 start = end + 1 -- start of next chunk
284 start = end + 1 -- start of next chunk
287 line = SU.unsafeTake (checkCR bs end) bs
285 line = SU.unsafeTake (checkCR bs end) bs
@@ -299,3 +297,7 @@ pauseTimeoutKey = unsafePerformIO Vault.newKey
299getFileInfoKey :: Vault.Key (FilePath -> IO FileInfo)
297getFileInfoKey :: Vault.Key (FilePath -> IO FileInfo)
300getFileInfoKey = unsafePerformIO Vault.newKey
298getFileInfoKey = unsafePerformIO Vault.newKey
301{-# NOINLINE getFileInfoKey #-}
299{-# NOINLINE getFileInfoKey #-}
301+getClientCertificateKey :: Vault.Key (Maybe CertificateChain)
302+getClientCertificateKey = unsafePerformIO Vault.newKey
303+{-# NOINLINE getClientCertificateKey #-}