Search code examples
dartaqueduct

Clarification needed regarding streaming responses with Aqueduct


I'm reading docs of Aqueduct HTTP web server for Dart. In the section about streaming response body I see following 2 statements which do not completely fit together for me:

A body object may also be a Stream<T>. Stream<T> body objects are most often used when serving files. This allows the contents of the file to be streamed from disk to the HTTP client without having to load the whole file into memory first.

and

When a body object is a Stream<T>, the response will not be sent until the stream is closed. For finite streams - like those from opened filed - this happens as soon as the entire file is read.

So how does it send the response only after the entire file is read without having to load the whole file into memory first?


Solution

  • That's a great question and the wording in the docs could be improved. The code that matters is here: https://github.com/stablekernel/aqueduct/blob/master/aqueduct/lib/src/http/request.dart#L237.

    The outgoing HTTP response is a stream, too. When you write bytes to that stream, the bytes are transmitted across the wire (if you enable buffering, which is on by default, a buffer is built up before sending; IIRC this is 8kb by default).

    Your source stream - the stream representing your body object - is piped to the HTTP response stream (after being transformed by any codecs, if applicable). As soon as you return the Response object from your controller, your source stream starts being consumed. The response cannot be completed until the source stream indicates it is 'closed'. If you take a peek at the source for FileController, you can see that it uses File.openRead, which automatically closes the source stream once all bytes have been read.

    If your source stream is manually controlled, you return your Response object and then asynchronously add bytes to the stream and close it once complete. The key takeaway is that if you own the stream, you need to close it, and system utilities will typically close the stream for you. Hope this answers the question.