@@ -107,6 +107,7 @@ import System.IO (hPrint, stderr)
107import ReadInt (readInt64)
107import ReadInt (readInt64)
108import qualified Data.IORef as I
108import qualified Data.IORef as I
109import Data.Conduit.Network (bindPort, HostPreference (HostIPv4))
109import Data.Conduit.Network (bindPort, HostPreference (HostIPv4))
110+import Network.HTTP.Conduit.Chunk (chunkedConduit)
111#if WINDOWS
112#if WINDOWS
112import Control.Concurrent (threadDelay)
113import Control.Concurrent (threadDelay)
@@ -269,6 +270,17 @@ ibsIsolate ibs@(IsolatedBSSource ref) =
269ibsDone :: IsolatedBSSource -> IO (C.Source (ResourceT IO) ByteString)
270ibsDone :: IsolatedBSSource -> IO (C.Source (ResourceT IO) ByteString)
270ibsDone (IsolatedBSSource ref) = fmap snd $ I.readIORef ref
271ibsDone (IsolatedBSSource ref) = fmap snd $ I.readIORef ref
273+refSource :: MonadIO m => I.IORef (C.Source m a) -> C.Source m a
274+refSource ref = C.PipeM pull (return ())
277+ src <- liftIO $ I.readIORef ref
278+ (src', ma) <- src C.$$+ CL.head
279+ liftIO $ I.writeIORef ref src'
281+ Nothing -> return $ C.Done Nothing ()
282+ Just a -> return $ C.HaveOutput (refSource ref) (return ()) a
272serveConnection :: Settings
284serveConnection :: Settings
273 -> T.Handle
285 -> T.Handle
274 -> (SomeException -> IO ())
286 -> (SomeException -> IO ())
@@ -286,7 +298,7 @@ serveConnection settings th onException port app conn remoteHost' =
286 serveConnection'' fromClient
298 serveConnection'' fromClient
288 serveConnection'' fromClient = do
300 serveConnection'' fromClient = do
289− (env, ibs) <- parseRequest conn port remoteHost' fromClient
301+ (env, getSource) <- parseRequest conn port remoteHost' fromClient
290 case settingsIntercept settings env of
302 case settingsIntercept settings env of
291 Nothing -> do
303 Nothing -> do
292 -- Let the application run for as long as it wants
304 -- Let the application run for as long as it wants
@@ -294,20 +306,20 @@ serveConnection settings th onException port app conn remoteHost' =
294 res <- app env
306 res <- app env
296 -- flush the rest of the request body
308 -- flush the rest of the request body
297− ibsIsolate ibs C.$$ CL.sinkNull
309+ requestBody env C.$$ CL.sinkNull
298− fromClient' <- liftIO $ ibsDone ibs
310+ fromClient' <- liftIO getSource
300 liftIO $ T.resume th
312 liftIO $ T.resume th
301 keepAlive <- sendResponse th env conn res
313 keepAlive <- sendResponse th env conn res
302 when keepAlive $ serveConnection'' fromClient'
314 when keepAlive $ serveConnection'' fromClient'
303 Just intercept -> do
315 Just intercept -> do
304 liftIO $ T.pause th
316 liftIO $ T.pause th
305− fromClient' <- liftIO $ ibsDone ibs
317+ fromClient' <- liftIO getSource
306 intercept fromClient' conn
318 intercept fromClient' conn
308parseRequest :: Connection -> Port -> SockAddr
320parseRequest :: Connection -> Port -> SockAddr
309 -> C.Source (ResourceT IO) S.ByteString
321 -> C.Source (ResourceT IO) S.ByteString
310− -> ResourceT IO (Request, IsolatedBSSource)
322+ -> ResourceT IO (Request, IO (C.Source (ResourceT IO) ByteString))
311parseRequest conn port remoteHost' src1 = do
323parseRequest conn port remoteHost' src1 = do
312 (src2, headers') <- src1 C.$$+ takeHeaders
324 (src2, headers') <- src1 C.$$+ takeHeaders
313 parseRequest' conn port headers' remoteHost' src2
325 parseRequest' conn port headers' remoteHost' src2
@@ -347,7 +359,7 @@ parseRequest' :: Connection
347 -> [ByteString]
359 -> [ByteString]
348 -> SockAddr
360 -> SockAddr
349 -> C.Source (ResourceT IO) S.ByteString -- FIXME was buffered
361 -> C.Source (ResourceT IO) S.ByteString -- FIXME was buffered
350− -> ResourceT IO (Request, IsolatedBSSource)
362+ -> ResourceT IO (Request, IO (C.Source (ResourceT IO) ByteString))
351parseRequest' _ _ [] _ _ = throwIO $ NotEnoughLines []
363parseRequest' _ _ [] _ _ = throwIO $ NotEnoughLines []
352parseRequest' conn port (firstLine:otherLines) remoteHost' src = do
364parseRequest' conn port (firstLine:otherLines) remoteHost' src = do
353 (method, rpath', gets, httpversion) <- parseFirst firstLine
365 (method, rpath', gets, httpversion) <- parseFirst firstLine
@@ -364,9 +376,17 @@ parseRequest' conn port (firstLine:otherLines) remoteHost' src = do
364 Nothing -> 0
376 Nothing -> 0
365 Just bs -> readInt bs
377 Just bs -> readInt bs
366 let serverName' = takeUntil 58 host -- ':'
378 let serverName' = takeUntil 58 host -- ':'
379+ let chunked = maybe False (=="chunked")
380+ $ lookup "transfer-encoding" heads
367− (rbody, ibs) <- liftIO $ do
381+ (rbody, getSource) <- liftIO $
384+ ref <- I.newIORef (src C.$= chunkedConduit False)
385+ return (refSource ref, I.readIORef ref)
368− ibs <- fmap IsolatedBSSource $ I.newIORef (len0, src)
387+ ibs <- fmap IsolatedBSSource $ I.newIORef (len0, src)
369− return (ibsIsolate ibs, ibs)
388+ return (ibsIsolate ibs, ibsDone ibs)
370 return (Request
390 return (Request
371 { requestMethod = method
391 { requestMethod = method
372 , httpVersion = httpversion
392 , httpVersion = httpversion
@@ -381,7 +401,7 @@ parseRequest' conn port (firstLine:otherLines) remoteHost' src = do
381 , remoteHost = remoteHost'
401 , remoteHost = remoteHost'
382 , requestBody = rbody
402 , requestBody = rbody
383 , vault = mempty
403 , vault = mempty
384− }, ibs)
404+ }, getSource)
387takeUntil :: Word8 -> ByteString -> ByteString
407takeUntil :: Word8 -> ByteString -> ByteString