<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Oct 30, 2013 at 4:18 AM, Manuel Gómez <span dir="ltr"><<a href="mailto:targen@gmail.com" target="_blank">targen@gmail.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Hi list,<br>
<br>
I’ve been playing with http-conduit in an attempt to do some manual<br>
testing on a HTTP service, and I ran into something I had not<br>
expected.  I was trying to set up a POST request with a chunked<br>
request body from a conduit.  The following code does work:<br>
<br>
> {-# LANGUAGE OverloadedStrings #-}<br>
><br>
> import Blaze.ByteString.Builder.ByteString (fromByteString)<br>
> import Control.Concurrent (threadDelay)<br>
> import Control.Monad.IO.Class (liftIO)<br>
> import Control.Monad.Trans.Resource (runResourceT)<br>
> import Data.ByteString (getLine)<br>
> import Data.Conduit (yield)<br>
> import Network.HTTP.Conduit (RequestBody(RequestBodySourceChunked), http, method, parseUrl, rawBody, requestBody, withManager)<br>
><br>
> source = do say "a"; wait; say "b"; wait; say "c"<br>
><br>
> wait = liftIO $ threadDelay 1000000<br>
> say = yield . fromByteString<br>
><br>
> main = runResourceT $ do<br>
>   req <- parseUrl "<a href="http://localhost:12345/" target="_blank">http://localhost:12345/</a>"<br>
>   withManager $ http req<br>
>     { method = "POST"<br>
>     , requestBody = RequestBodySourceChunked source<br>
>     }<br>
<br>
The important part is the `source` conduit: it yields a string, waits<br>
for a bit, yields another, waits for a bit, and yields again.  I<br>
expected this to send chunks as soon as the source yielded them.<br>
However, it seems to be sending all the chunks together at the end,<br>
when the source finishes.<br>
<br>
Doing the same thing without `wait`, and with `forever` as opposed to<br>
just sending three bits of string, seems to work closer to my<br>
expectations: it seems to buffer for a bit, then it sends what was<br>
buffered, then it buffers some more, and so on.<br>
<br>
Is this http-conduit or Blaze doing undesired buffering?  A quick run<br>
on `strace` seems to indicate it’s only doing the `send` system call<br>
every once in a while, so the buffering seems to be happening inside<br>
Haskell.<br>
<br>
I’m not even sure this is how the HTTP chunked transfer encoding is<br>
meant to be used — my actual use case has to do with sending<br>
potentially large files and hopefully using constant memory at the<br>
other end, but I’m also curious about using this to send asynchronous<br>
events and such.  Is this how it’s supposed to work?<br></blockquote><div><br></div><div>In order to get the behavior you're looking for, you need to flush the Builders to cause the buffers to be emptied. The important change is to your say function:</div>

<div><br></div><div>say :: Monad m => ByteString -> Source m Builder</div><div>say bs = yield (fromByteString bs <> flush)</div><div><br></div><div>I've set this up as a SoH tutorial as well: <a href="https://www.fpcomplete.com/user/snoyberg/random-code-snippets/http-conduit-buffering-tutorial">https://www.fpcomplete.com/user/snoyberg/random-code-snippets/http-conduit-buffering-tutorial</a></div>

<div><br></div><div>Michael </div></div></div></div>