|
|
@ -78,6 +78,9 @@ utcDate._onTimeout = function _onTimeout() { |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
function noopPendingOutput(amount) {} |
|
|
|
|
|
|
|
|
|
|
|
function OutgoingMessage() { |
|
|
|
Stream.call(this); |
|
|
|
|
|
|
@ -117,7 +120,7 @@ function OutgoingMessage() { |
|
|
|
this._header = null; |
|
|
|
this[outHeadersKey] = null; |
|
|
|
|
|
|
|
this._onPendingData = null; |
|
|
|
this._onPendingData = noopPendingOutput; |
|
|
|
} |
|
|
|
util.inherits(OutgoingMessage, Stream); |
|
|
|
|
|
|
@ -234,12 +237,18 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) { |
|
|
|
(encoding === 'utf8' || encoding === 'latin1' || !encoding)) { |
|
|
|
data = this._header + data; |
|
|
|
} else { |
|
|
|
this.output.unshift(this._header); |
|
|
|
this.outputEncodings.unshift('latin1'); |
|
|
|
this.outputCallbacks.unshift(null); |
|
|
|
this.outputSize += this._header.length; |
|
|
|
if (typeof this._onPendingData === 'function') |
|
|
|
this._onPendingData(this._header.length); |
|
|
|
var header = this._header; |
|
|
|
if (this.output.length === 0) { |
|
|
|
this.output = [header]; |
|
|
|
this.outputEncodings = ['latin1']; |
|
|
|
this.outputCallbacks = [null]; |
|
|
|
} else { |
|
|
|
this.output.unshift(header); |
|
|
|
this.outputEncodings.unshift('latin1'); |
|
|
|
this.outputCallbacks.unshift(null); |
|
|
|
} |
|
|
|
this.outputSize += header.length; |
|
|
|
this._onPendingData(header.length); |
|
|
|
} |
|
|
|
this._headerSent = true; |
|
|
|
} |
|
|
@ -275,19 +284,13 @@ function _writeRaw(data, encoding, callback) { |
|
|
|
return conn.write(data, encoding, callback); |
|
|
|
} |
|
|
|
// Buffer, as long as we're not destroyed.
|
|
|
|
return this._buffer(data, encoding, callback); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
OutgoingMessage.prototype._buffer = function _buffer(data, encoding, callback) { |
|
|
|
this.output.push(data); |
|
|
|
this.outputEncodings.push(encoding); |
|
|
|
this.outputCallbacks.push(callback); |
|
|
|
this.outputSize += data.length; |
|
|
|
if (typeof this._onPendingData === 'function') |
|
|
|
this._onPendingData(data.length); |
|
|
|
this._onPendingData(data.length); |
|
|
|
return false; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
OutgoingMessage.prototype._storeHeader = _storeHeader; |
|
|
@ -624,27 +627,31 @@ Object.defineProperty(OutgoingMessage.prototype, 'headersSent', { |
|
|
|
|
|
|
|
const crlf_buf = Buffer.from('\r\n'); |
|
|
|
OutgoingMessage.prototype.write = function write(chunk, encoding, callback) { |
|
|
|
if (this.finished) { |
|
|
|
return write_(this, chunk, encoding, callback, false); |
|
|
|
}; |
|
|
|
|
|
|
|
function write_(msg, chunk, encoding, callback, fromEnd) { |
|
|
|
if (msg.finished) { |
|
|
|
var err = new Error('write after end'); |
|
|
|
nextTick(this.socket[async_id_symbol], |
|
|
|
writeAfterEndNT.bind(this), |
|
|
|
nextTick(msg.socket[async_id_symbol], |
|
|
|
writeAfterEndNT.bind(msg), |
|
|
|
err, |
|
|
|
callback); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
if (!this._header) { |
|
|
|
this._implicitHeader(); |
|
|
|
if (!msg._header) { |
|
|
|
msg._implicitHeader(); |
|
|
|
} |
|
|
|
|
|
|
|
if (!this._hasBody) { |
|
|
|
if (!msg._hasBody) { |
|
|
|
debug('This type of response MUST NOT have a body. ' + |
|
|
|
'Ignoring write() calls.'); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) { |
|
|
|
if (!fromEnd && typeof chunk !== 'string' && !(chunk instanceof Buffer)) { |
|
|
|
throw new TypeError('First argument must be a string or Buffer'); |
|
|
|
} |
|
|
|
|
|
|
@ -654,38 +661,28 @@ OutgoingMessage.prototype.write = function write(chunk, encoding, callback) { |
|
|
|
if (chunk.length === 0) return true; |
|
|
|
|
|
|
|
var len, ret; |
|
|
|
if (this.chunkedEncoding) { |
|
|
|
if (typeof chunk === 'string' && |
|
|
|
encoding !== 'hex' && |
|
|
|
encoding !== 'base64' && |
|
|
|
encoding !== 'latin1') { |
|
|
|
if (msg.chunkedEncoding) { |
|
|
|
if (typeof chunk === 'string') |
|
|
|
len = Buffer.byteLength(chunk, encoding); |
|
|
|
chunk = len.toString(16) + CRLF + chunk + CRLF; |
|
|
|
ret = this._send(chunk, encoding, callback); |
|
|
|
} else { |
|
|
|
// buffer, or a non-toString-friendly encoding
|
|
|
|
if (typeof chunk === 'string') |
|
|
|
len = Buffer.byteLength(chunk, encoding); |
|
|
|
else |
|
|
|
len = chunk.length; |
|
|
|
|
|
|
|
if (this.connection && !this.connection.corked) { |
|
|
|
this.connection.cork(); |
|
|
|
process.nextTick(connectionCorkNT, this.connection); |
|
|
|
} |
|
|
|
else |
|
|
|
len = chunk.length; |
|
|
|
|
|
|
|
this._send(len.toString(16), 'latin1', null); |
|
|
|
this._send(crlf_buf, null, null); |
|
|
|
this._send(chunk, encoding, null); |
|
|
|
ret = this._send(crlf_buf, null, callback); |
|
|
|
if (msg.connection && !msg.connection.corked) { |
|
|
|
msg.connection.cork(); |
|
|
|
process.nextTick(connectionCorkNT, msg.connection); |
|
|
|
} |
|
|
|
|
|
|
|
msg._send(len.toString(16), 'latin1', null); |
|
|
|
msg._send(crlf_buf, null, null); |
|
|
|
msg._send(chunk, encoding, null); |
|
|
|
ret = msg._send(crlf_buf, null, callback); |
|
|
|
} else { |
|
|
|
ret = this._send(chunk, encoding, callback); |
|
|
|
ret = msg._send(chunk, encoding, callback); |
|
|
|
} |
|
|
|
|
|
|
|
debug('write ret = ' + ret); |
|
|
|
return ret; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function writeAfterEndNT(err, callback) { |
|
|
@ -736,49 +733,40 @@ function onFinish(outmsg) { |
|
|
|
outmsg.emit('finish'); |
|
|
|
} |
|
|
|
|
|
|
|
OutgoingMessage.prototype.end = function end(data, encoding, callback) { |
|
|
|
if (typeof data === 'function') { |
|
|
|
callback = data; |
|
|
|
data = null; |
|
|
|
OutgoingMessage.prototype.end = function end(chunk, encoding, callback) { |
|
|
|
if (typeof chunk === 'function') { |
|
|
|
callback = chunk; |
|
|
|
chunk = null; |
|
|
|
} else if (typeof encoding === 'function') { |
|
|
|
callback = encoding; |
|
|
|
encoding = null; |
|
|
|
} |
|
|
|
|
|
|
|
if (data && typeof data !== 'string' && !(data instanceof Buffer)) { |
|
|
|
throw new TypeError('First argument must be a string or Buffer'); |
|
|
|
} |
|
|
|
|
|
|
|
if (this.finished) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (!this._header) { |
|
|
|
if (data) { |
|
|
|
if (typeof data === 'string') |
|
|
|
this._contentLength = Buffer.byteLength(data, encoding); |
|
|
|
var uncork; |
|
|
|
if (chunk) { |
|
|
|
if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) { |
|
|
|
throw new TypeError('First argument must be a string or Buffer'); |
|
|
|
} |
|
|
|
if (!this._header) { |
|
|
|
if (typeof chunk === 'string') |
|
|
|
this._contentLength = Buffer.byteLength(chunk, encoding); |
|
|
|
else |
|
|
|
this._contentLength = data.length; |
|
|
|
} else { |
|
|
|
this._contentLength = 0; |
|
|
|
this._contentLength = chunk.length; |
|
|
|
} |
|
|
|
if (this.connection) { |
|
|
|
this.connection.cork(); |
|
|
|
uncork = true; |
|
|
|
} |
|
|
|
write_(this, chunk, encoding, null, true); |
|
|
|
} else if (!this._header) { |
|
|
|
this._contentLength = 0; |
|
|
|
this._implicitHeader(); |
|
|
|
} |
|
|
|
|
|
|
|
if (data && !this._hasBody) { |
|
|
|
debug('This type of response MUST NOT have a body. ' + |
|
|
|
'Ignoring data passed to end().'); |
|
|
|
data = null; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.connection && data) |
|
|
|
this.connection.cork(); |
|
|
|
|
|
|
|
if (data) { |
|
|
|
// Normal body write.
|
|
|
|
this.write(data, encoding); |
|
|
|
} |
|
|
|
|
|
|
|
if (typeof callback === 'function') |
|
|
|
this.once('finish', callback); |
|
|
|
|
|
|
@ -792,7 +780,7 @@ OutgoingMessage.prototype.end = function end(data, encoding, callback) { |
|
|
|
ret = this._send('', 'latin1', finish); |
|
|
|
} |
|
|
|
|
|
|
|
if (this.connection && data) |
|
|
|
if (uncork) |
|
|
|
this.connection.uncork(); |
|
|
|
|
|
|
|
this.finished = true; |
|
|
@ -871,8 +859,7 @@ OutgoingMessage.prototype._flushOutput = function _flushOutput(socket) { |
|
|
|
this.output = []; |
|
|
|
this.outputEncodings = []; |
|
|
|
this.outputCallbacks = []; |
|
|
|
if (typeof this._onPendingData === 'function') |
|
|
|
this._onPendingData(-this.outputSize); |
|
|
|
this._onPendingData(-this.outputSize); |
|
|
|
this.outputSize = 0; |
|
|
|
|
|
|
|
return ret; |
|
|
|