|
|
@ -511,47 +511,20 @@ OutgoingMessage.prototype._buffer = function(data, encoding) { |
|
|
|
|
|
|
|
|
|
|
|
OutgoingMessage.prototype._storeHeader = function(firstLine, headers) { |
|
|
|
var sentConnectionHeader = false; |
|
|
|
var sentContentLengthHeader = false; |
|
|
|
var sentTransferEncodingHeader = false; |
|
|
|
var sentDateHeader = false; |
|
|
|
var sentExpect = false; |
|
|
|
|
|
|
|
// firstLine in the case of request is: 'GET /index.html HTTP/1.1\r\n'
|
|
|
|
// in the case of response it is: 'HTTP/1.1 200 OK\r\n'
|
|
|
|
var messageHeader = firstLine; |
|
|
|
var state = { |
|
|
|
sentConnectionHeader: false, |
|
|
|
sentContentLengthHeader: false, |
|
|
|
sentTransferEncodingHeader: false, |
|
|
|
sentDateHeader: false, |
|
|
|
sentExpect: false, |
|
|
|
messageHeader: firstLine |
|
|
|
}; |
|
|
|
|
|
|
|
var field, value; |
|
|
|
var self = this; |
|
|
|
|
|
|
|
function store(field, value) { |
|
|
|
// Protect against response splitting. The if statement is there to
|
|
|
|
// minimize the performance impact in the common case.
|
|
|
|
if (/[\r\n]/.test(value)) |
|
|
|
value = value.replace(/[\r\n]+[ \t]*/g, ''); |
|
|
|
|
|
|
|
messageHeader += field + ': ' + value + CRLF; |
|
|
|
|
|
|
|
if (connectionExpression.test(field)) { |
|
|
|
sentConnectionHeader = true; |
|
|
|
if (closeExpression.test(value)) { |
|
|
|
self._last = true; |
|
|
|
} else { |
|
|
|
self.shouldKeepAlive = true; |
|
|
|
} |
|
|
|
|
|
|
|
} else if (transferEncodingExpression.test(field)) { |
|
|
|
sentTransferEncodingHeader = true; |
|
|
|
if (chunkExpression.test(value)) self.chunkedEncoding = true; |
|
|
|
|
|
|
|
} else if (contentLengthExpression.test(field)) { |
|
|
|
sentContentLengthHeader = true; |
|
|
|
} else if (dateExpression.test(field)) { |
|
|
|
sentDateHeader = true; |
|
|
|
} else if (expectExpression.test(field)) { |
|
|
|
sentExpect = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (headers) { |
|
|
|
var keys = Object.keys(headers); |
|
|
|
var isArray = (Array.isArray(headers)); |
|
|
@ -569,37 +542,38 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) { |
|
|
|
|
|
|
|
if (Array.isArray(value)) { |
|
|
|
for (var j = 0; j < value.length; j++) { |
|
|
|
store(field, value[j]); |
|
|
|
storeHeader(this, state, field, value[j]); |
|
|
|
} |
|
|
|
} else { |
|
|
|
store(field, value); |
|
|
|
storeHeader(this, state, field, value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Date header
|
|
|
|
if (this.sendDate == true && sentDateHeader == false) { |
|
|
|
messageHeader += 'Date: ' + utcDate() + CRLF; |
|
|
|
if (this.sendDate == true && state.sentDateHeader == false) { |
|
|
|
state.messageHeader += 'Date: ' + utcDate() + CRLF; |
|
|
|
} |
|
|
|
|
|
|
|
// keep-alive logic
|
|
|
|
if (sentConnectionHeader === false) { |
|
|
|
if (state.sentConnectionHeader === false) { |
|
|
|
var shouldSendKeepAlive = this.shouldKeepAlive && |
|
|
|
(sentContentLengthHeader || |
|
|
|
(state.sentContentLengthHeader || |
|
|
|
this.useChunkedEncodingByDefault || |
|
|
|
this.agent); |
|
|
|
if (shouldSendKeepAlive) { |
|
|
|
messageHeader += 'Connection: keep-alive\r\n'; |
|
|
|
state.messageHeader += 'Connection: keep-alive\r\n'; |
|
|
|
} else { |
|
|
|
this._last = true; |
|
|
|
messageHeader += 'Connection: close\r\n'; |
|
|
|
state.messageHeader += 'Connection: close\r\n'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (sentContentLengthHeader == false && sentTransferEncodingHeader == false) { |
|
|
|
if (state.sentContentLengthHeader == false && |
|
|
|
state.sentTransferEncodingHeader == false) { |
|
|
|
if (this._hasBody) { |
|
|
|
if (this.useChunkedEncodingByDefault) { |
|
|
|
messageHeader += 'Transfer-Encoding: chunked\r\n'; |
|
|
|
state.messageHeader += 'Transfer-Encoding: chunked\r\n'; |
|
|
|
this.chunkedEncoding = true; |
|
|
|
} else { |
|
|
|
this._last = true; |
|
|
@ -610,14 +584,43 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this._header = messageHeader + CRLF; |
|
|
|
this._header = state.messageHeader + CRLF; |
|
|
|
this._headerSent = false; |
|
|
|
|
|
|
|
// wait until the first body chunk, or close(), is sent to flush,
|
|
|
|
// UNLESS we're sending Expect: 100-continue.
|
|
|
|
if (sentExpect) this._send(''); |
|
|
|
if (state.sentExpect) this._send(''); |
|
|
|
}; |
|
|
|
|
|
|
|
function storeHeader(self, state, field, value) { |
|
|
|
// Protect against response splitting. The if statement is there to
|
|
|
|
// minimize the performance impact in the common case.
|
|
|
|
if (/[\r\n]/.test(value)) |
|
|
|
value = value.replace(/[\r\n]+[ \t]*/g, ''); |
|
|
|
|
|
|
|
state.messageHeader += field + ': ' + value + CRLF; |
|
|
|
|
|
|
|
if (connectionExpression.test(field)) { |
|
|
|
state.sentConnectionHeader = true; |
|
|
|
if (closeExpression.test(value)) { |
|
|
|
self._last = true; |
|
|
|
} else { |
|
|
|
self.shouldKeepAlive = true; |
|
|
|
} |
|
|
|
|
|
|
|
} else if (transferEncodingExpression.test(field)) { |
|
|
|
state.sentTransferEncodingHeader = true; |
|
|
|
if (chunkExpression.test(value)) self.chunkedEncoding = true; |
|
|
|
|
|
|
|
} else if (contentLengthExpression.test(field)) { |
|
|
|
state.sentContentLengthHeader = true; |
|
|
|
} else if (dateExpression.test(field)) { |
|
|
|
state.sentDateHeader = true; |
|
|
|
} else if (expectExpression.test(field)) { |
|
|
|
state.sentExpect = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
OutgoingMessage.prototype.setHeader = function(name, value) { |
|
|
|
if (arguments.length < 2) { |
|
|
|