@@ -80,9 +80,9 @@ serveConnection port app conn remoteHost' = do
8080 res <- app env
8181 remaining <- readIORef ilen
8282 _ <- B.hGet conn remaining -- FIXME just skip, don't read
83− sendResponse (httpVersion env) conn res
83+ keepAlive <- sendResponse (httpVersion env) conn res
8484 hFlush conn
85− when (isChunked $ httpVersion env) serveConnection'
85+ when keepAlive serveConnection'
8686
8787 catchEOFError :: IOError -> IO ()
8888 catchEOFError e | isEOFError e = case ioeGetHandle e of
@@ -169,8 +169,8 @@ parseFirst s = do
169169 let (rpath, qstring) = B.break (== '?') query
170170 return (method, rpath, qstring, hsecond)
171171
172−headers :: HttpVersion -> Status -> ResponseHeaders -> Builder
173−headers httpversion status responseHeaders = mconcat
172+headers :: HttpVersion -> Status -> ResponseHeaders -> Bool -> Builder
173+headers httpversion status responseHeaders isChunked' = mconcat
174174 [ fromByteString "HTTP/"
175175 , fromByteString httpversion
176176 , fromChar ' '
@@ -179,7 +179,7 @@ headers httpversion status responseHeaders = mconcat
179179 , fromByteString $ statusMessage status
180180 , fromByteString "\r\n"
181181 , mconcat $ map go responseHeaders
182− , if isChunked httpversion
182+ , if isChunked'
183183 then fromByteString "Transfer-Encoding: chunked\r\n\r\n"
184184 else fromByteString "\r\n"
185185 ]
@@ -194,26 +194,37 @@ headers httpversion status responseHeaders = mconcat
194194isChunked :: HttpVersion -> Bool
195195isChunked = (==) http11
196196
197−sendResponse :: HttpVersion -> Handle -> Response -> IO ()
198−sendResponse hv handle res = do
199− responseEnumerator res $ \s hs ->
200− chunk'
201− $ E.enumList 1 [headers hv s hs]
202− $$ E.joinI $ builderToByteString
203− $$ iterHandle handle
197+sendResponse :: HttpVersion -> Handle -> Response -> IO Bool
198+sendResponse hv handle res =
199+ responseEnumerator res go
204200 where
205− chunk' i =
206− if isChunked hv
207− then E.joinI $ chunk $$ i
208− else i
209− chunk :: E.Enumeratee Builder Builder IO ()
210− chunk = E.checkDone $ E.continue . step
211− step k E.EOF = k (E.Chunks [chunkedTransferTerminator]) >>== return
212− step k (E.Chunks []) = E.continue $ step k
213− step k (E.Chunks builders) =
214− k (E.Chunks [chunked]) >>== chunk
201+ go s hs =
202+ chunk'
203+ $ E.enumList 1 [headers hv s hs isChunked']
204+ $$ E.joinI $ builderToByteString
205+ $$ (iterHandle handle >> return isKeepAlive)
215206 where
216− chunked = chunkedTransferEncoding $ mconcat builders
207+ hasLength = lookup "content-length" hs /= Nothing
208+ isChunked' = isChunked hv && not hasLength
209+ isKeepAlive = isChunked' || hasLength
210+ chunk' i =
211+ if isChunked'
212+ then E.joinI $ chunk $$ i
213+ else
214+ (if isKeepAlive
215+ then E.joinI $ after $$ i
216+ else i)
217+ chunk :: E.Enumeratee Builder Builder IO Bool
218+ chunk = E.checkDone $ E.continue . step
219+ step k E.EOF = k (E.Chunks [chunkedTransferTerminator]) >>== return
220+ step k (E.Chunks []) = E.continue $ step k
221+ step k (E.Chunks builders) =
222+ k (E.Chunks [chunked]) >>== chunk
223+ where
224+ chunked = chunkedTransferEncoding $ mconcat builders
225+ after = E.checkDone $ E.continue . after'
226+ after' k E.EOF = k (E.Chunks [fromByteString "\r\n\r\n"]) >>== return
227+ after' k chunks = k chunks >>== after
217228
218229parseHeaderNoAttr :: ByteString -> (ByteString, ByteString)
219230parseHeaderNoAttr s =