mirror of https://github.com/nodejs/node.git
http: expose http.validate-header-name/value
The use-case is for any framework that provides user mw a response replacement, that collects the desired response state, and applies them only on conclusion. As such a framework, I'd want to validate the header names and values as soon as the user-code provides them. This - to eliminate errors on response-send time, and provide developer stack trace that contains the line that submits the offending values. PR-URL: https://github.com/nodejs/node/pull/33119 Reviewed-By: Anna Henningsen <anna@addaleax.net>pull/33322/head
parent
d8a380e136
commit
96faea137e
|
@ -2469,6 +2469,76 @@ events will be emitted in the following order:
|
|||
Setting the `timeout` option or using the `setTimeout()` function will
|
||||
not abort the request or do anything besides add a `'timeout'` event.
|
||||
|
||||
## `http.validateHeaderName(name)`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* `name` {string}
|
||||
|
||||
Performs the low-level validations on the provided `name` that are done when
|
||||
`res.setHeader(name, value)` is called.
|
||||
|
||||
Passing illegal value as `name` will result in a [`TypeError`][] being thrown,
|
||||
identified by `code: 'ERR_INVALID_HTTP_TOKEN'`.
|
||||
|
||||
It is not necessary to use this method before passing headers to an HTTP request
|
||||
or response. The HTTP module will automatically validate such headers.
|
||||
Examples:
|
||||
|
||||
Example:
|
||||
```js
|
||||
const { validateHeaderName } = require('http');
|
||||
|
||||
try {
|
||||
validateHeaderName('');
|
||||
} catch (err) {
|
||||
err instanceof TypeError; // --> true
|
||||
err.code; // --> 'ERR_INVALID_HTTP_TOKEN'
|
||||
err.message; // --> 'Header name must be a valid HTTP token [""]'
|
||||
}
|
||||
```
|
||||
|
||||
## `http.validateHeaderValue(name, value)`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* `name` {string}
|
||||
* `value` {any}
|
||||
|
||||
Performs the low-level validations on the provided `value` that are done when
|
||||
`res.setHeader(name, value)` is called.
|
||||
|
||||
Passing illegal value as `value` will result in a [`TypeError`][] being thrown.
|
||||
* Undefined value error is identified by `code: 'ERR_HTTP_INVALID_HEADER_VALUE'`.
|
||||
* Invalid value character error is identified by `code: 'ERR_INVALID_CHAR'`.
|
||||
|
||||
It is not necessary to use this method before passing headers to an HTTP request
|
||||
or response. The HTTP module will automatically validate such headers.
|
||||
|
||||
Examples:
|
||||
|
||||
```js
|
||||
const { validateHeaderValue } = require('http');
|
||||
|
||||
try {
|
||||
validateHeaderValue('x-my-header', undefined);
|
||||
} catch (err) {
|
||||
err instanceof TypeError; // --> true
|
||||
err.code === 'ERR_HTTP_INVALID_HEADER_VALUE'; // --> true
|
||||
err.message; // --> 'Invalid value "undefined" for header "x-my-header"'
|
||||
}
|
||||
|
||||
try {
|
||||
validateHeaderValue('x-my-header', 'oʊmɪɡə');
|
||||
} catch (err) {
|
||||
err instanceof TypeError; // --> true
|
||||
err.code === 'ERR_INVALID_CHAR'; // --> true
|
||||
err.message; // --> 'Invalid character in header content ["x-my-header"]'
|
||||
}
|
||||
```
|
||||
|
||||
[`--insecure-http-parser`]: cli.html#cli_insecure_http_parser
|
||||
[`--max-http-header-size`]: cli.html#cli_max_http_header_size_size
|
||||
[`'checkContinue'`]: #http_event_checkcontinue
|
||||
|
|
|
@ -916,6 +916,9 @@ function(err, event) {
|
|||
this.destroy(err);
|
||||
};
|
||||
|
||||
OutgoingMessage.validateHeaderName = validateHeaderName;
|
||||
OutgoingMessage.validateHeaderValue = validateHeaderValue;
|
||||
|
||||
module.exports = {
|
||||
OutgoingMessage
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@ const { ClientRequest } = require('_http_client');
|
|||
const { methods } = require('_http_common');
|
||||
const { IncomingMessage } = require('_http_incoming');
|
||||
const { OutgoingMessage } = require('_http_outgoing');
|
||||
const { validateHeaderName, validateHeaderValue } = OutgoingMessage;
|
||||
const {
|
||||
_connectionListener,
|
||||
STATUS_CODES,
|
||||
|
@ -63,6 +64,8 @@ module.exports = {
|
|||
Server,
|
||||
ServerResponse,
|
||||
createServer,
|
||||
validateHeaderName,
|
||||
validateHeaderValue,
|
||||
get,
|
||||
request
|
||||
};
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const { validateHeaderName, validateHeaderValue } = require('http');
|
||||
|
||||
// Expected static methods
|
||||
isFunc(validateHeaderName, 'validateHeaderName');
|
||||
isFunc(validateHeaderValue, 'validateHeaderValue');
|
||||
|
||||
// Expected to be useful as static methods
|
||||
console.log('validateHeaderName');
|
||||
// - when used with valid header names - should not throw
|
||||
[
|
||||
'user-agent',
|
||||
'USER-AGENT',
|
||||
'User-Agent',
|
||||
'x-forwarded-for'
|
||||
].forEach((name) => {
|
||||
console.log('does not throw for "%s"', name);
|
||||
validateHeaderName(name);
|
||||
});
|
||||
|
||||
// - when used with invalid header names:
|
||||
[
|
||||
'איקס-פורוורד-פור',
|
||||
'x-forwarded-fםr',
|
||||
].forEach((name) => {
|
||||
console.log('throws for: "%s"', name.slice(0, 50));
|
||||
assert.throws(
|
||||
() => validateHeaderName(name),
|
||||
{ code: 'ERR_INVALID_HTTP_TOKEN' }
|
||||
);
|
||||
});
|
||||
|
||||
console.log('validateHeaderValue');
|
||||
// - when used with valid header values - should not throw
|
||||
[
|
||||
['x-valid', 1],
|
||||
['x-valid', '1'],
|
||||
['x-valid', 'string'],
|
||||
].forEach(([name, value]) => {
|
||||
console.log('does not throw for "%s"', name);
|
||||
validateHeaderValue(name, value);
|
||||
});
|
||||
|
||||
// - when used with invalid header values:
|
||||
[
|
||||
// [header, value, expectedCode]
|
||||
['x-undefined', undefined, 'ERR_HTTP_INVALID_HEADER_VALUE'],
|
||||
['x-bad-char', 'לא תקין', 'ERR_INVALID_CHAR'],
|
||||
].forEach(([name, value, code]) => {
|
||||
console.log('throws %s for: "%s: %s"', code, name, value);
|
||||
assert.throws(
|
||||
() => validateHeaderValue(name, value),
|
||||
{ code }
|
||||
);
|
||||
});
|
||||
|
||||
// Misc.
|
||||
function isFunc(v, ttl) {
|
||||
assert.ok(v.constructor === Function, `${ttl} is expected to be a function`);
|
||||
}
|
Loading…
Reference in New Issue