yesodweb / wai

Haskell Web Application Interface
MIT License
834 stars 263 forks source link

Why are there two different implementations of sending a `Builder`? #995

Open mitchellwrosen opened 5 months ago

mitchellwrosen commented 5 months ago

Hi, I've been reading over some of the warp code and I'm a bit unsure why there seem to be two different implementations of this basic operation:

sendBuilder :: Connection -> Builder -> IO ()

One implementation is used here, when sending a Builder body.

Here's the main "work loop" of the function, which uses the BufferWriter abstraction to discover chunk boundaries in the builder and send them each on the connection.

The second implementation is used here, when sending a streaming body, for which the user is handed a Builder -> IO () callback to execute whenever they want to send bytes to the client.

I don't really understand the implementation very well: it mostly leverages the streaming ByteString Builder interface here, but the guts of newByteStringBuilderRecv are kind of hard to understand.

Does anyone know why these two Builder -> IO () implementations are not the same? Perhaps there is a good a reason to prefer one mechanism when the function is called precisely once (as in the Builder response), and another mechanism when the function is called an arbitrary number of times (as in the streaming response)?

Vlix commented 3 weeks ago

I'm not completely sure, but I'd expect that in the streaming case, the user should get as much freedom as possible in when they want to send something, instead of buffering. :thinking: