Skip to content

Commit

Permalink
errors: migrate _http_outgoing
Browse files Browse the repository at this point in the history
PR-URL: #14735
Refs: #11273
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
  • Loading branch information
starkwang authored and refack committed Aug 14, 2017
1 parent 28a47aa commit 11a2ca2
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 96 deletions.
5 changes: 5 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,11 @@ Used when an attempt is made to open an IPC communication channel with a
synchronous forked Node.js process. See the documentation for the
[`child_process`](child_process.html) module for more information.

<a id="ERR_METHOD_NOT_IMPLEMENTED"></a>
### ERR_METHOD_NOT_IMPLEMENTED

Used when a method is required but not implemented.

<a id="ERR_MISSING_ARGS"></a>
### ERR_MISSING_ARGS

Expand Down
6 changes: 3 additions & 3 deletions lib/_http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function ClientRequest(options, cb) {

if (methodIsString && method) {
if (!common._checkIsHttpToken(method)) {
throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Method');
throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Method', method);
}
method = this.method = method.toUpperCase();
} else {
Expand Down Expand Up @@ -211,7 +211,7 @@ function ClientRequest(options, cb) {
options.headers);
} else if (this.getHeader('expect')) {
if (this._header) {
throw new errors.Error('ERR_HTTP_HEADERS_SENT');
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'render');
}

this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
Expand Down Expand Up @@ -302,7 +302,7 @@ ClientRequest.prototype._finish = function _finish() {

ClientRequest.prototype._implicitHeader = function _implicitHeader() {
if (this._header) {
throw new errors.Error('ERR_HTTP_HEADERS_SENT');
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'render');
}
this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
this[outHeadersKey]);
Expand Down
40 changes: 21 additions & 19 deletions lib/_http_outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ Object.defineProperty(OutgoingMessage.prototype, '_headerNames', {

OutgoingMessage.prototype._renderHeaders = function _renderHeaders() {
if (this._header) {
throw new Error('Can\'t render headers after they are sent to the client');
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'render');
}

var headersMap = this[outHeadersKey];
Expand Down Expand Up @@ -433,14 +433,14 @@ function _storeHeader(firstLine, headers) {
function storeHeader(self, state, key, value, validate) {
if (validate) {
if (typeof key !== 'string' || !key || !checkIsHttpToken(key)) {
throw new TypeError(
'Header name must be a valid HTTP Token ["' + key + '"]');
throw new errors.TypeError(
'ERR_INVALID_HTTP_TOKEN', 'Header name', key);
}
if (value === undefined) {
throw new Error('Header "%s" value must not be undefined', key);
throw new errors.TypeError('ERR_MISSING_ARGS', `header "${key}"`);
} else if (checkInvalidHeaderChar(value)) {
debug('Header "%s" contains invalid characters', key);
throw new TypeError('The header content contains invalid characters');
throw new errors.TypeError('ERR_INVALID_CHAR', 'header content', key);
}
}
state.header += key + ': ' + escapeHeaderValue(value) + CRLF;
Expand Down Expand Up @@ -491,14 +491,14 @@ function matchHeader(self, state, field, value) {

function validateHeader(msg, name, value) {
if (typeof name !== 'string' || !name || !checkIsHttpToken(name))
throw new TypeError(`Header name must be a valid HTTP Token ["${name}"]`);
throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Header name', name);
if (value === undefined)
throw new Error('"value" required in setHeader("' + name + '", value)');
throw new errors.TypeError('ERR_MISSING_ARGS', 'value');
if (msg._header)
throw new Error('Can\'t set headers after they are sent.');
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'set');
if (checkInvalidHeaderChar(value)) {
debug('Header "%s" contains invalid characters', name);
throw new TypeError('The header content contains invalid characters');
throw new errors.TypeError('ERR_INVALID_CHAR', 'header content', name);
}
}
OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
Expand Down Expand Up @@ -529,7 +529,7 @@ OutgoingMessage.prototype.setHeader = function setHeader(name, value) {

OutgoingMessage.prototype.getHeader = function getHeader(name) {
if (typeof name !== 'string') {
throw new TypeError('"name" argument must be a string');
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'name', 'string');
}

if (!this[outHeadersKey]) return;
Expand Down Expand Up @@ -565,7 +565,7 @@ OutgoingMessage.prototype.getHeaders = function getHeaders() {

OutgoingMessage.prototype.hasHeader = function hasHeader(name) {
if (typeof name !== 'string') {
throw new TypeError('"name" argument must be a string');
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'name', 'string');
}

return !!(this[outHeadersKey] && this[outHeadersKey][name.toLowerCase()]);
Expand All @@ -574,11 +574,11 @@ OutgoingMessage.prototype.hasHeader = function hasHeader(name) {

OutgoingMessage.prototype.removeHeader = function removeHeader(name) {
if (typeof name !== 'string') {
throw new TypeError('"name" argument must be a string');
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'name', 'string');
}

if (this._header) {
throw new Error('Can\'t remove headers after they are sent');
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'remove');
}

var key = name.toLowerCase();
Expand Down Expand Up @@ -609,7 +609,7 @@ OutgoingMessage.prototype.removeHeader = function removeHeader(name) {


OutgoingMessage.prototype._implicitHeader = function _implicitHeader() {
throw new Error('_implicitHeader() method is not implemented');
throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED', '_implicitHeader()');
};

Object.defineProperty(OutgoingMessage.prototype, 'headersSent', {
Expand Down Expand Up @@ -646,7 +646,8 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
}

if (!fromEnd && typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
throw new TypeError('First argument must be a string or Buffer');
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'first argument',
['string', 'buffer']);
}


Expand Down Expand Up @@ -712,12 +713,12 @@ OutgoingMessage.prototype.addTrailers = function addTrailers(headers) {
value = headers[key];
}
if (typeof field !== 'string' || !field || !checkIsHttpToken(field)) {
throw new TypeError(
'Trailer name must be a valid HTTP Token ["' + field + '"]');
throw new errors.TypeError('ERR_INVALID_HTTP_TOKEN', 'Trailer name',
field);
}
if (checkInvalidHeaderChar(value)) {
debug('Trailer "%s" contains invalid characters', field);
throw new TypeError('The trailer content contains invalid characters');
throw new errors.TypeError('ERR_INVALID_CHAR', 'trailer content', field);
}
this._trailer += field + ': ' + escapeHeaderValue(value) + CRLF;
}
Expand All @@ -743,7 +744,8 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
var uncork;
if (chunk) {
if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
throw new TypeError('First argument must be a string or Buffer');
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'first argument',
['string', 'buffer']);
}
if (!this._header) {
if (typeof chunk === 'string')
Expand Down
2 changes: 1 addition & 1 deletion lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ function writeHead(statusCode, reason, obj) {
}
}
if (k === undefined && this._header) {
throw new errors.Error('ERR_HTTP_HEADERS_SENT');
throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'render');
}
// only progressive api is used
headers = this[outHeadersKey];
Expand Down
15 changes: 12 additions & 3 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ E('ERR_ENCODING_NOT_SUPPORTED',
E('ERR_ENCODING_INVALID_ENCODED_DATA',
(enc) => `The encoded data was not valid for encoding ${enc}`);
E('ERR_HTTP_HEADERS_SENT',
'Cannot render headers after they are sent to the client');
'Cannot %s headers after they are sent to the client');
E('ERR_HTTP_INVALID_STATUS_CODE', 'Invalid status code: %s');
E('ERR_HTTP_TRAILER_INVALID',
'Trailers are invalid with this transfer encoding');
Expand Down Expand Up @@ -190,7 +190,7 @@ E('ERR_INVALID_ARRAY_LENGTH',
});
E('ERR_INVALID_BUFFER_SIZE', 'Buffer size must be a multiple of %s');
E('ERR_INVALID_CALLBACK', 'Callback must be a function');
E('ERR_INVALID_CHAR', 'Invalid character in %s');
E('ERR_INVALID_CHAR', invalidChar);
E('ERR_INVALID_CURSOR_POS',
'Cannot set cursor row without setting its column');
E('ERR_INVALID_DOMAIN_NAME', 'Unable to determine the domain name');
Expand All @@ -199,7 +199,7 @@ E('ERR_INVALID_FILE_URL_HOST',
'File URL host must be "localhost" or empty on %s');
E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s');
E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent');
E('ERR_INVALID_HTTP_TOKEN', (name) => `${name} must be a valid HTTP token`);
E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]');
E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s');
E('ERR_INVALID_OPT_VALUE',
(name, value) => {
Expand All @@ -222,6 +222,7 @@ E('ERR_IPC_CHANNEL_CLOSED', 'Channel closed');
E('ERR_IPC_DISCONNECTED', 'IPC channel is already disconnected');
E('ERR_IPC_ONE_PIPE', 'Child process can have only one IPC pipe');
E('ERR_IPC_SYNC_FORK', 'IPC cannot be used with synchronous forks');
E('ERR_METHOD_NOT_IMPLEMENTED', 'The %s method is not implemented');
E('ERR_MISSING_ARGS', missingArgs);
E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');
E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function');
Expand Down Expand Up @@ -342,3 +343,11 @@ function bufferOutOfBounds(name, isWriting) {
return `"${name}" is outside of buffer bounds`;
}
}

function invalidChar(name, field) {
let msg = `Invalid character in ${name}`;
if (field) {
msg += ` ["${field}"]`;
}
return msg;
}
73 changes: 49 additions & 24 deletions test/parallel/test-http-mutable-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,38 @@ const s = http.createServer(common.mustCall((req, res) => {
assert.deepStrictEqual(res.hasHeader('Connection'), false);
assert.deepStrictEqual(res.getHeader('Connection'), undefined);

assert.throws(() => {
res.setHeader();
}, /^TypeError: Header name must be a valid HTTP Token \["undefined"\]$/);
assert.throws(() => {
res.setHeader('someHeader');
}, /^Error: "value" required in setHeader\("someHeader", value\)$/);
assert.throws(() => {
res.getHeader();
}, /^TypeError: "name" argument must be a string$/);
assert.throws(() => {
res.removeHeader();
}, /^TypeError: "name" argument must be a string$/);
common.expectsError(
() => res.setHeader(),
{
code: 'ERR_INVALID_HTTP_TOKEN',
type: TypeError,
message: 'Header name must be a valid HTTP token ["undefined"]'
}
);
common.expectsError(
() => res.setHeader('someHeader'),
{
code: 'ERR_MISSING_ARGS',
type: TypeError,
message: 'The "value" argument must be specified'
}
);
common.expectsError(
() => res.getHeader(),
{
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
message: 'The "name" argument must be of type string'
}
);
common.expectsError(
() => res.removeHeader(),
{
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
message: 'The "name" argument must be of type string'
}
);

const arrayValues = [1, 2, 3];
res.setHeader('x-test-header', 'testing');
Expand Down Expand Up @@ -89,18 +109,23 @@ const s = http.createServer(common.mustCall((req, res) => {
assert.strictEqual(res.hasHeader('x-test-header2'), true);
assert.strictEqual(res.hasHeader('X-TEST-HEADER2'), true);
assert.strictEqual(res.hasHeader('X-Test-Header2'), true);
assert.throws(() => {
res.hasHeader();
}, /^TypeError: "name" argument must be a string$/);
assert.throws(() => {
res.hasHeader(null);
}, /^TypeError: "name" argument must be a string$/);
assert.throws(() => {
res.hasHeader(true);
}, /^TypeError: "name" argument must be a string$/);
assert.throws(() => {
res.hasHeader({ toString: () => 'X-TEST-HEADER2' });
}, /^TypeError: "name" argument must be a string$/);
[
undefined,
null,
true,
{},
{ toString: () => 'X-TEST-HEADER2' },
() => { }
].forEach((val) => {
common.expectsError(
() => res.hasHeader(val),
{
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
message: 'The "name" argument must be of type string'
}
);
});

res.removeHeader('x-test-header2');

Expand Down
Loading

0 comments on commit 11a2ca2

Please sign in to comment.