http: Use writev instead of the hacky hot end
This commit is contained in:
parent
a58454226f
commit
ec576235f1
@ -460,6 +460,10 @@ var crlf_buf = new Buffer('\r\n');
|
|||||||
|
|
||||||
|
|
||||||
OutgoingMessage.prototype.end = function(data, encoding) {
|
OutgoingMessage.prototype.end = function(data, encoding) {
|
||||||
|
if (data && typeof data !== 'string' && !Buffer.isBuffer(data)) {
|
||||||
|
throw new TypeError('first argument must be a string or Buffer');
|
||||||
|
}
|
||||||
|
|
||||||
if (this.finished) {
|
if (this.finished) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -473,113 +477,25 @@ OutgoingMessage.prototype.end = function(data, encoding) {
|
|||||||
data = false;
|
data = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.connection && data)
|
||||||
|
this.connection.cork();
|
||||||
|
|
||||||
var ret;
|
var ret;
|
||||||
|
if (data) {
|
||||||
var hot = this._headerSent === false &&
|
|
||||||
(data && data.length > 0) &&
|
|
||||||
this.output.length === 0 &&
|
|
||||||
this.connection &&
|
|
||||||
this.connection.writable &&
|
|
||||||
this.connection._httpMessage === this;
|
|
||||||
|
|
||||||
// The benefits of the hot-path optimization below start to fall
|
|
||||||
// off when the buffer size gets up near 128KB, because the cost
|
|
||||||
// of the copy is more than the cost of the extra write() call.
|
|
||||||
// Switch to the write/end method at that point. Heuristics and
|
|
||||||
// magic numbers are awful, but slow http responses are worse.
|
|
||||||
if (hot && Buffer.isBuffer(data) && data.length > 120 * 1024)
|
|
||||||
hot = false;
|
|
||||||
|
|
||||||
if (hot) {
|
|
||||||
// Hot path. They're doing
|
|
||||||
// res.writeHead();
|
|
||||||
// res.end(blah);
|
|
||||||
// HACKY.
|
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
if (this.chunkedEncoding) {
|
|
||||||
var l = Buffer.byteLength(data, encoding).toString(16);
|
|
||||||
ret = this.connection.write(this._header + l + CRLF +
|
|
||||||
data + '\r\n0\r\n' +
|
|
||||||
this._trailer + '\r\n', encoding);
|
|
||||||
} else {
|
|
||||||
ret = this.connection.write(this._header + data, encoding);
|
|
||||||
}
|
|
||||||
} else if (Buffer.isBuffer(data)) {
|
|
||||||
if (this.chunkedEncoding) {
|
|
||||||
var chunk_size = data.length.toString(16);
|
|
||||||
|
|
||||||
// Skip expensive Buffer.byteLength() calls; only ISO-8859-1 characters
|
|
||||||
// are allowed in HTTP headers. Therefore:
|
|
||||||
//
|
|
||||||
// this._header.length == Buffer.byteLength(this._header.length)
|
|
||||||
// this._trailer.length == Buffer.byteLength(this._trailer.length)
|
|
||||||
//
|
|
||||||
var header_len = this._header.length;
|
|
||||||
var chunk_size_len = chunk_size.length;
|
|
||||||
var data_len = data.length;
|
|
||||||
var trailer_len = this._trailer.length;
|
|
||||||
|
|
||||||
var len = header_len +
|
|
||||||
chunk_size_len +
|
|
||||||
2 + // '\r\n'.length
|
|
||||||
data_len +
|
|
||||||
5 + // '\r\n0\r\n'.length
|
|
||||||
trailer_len +
|
|
||||||
2; // '\r\n'.length
|
|
||||||
|
|
||||||
var buf = new Buffer(len);
|
|
||||||
var off = 0;
|
|
||||||
|
|
||||||
buf.write(this._header, off, header_len, 'ascii');
|
|
||||||
off += header_len;
|
|
||||||
|
|
||||||
buf.write(chunk_size, off, chunk_size_len, 'ascii');
|
|
||||||
off += chunk_size_len;
|
|
||||||
|
|
||||||
crlf_buf.copy(buf, off);
|
|
||||||
off += 2;
|
|
||||||
|
|
||||||
data.copy(buf, off);
|
|
||||||
off += data_len;
|
|
||||||
|
|
||||||
zero_chunk_buf.copy(buf, off);
|
|
||||||
off += 5;
|
|
||||||
|
|
||||||
if (trailer_len > 0) {
|
|
||||||
buf.write(this._trailer, off, trailer_len, 'ascii');
|
|
||||||
off += trailer_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
crlf_buf.copy(buf, off);
|
|
||||||
|
|
||||||
ret = this.connection.write(buf);
|
|
||||||
} else {
|
|
||||||
var header_len = this._header.length;
|
|
||||||
var buf = new Buffer(header_len + data.length);
|
|
||||||
buf.write(this._header, 0, header_len, 'ascii');
|
|
||||||
data.copy(buf, header_len);
|
|
||||||
ret = this.connection.write(buf);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new TypeError('first argument must be a string or Buffer');
|
|
||||||
}
|
|
||||||
this._headerSent = true;
|
|
||||||
|
|
||||||
} else if (data) {
|
|
||||||
// Normal body write.
|
// Normal body write.
|
||||||
ret = this.write(data, encoding);
|
ret = this.write(data, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hot) {
|
if (this.chunkedEncoding) {
|
||||||
if (this.chunkedEncoding) {
|
ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk.
|
||||||
ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk.
|
} else {
|
||||||
} else {
|
// Force a flush, HACK.
|
||||||
// Force a flush, HACK.
|
ret = this._send('');
|
||||||
ret = this._send('');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.connection && data)
|
||||||
|
this.connection.uncork();
|
||||||
|
|
||||||
this.finished = true;
|
this.finished = true;
|
||||||
|
|
||||||
// There is the first message on the outgoing queue, and we've sent
|
// There is the first message on the outgoing queue, and we've sent
|
||||||
|
Loading…
x
Reference in New Issue
Block a user