http: Use writev instead of the hacky hot end

pull/24998/head
isaacs 2013-05-08 14:28:56 -07:00
parent a58454226f
commit ec576235f1
1 changed files with 16 additions and 100 deletions

View File

@ -460,6 +460,10 @@ var crlf_buf = new Buffer('\r\n');
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) {
return false;
}
@ -473,113 +477,25 @@ OutgoingMessage.prototype.end = function(data, encoding) {
data = false;
}
if (this.connection && data)
this.connection.cork();
var ret;
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) {
if (data) {
// Normal body write.
ret = this.write(data, encoding);
}
if (!hot) {
if (this.chunkedEncoding) {
ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk.
} else {
// Force a flush, HACK.
ret = this._send('');
}
if (this.chunkedEncoding) {
ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk.
} else {
// Force a flush, HACK.
ret = this._send('');
}
if (this.connection && data)
this.connection.uncork();
this.finished = true;
// There is the first message on the outgoing queue, and we've sent