HTTP OutgoingMessage _send in two packets when a Buffer is written #7914
Labels
http
Issues or PRs related to the http subsystem.
performance
Issues and PRs related to the performance of Node.js.
stalled
Issues and PRs that are stalled.
When sending an HTTP outgoing message (HTTP.ServerResponse in this case), the behavior of _send, _flushOutput and _writeRaw cause short HTTP messages that should fit in one packet to often be written in two packets. I believe this is caused by some inefficient cork/uncork.
Here is an example program:
I know that I could use res.end(endBuf) / res.end(endStr) in this case but I'm not because this is just an example. I actually found this in a program that is piping from an HTTP.ClientResponse to an HTTP.ServerResponse, but that is much more complicated to work with. In this application, we're also forwarding the Content-Length header from the origin server (that's why I set Content-Length, too). This is the simplest example I could come up with that demonstrates the behavior.
Actual results:
Expected Results:
My analysis:
I think that the use of cork in _http_outgoing.js is not 100% correct in this case. It looks like in the buffer path we cork, write the headers, uncork and write the body.
If OutgoingMessage.prototype._send is called with a string, it will create one data string of the headers + body portion combined, and then call this._writeRaw() with that combined string. This path works (though pays the price of a) not using node Buffers and b) forcing a string concatenation.
If instead it is called with a Buffer, it executes the else{} case which cleverly unshifts the serialized headers into the output buffer and and then calls _writeRaw with the body portion. So far so good.
OK, next _writeRaw actually pushes things out in two stages: it calls _flushOutput and then connection.write:
_flushOutput does wrap its writes in cork()/uncork() but unfortunately it calls uncork() before the connection.write() of the body hits. On my system this usually forces the writes into two packets.
I hacked this shim into my program which does an extremely hacky and ugly job of calling uncork() only after also writing out the body, and this fixes it for me. See the "!!!" for the changes I made.
The text was updated successfully, but these errors were encountered: