@@ -10,6 +10,7 @@ module Network.Wai.Handler.Warp.Request (
10import Control.Applicative
10import Control.Applicative
11import Control.Exception.Lifted (throwIO)
11import Control.Exception.Lifted (throwIO)
12import Control.Monad.IO.Class (liftIO)
12import Control.Monad.IO.Class (liftIO)
13+import Data.Array ((!))
13import Data.ByteString (ByteString)
14import Data.ByteString (ByteString)
14import qualified Data.ByteString as S
15import qualified Data.ByteString as S
15import qualified Data.ByteString.Unsafe as SU
16import qualified Data.ByteString.Unsafe as SU
@@ -21,6 +22,7 @@ import qualified Network.HTTP.Types as H
21import Network.Socket (SockAddr)
22import Network.Socket (SockAddr)
22import Network.Wai
23import Network.Wai
23import Network.Wai.Handler.Warp.Conduit
24import Network.Wai.Handler.Warp.Conduit
25+import Network.Wai.Handler.Warp.Header
24import Network.Wai.Handler.Warp.ReadInt
26import Network.Wai.Handler.Warp.ReadInt
25import Network.Wai.Handler.Warp.RequestHeader
27import Network.Wai.Handler.Warp.RequestHeader
26import qualified Network.Wai.Handler.Warp.Timeout as Timeout
28import qualified Network.Wai.Handler.Warp.Timeout as Timeout
@@ -43,9 +45,12 @@ recvRequest :: Connection
43 -> IO (Request, IO (ResumableSource IO ByteString))
45 -> IO (Request, IO (ResumableSource IO ByteString))
44recvRequest conn timeoutHandle remoteHost' src0 = do
46recvRequest conn timeoutHandle remoteHost' src0 = do
45 (src, hdrlines) <- src0 $$+ headerLines
47 (src, hdrlines) <- src0 $$+ headerLines
46− (method, rpath, gets, httpversion, hdr') <- parseHeaderLines hdrlines
48+ (method, rpath, gets, httpversion, hdr) <- parseHeaderLines hdrlines
49+ let idxhdr = indexRequestHeader hdr
47− hdr <- liftIO $ handleExpect conn httpversion id hdr'
50+ liftIO $ handleExpect conn httpversion (idxhdr ! idxExpect)
48− (rbody, bodyLength, getSource) <- bodyAndSource src hdr
51+ (rbody, bodyLength, getSource) <- bodyAndSource src
52+ (idxhdr ! idxContentLength)
53+ (idxhdr ! idxTransferEncoding)
50 return (Request
55 return (Request
51 { requestMethod = method
56 { requestMethod = method
@@ -72,41 +77,42 @@ headerLines =
73handleExpect :: Connection
78handleExpect :: Connection
74 -> H.HttpVersion
79 -> H.HttpVersion
75− -> (H.RequestHeaders -> H.RequestHeaders)
80+ -> Maybe HeaderValue
76− -> H.RequestHeaders
81+ -> IO ()
77− -> IO H.RequestHeaders
78−handleExpect _ _ front [] = return $ front []
79−handleExpect conn hv front (("expect", "100-continue"):rest) = do
82+handleExpect conn ver (Just "100-continue") = connSendAll conn continue
80− connSendAll conn $
83+ where
81− if hv == H.http11
84+ continue
82− then "HTTP/1.1 100 Continue\r\n\r\n"
85+ | ver == H.http11 = "HTTP/1.1 100 Continue\r\n\r\n"
83− else "HTTP/1.0 100 Continue\r\n\r\n"
86+ | otherwise = "HTTP/1.0 100 Continue\r\n\r\n"
84− return $ front rest
87+handleExpect _ _ _ = return ()
85−handleExpect conn hv front (x:xs) = handleExpect conn hv (front . (x:)) xs
87----------------------------------------------------------------
89----------------------------------------------------------------
89bodyAndSource :: ResumableSource IO ByteString
91bodyAndSource :: ResumableSource IO ByteString
90− -> H.RequestHeaders
92+ -> Maybe HeaderValue
91 -> IO (Source IO ByteString
94 -> IO (Source IO ByteString
92 ,RequestBodyLength
95 ,RequestBodyLength
93 ,IO (ResumableSource IO ByteString))
96 ,IO (ResumableSource IO ByteString))
94−bodyAndSource src hdr
97+bodyAndSource src cl te
95 | chunked = do
98 | chunked = do
96 ref <- I.newIORef (src, NeedLen)
99 ref <- I.newIORef (src, NeedLen)
97 return (chunkedSource ref, ChunkedBody, fst <$> I.readIORef ref)
100 return (chunkedSource ref, ChunkedBody, fst <$> I.readIORef ref)
98 | otherwise = do
101 | otherwise = do
99− ibs <- IsolatedBSSource <$> I.newIORef (len0, src)
102+ ibs <- IsolatedBSSource <$> I.newIORef (len, src)
100 return (ibsIsolate ibs, bodyLen, ibsDone ibs)
103 return (ibsIsolate ibs, bodyLen, ibsDone ibs)
102− len0 = case lookup H.hContentLength hdr of
105+ len = toLength cl
106+ bodyLen = KnownLength $ fromIntegral len
107+ chunked = isChunked te
109+toLength :: Maybe HeaderValue -> Int
103− Nothing -> 0
110+toLength Nothing = 0
104− Just bs -> readInt bs
111+toLength (Just bs) = readInt bs
105− bodyLen = KnownLength $ fromIntegral len0
112+
106− chunked = isChunked hdr
108−isChunked :: H.RequestHeaders -> Bool
113+isChunked :: Maybe HeaderValue -> Bool
109−isChunked hdr = maybe False ((== "chunked") . CI.foldCase) $ lookup hTransferEncoding hdr
114+isChunked (Just bs) = CI.foldCase bs == "chunked"
111----------------------------------------------------------------
117----------------------------------------------------------------