diff --git a/doc/api/errors.md b/doc/api/errors.md index 23817ef3d1924f..ad34c15896d84b 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -818,9 +818,11 @@ HTTP/1 connection specific headers are forbidden to be used in HTTP/2 requests and responses. -### ERR_HTTP2_INVALID_HEADER_VALUE +### ERR_HTTP_INVALID_HEADER_VALUE + +### ERR_HTTP_INVALID_HEADER_VALUE -Used to indicate that an invalid HTTP/2 header value has been specified. +Used to indicate that an invalid HTTP header value has been specified. ### ERR_HTTP2_INVALID_INFO_STATUS diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 76d83b19218ceb..b5f87d604d4282 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -437,16 +437,7 @@ function _storeHeader(firstLine, headers) { function storeHeader(self, state, key, value, validate) { if (validate) { - if (typeof key !== 'string' || !key || !checkIsHttpToken(key)) { - 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); - } + validateHeader(key, value); } state.header += key + ': ' + escapeHeaderValue(value) + CRLF; matchHeader(self, state, key, value); @@ -494,20 +485,27 @@ function matchHeader(self, state, field, value) { } } -function validateHeader(msg, name, value) { - if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) - throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name); - if (value === undefined) - throw new errors.TypeError('ERR_MISSING_ARGS', 'value'); - if (msg._header) - throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'set'); - if (checkInvalidHeaderChar(value)) { +function validateHeader(name, value) { + var err; + if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) { + err = new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name); + } else if (value === undefined) { + err = new errors.TypeError('ERR_HTTP_INVALID_HEADER_VALUE', value, name); + } else if (checkInvalidHeaderChar(value)) { 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) { + Error.captureStackTrace(err, validateHeader); + throw err; } } + 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]) this[outHeadersKey] = {}; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 7148279672c2cc..0e7f049a0cd275 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -204,7 +204,6 @@ E('ERR_HTTP2_INFO_STATUS_NOT_ALLOWED', 'Informational status codes cannot be used'); E('ERR_HTTP2_INVALID_CONNECTION_HEADERS', 'HTTP/1 Connection specific headers are forbidden: "%s"'); -E('ERR_HTTP2_INVALID_HEADER_VALUE', 'Value must not be undefined or null'); E('ERR_HTTP2_INVALID_INFO_STATUS', (code) => `Invalid informational status code: ${code}`); E('ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH', @@ -241,6 +240,7 @@ E('ERR_HTTP2_UNSUPPORTED_PROTOCOL', E('ERR_HTTP_HEADERS_SENT', 'Cannot %s headers after they are sent to the client'); 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', (originalStatusCode) => `Invalid status code: ${originalStatusCode}`); E('ERR_HTTP_TRAILER_INVALID', diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index c96fc931969f39..f4ce18798bee84 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -40,12 +40,18 @@ let statusMessageWarned = false; // close as possible to the current require('http') API function assertValidHeader(name, value) { - if (name === '' || typeof name !== 'string') - throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name); - if (isPseudoHeader(name)) - throw new errors.Error('ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED'); - if (value === undefined || value === null) - throw new errors.TypeError('ERR_HTTP2_INVALID_HEADER_VALUE'); + var err; + if (name === '' || typeof name !== 'string') { + err = new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name); + } else if (isPseudoHeader(name)) { + err = new errors.Error('ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED'); + } else if (value === undefined || value === null) { + err = new errors.TypeError('ERR_HTTP_INVALID_HEADER_VALUE', value, name); + } + if (err) { + Error.captureStackTrace(err, assertValidHeader); + throw err; + } } function isPseudoHeader(name) { diff --git a/test/parallel/test-http-mutable-headers.js b/test/parallel/test-http-mutable-headers.js index 929a566caf5578..2473a08eb1978e 100644 --- a/test/parallel/test-http-mutable-headers.js +++ b/test/parallel/test-http-mutable-headers.js @@ -61,9 +61,9 @@ const s = http.createServer(common.mustCall((req, res) => { common.expectsError( () => res.setHeader('someHeader'), { - code: 'ERR_MISSING_ARGS', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'The "value" argument must be specified' + message: 'Invalid value "undefined" for header "someHeader"' } ); common.expectsError( diff --git a/test/parallel/test-http-outgoing-proto.js b/test/parallel/test-http-outgoing-proto.js index 22eba0981f6fc2..7db252dfbf9855 100644 --- a/test/parallel/test-http-outgoing-proto.js +++ b/test/parallel/test-http-outgoing-proto.js @@ -34,9 +34,9 @@ assert.throws(() => { const outgoingMessage = new OutgoingMessage(); outgoingMessage.setHeader('test'); }, common.expectsError({ - code: 'ERR_MISSING_ARGS', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'The "value" argument must be specified' + message: 'Invalid value "undefined" for header "test"' })); assert.throws(() => { diff --git a/test/parallel/test-http-write-head.js b/test/parallel/test-http-write-head.js index 70ad5935a92690..e254f8d64da349 100644 --- a/test/parallel/test-http-write-head.js +++ b/test/parallel/test-http-write-head.js @@ -44,9 +44,9 @@ const s = http.createServer(common.mustCall((req, res) => { common.expectsError( () => res.setHeader('foo', undefined), { - code: 'ERR_MISSING_ARGS', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'The "value" argument must be specified' + message: 'Invalid value "undefined" for header "foo"' } ); diff --git a/test/parallel/test-http2-compat-serverresponse-headers.js b/test/parallel/test-http2-compat-serverresponse-headers.js index aae1d96c552ebe..a46c7348ae9477 100644 --- a/test/parallel/test-http2-compat-serverresponse-headers.js +++ b/test/parallel/test-http2-compat-serverresponse-headers.js @@ -83,16 +83,16 @@ server.listen(0, common.mustCall(function() { assert.throws(function() { response.setHeader(real, null); }, common.expectsError({ - code: 'ERR_HTTP2_INVALID_HEADER_VALUE', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'Value must not be undefined or null' + message: 'Invalid value "null" for header "foo-bar"' })); assert.throws(function() { response.setHeader(real, undefined); }, common.expectsError({ - code: 'ERR_HTTP2_INVALID_HEADER_VALUE', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'Value must not be undefined or null' + message: 'Invalid value "undefined" for header "foo-bar"' })); common.expectsError( () => response.setHeader(), // header name undefined diff --git a/test/parallel/test-http2-compat-serverresponse-trailers.js b/test/parallel/test-http2-compat-serverresponse-trailers.js index 4d93e14dbec4b4..718a30c7cd45d9 100644 --- a/test/parallel/test-http2-compat-serverresponse-trailers.js +++ b/test/parallel/test-http2-compat-serverresponse-trailers.js @@ -26,17 +26,17 @@ server.listen(0, common.mustCall(() => { common.expectsError( () => response.setTrailer('test', undefined), { - code: 'ERR_HTTP2_INVALID_HEADER_VALUE', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'Value must not be undefined or null' + message: 'Invalid value "undefined" for header "test"' } ); common.expectsError( () => response.setTrailer('test', null), { - code: 'ERR_HTTP2_INVALID_HEADER_VALUE', + code: 'ERR_HTTP_INVALID_HEADER_VALUE', type: TypeError, - message: 'Value must not be undefined or null' + message: 'Invalid value "null" for header "test"' } ); common.expectsError(