You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Calling response.writeHead() when using response.stream() prevents the stream from being piped to the response body.
Cause of the issue
In line 1113 of file src/response.ts, a check against response.isPending is made before the stream is about to be piped to the body in response.streamBody(); if response.isPending is false, the finish() method returns and never reaches response.streamBody().
If response.writeHead() is called anywhere before a response.finish call (implicit or explicit), it will cause response.headersSent to be true, and since response.isPending = !response.headersSent && !response.finished, response.isPending will be false.
Why this is a bug
In my real-world app, I have to stream out a CSV file without knowing its length beforehand, and hence I cannot set the Content-Length header. This means, I have to set the Transfer-Encoding: chunked header, and write the response headers as soon as possible. This bug prevents me from doing that without resorting to a workaround.
My workaround is to force the piping of the stream to the response body by copying the contents of response.streamBody() and placing them in my controller function. Thankfully, the AdonisJS Response object exposes the underlying Node.js ServerResponse object, which makes the forcing of the pipe possible.
Reproduction
I created a reproduction using the starter web kit. In it, I have a web page at / endpoint, which contains two buttons Errored Dump and Dump. Errored Dump calls the /dump-error endpoint, which reproduces the bug. Dump calls the /dump endpoint, which shows my workaround as working.
Fix Proposal
The simplest way to fix this would be to add a response.writeHeadCalled flag, which will cancel out response.headersSent like this: response.isPending = !(response.writeHeadCalled ? false : response.headersSent) && !response.finished.
Package version
@adonisjs/[email protected]
Describe the bug
Calling
response.writeHead()
when usingresponse.stream()
prevents the stream from being piped to the response body.Cause of the issue
In line 1113 of file
src/response.ts
, a check againstresponse.isPending
is made before the stream is about to be piped to the body inresponse.streamBody()
; ifresponse.isPending
is false, thefinish()
method returns and never reachesresponse.streamBody()
.If
response.writeHead()
is called anywhere before aresponse.finish
call (implicit or explicit), it will causeresponse.headersSent
to betrue
, and sinceresponse.isPending = !response.headersSent && !response.finished
,response.isPending
will befalse
.Why this is a bug
In my real-world app, I have to stream out a CSV file without knowing its length beforehand, and hence I cannot set the
Content-Length
header. This means, I have to set theTransfer-Encoding: chunked
header, and write the response headers as soon as possible. This bug prevents me from doing that without resorting to a workaround.My workaround is to force the piping of the stream to the response body by copying the contents of
response.streamBody()
and placing them in my controller function. Thankfully, the AdonisJSResponse
object exposes the underlying Node.jsServerResponse
object, which makes the forcing of the pipe possible.Reproduction
I created a reproduction using the starter web kit. In it, I have a web page at
/
endpoint, which contains two buttonsErrored Dump
andDump
.Errored Dump
calls the/dump-error
endpoint, which reproduces the bug.Dump
calls the/dump
endpoint, which shows my workaround as working.Fix Proposal
The simplest way to fix this would be to add a
response.writeHeadCalled
flag, which will cancel outresponse.headersSent
like this:response.isPending = !(response.writeHeadCalled ? false : response.headersSent) && !response.finished
.Reproduction repo
https://github.com/vocafeuvre/write-head-issue-repro
The text was updated successfully, but these errors were encountered: