http: improve errors thrown in header validation

PR-URL: https://github.com/nodejs/node/pull/16719
Fixes: https://github.com/nodejs/node/issues/16714
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Joyee Cheung 2017-11-03 20:04:12 +08:00
parent 11a9f36cae
commit 0a84e95cd9
6 changed files with 30 additions and 26 deletions

View File

@ -754,6 +754,11 @@ more headers.
Used when an invalid character is found in an HTTP response status message Used when an invalid character is found in an HTTP response status message
(reason phrase). (reason phrase).
<a id="ERR_HTTP_INVALID_HEADER_VALUE"></a>
### ERR_HTTP_INVALID_HEADER_VALUE
Used to indicate that an invalid HTTP header value has been specified.
<a id="ERR_HTTP_INVALID_STATUS_CODE"></a> <a id="ERR_HTTP_INVALID_STATUS_CODE"></a>
### ERR_HTTP_INVALID_STATUS_CODE ### ERR_HTTP_INVALID_STATUS_CODE

View File

@ -437,16 +437,7 @@ function _storeHeader(firstLine, headers) {
function storeHeader(self, state, key, value, validate) { function storeHeader(self, state, key, value, validate) {
if (validate) { if (validate) {
if (typeof key !== 'string' || !key || !checkIsHttpToken(key)) { validateHeader(key, value);
throw new errors.TypeError(
'ERR_INVALID_HTTP_TOKEN', 'Header name', key);
}
if (value === undefined) {
throw new errors.TypeError('ERR_MISSING_ARGS', `header "${key}"`);
} else if (checkInvalidHeaderChar(value)) {
debug('Header "%s" contains invalid characters', key);
throw new errors.TypeError('ERR_INVALID_CHAR', 'header content', key);
}
} }
state.header += key + ': ' + escapeHeaderValue(value) + CRLF; state.header += key + ': ' + escapeHeaderValue(value) + CRLF;
matchHeader(self, state, key, value); matchHeader(self, state, key, value);
@ -494,20 +485,27 @@ function matchHeader(self, state, field, value) {
} }
} }
function validateHeader(msg, name, value) { function validateHeader(name, value) {
if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) let err;
throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name); if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) {
if (value === undefined) err = new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name);
throw new errors.TypeError('ERR_MISSING_ARGS', 'value'); } else if (value === undefined) {
if (msg._header) err = new errors.TypeError('ERR_HTTP_INVALID_HEADER_VALUE', value, name);
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'set'); } else if (checkInvalidHeaderChar(value)) {
if (checkInvalidHeaderChar(value)) {
debug('Header "%s" contains invalid characters', name); debug('Header "%s" contains invalid characters', name);
throw new errors.TypeError('ERR_INVALID_CHAR', 'header content', name); err = new errors.TypeError('ERR_INVALID_CHAR', 'header content', name);
}
if (err !== undefined) {
Error.captureStackTrace(err, validateHeader);
throw err;
} }
} }
OutgoingMessage.prototype.setHeader = function setHeader(name, value) { OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
validateHeader(this, name, value); if (this._header) {
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'set');
}
validateHeader(name, value);
if (!this[outHeadersKey]) if (!this[outHeadersKey])
this[outHeadersKey] = {}; this[outHeadersKey] = {};

View File

@ -317,6 +317,7 @@ E('ERR_HTTP2_UNSUPPORTED_PROTOCOL',
E('ERR_HTTP_HEADERS_SENT', E('ERR_HTTP_HEADERS_SENT',
'Cannot %s headers after they are sent to the client'); 'Cannot %s headers after they are sent to the client');
E('ERR_HTTP_INVALID_CHAR', 'Invalid character in statusMessage.'); E('ERR_HTTP_INVALID_CHAR', 'Invalid character in statusMessage.');
E('ERR_HTTP_INVALID_HEADER_VALUE', 'Invalid value "%s" for header "%s"');
E('ERR_HTTP_INVALID_STATUS_CODE', E('ERR_HTTP_INVALID_STATUS_CODE',
(originalStatusCode) => `Invalid status code: ${originalStatusCode}`); (originalStatusCode) => `Invalid status code: ${originalStatusCode}`);
E('ERR_HTTP_TRAILER_INVALID', E('ERR_HTTP_TRAILER_INVALID',

View File

@ -61,9 +61,9 @@ const s = http.createServer(common.mustCall((req, res) => {
common.expectsError( common.expectsError(
() => res.setHeader('someHeader'), () => res.setHeader('someHeader'),
{ {
code: 'ERR_MISSING_ARGS', code: 'ERR_HTTP_INVALID_HEADER_VALUE',
type: TypeError, type: TypeError,
message: 'The "value" argument must be specified' message: 'Invalid value "undefined" for header "someHeader"'
} }
); );
common.expectsError( common.expectsError(

View File

@ -34,9 +34,9 @@ assert.throws(() => {
const outgoingMessage = new OutgoingMessage(); const outgoingMessage = new OutgoingMessage();
outgoingMessage.setHeader('test'); outgoingMessage.setHeader('test');
}, common.expectsError({ }, common.expectsError({
code: 'ERR_MISSING_ARGS', code: 'ERR_HTTP_INVALID_HEADER_VALUE',
type: TypeError, type: TypeError,
message: 'The "value" argument must be specified' message: 'Invalid value "undefined" for header "test"'
})); }));
assert.throws(() => { assert.throws(() => {

View File

@ -44,9 +44,9 @@ const s = http.createServer(common.mustCall((req, res) => {
common.expectsError( common.expectsError(
() => res.setHeader('foo', undefined), () => res.setHeader('foo', undefined),
{ {
code: 'ERR_MISSING_ARGS', code: 'ERR_HTTP_INVALID_HEADER_VALUE',
type: TypeError, type: TypeError,
message: 'The "value" argument must be specified' message: 'Invalid value "undefined" for header "foo"'
} }
); );