@@ -39,6 +39,7 @@ module Network.Wai.Handler.Warp
39 , InvalidRequest (..)
39 , InvalidRequest (..)
41 , takeHeaders
41 , takeHeaders
@@ -81,6 +82,8 @@ import Blaze.ByteString.Builder.Char8 (fromChar, fromShow)
81import Data.Monoid (mappend, mconcat)
82import Data.Monoid (mappend, mconcat)
82import Network.Sendfile
83import Network.Sendfile
85+import qualified System.PosixCompat.Files as P
84import Control.Monad.IO.Class (liftIO)
87import Control.Monad.IO.Class (liftIO)
85import qualified Timeout as T
88import qualified Timeout as T
86import Data.Word (Word8)
89import Data.Word (Word8)
@@ -296,17 +299,29 @@ hasBody s req = s /= (H.Status 204 "") && requestMethod req /= "HEAD"
296sendResponse :: T.Handle
299sendResponse :: T.Handle
297 -> Request -> H.HttpVersion -> Socket -> Response -> IO Bool
300 -> Request -> H.HttpVersion -> Socket -> Response -> IO Bool
298sendResponse th req hv socket (ResponseFile s hs fp mpart) = do
301sendResponse th req hv socket (ResponseFile s hs fp mpart) = do
303+ case (readInt `fmap` lookup "content-length" hs, mpart) of
304+ (Just cl, _) -> return (hs, cl)
305+ (Nothing, Nothing) -> do
306+ cl <- P.fileSize `fmap` P.getFileStatus fp
307+ return (("Content-Length", B.pack $ show cl):hs, fromIntegral cl)
308+ (Nothing, Just part) -> do
309+ let cl = filePartByteCount part
310+ return (("Content-Length", B.pack $ show cl):hs, fromIntegral cl)
299− Sock.sendMany socket $ L.toChunks $ toLazyByteString $ headers hv s hs False
311+ Sock.sendMany socket $ L.toChunks $ toLazyByteString $ headers hv s hs' False
300 if hasBody s req
312 if hasBody s req
302 case mpart of
314 case mpart of
303− Nothing -> sendfile socket fp EntireFile (T.tickle th)
315+ Nothing -> sendfile socket fp PartOfFile {
304 Just part -> sendfile socket fp PartOfFile {
319 Just part -> sendfile socket fp PartOfFile {
305 rangeOffset = filePartOffset part
320 rangeOffset = filePartOffset part
306 , rangeLength = filePartByteCount part
321 , rangeLength = filePartByteCount part
307 } (T.tickle th)
322 } (T.tickle th)
308 T.tickle th
323 T.tickle th
309− return $ lookup "content-length" hs /= Nothing
324+ return True
310 else return True
325 else return True
311sendResponse th req hv socket (ResponseBuilder s hs b)
326sendResponse th req hv socket (ResponseBuilder s hs b)
312 | hasBody s req = do
327 | hasBody s req = do
@@ -497,3 +512,8 @@ checkCR bs pos =
499{-# INLINE checkCR #-}
514{-# INLINE checkCR #-}
516+-- Note: This function produces garbage on invalid input. But serving an
517+-- invalid content-length is a bad idea, mkay?
518+readInt :: S.ByteString -> Integer
519+readInt = S.foldl' (\x w -> x * 10 + fromIntegral w - 48) 0