mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
http2: remove prototype primordials
Co-authored-by: Yagiz Nizipli <yagiz@nizipli.com> PR-URL: https://github.com/nodejs/node/pull/53696 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
parent
5a775b3b9e
commit
88beb76e5c
@ -4,8 +4,13 @@ The file `lib/internal/per_context/primordials.js` subclasses and stores the JS
|
|||||||
built-ins that come from the VM so that Node.js built-in modules do not need to
|
built-ins that come from the VM so that Node.js built-in modules do not need to
|
||||||
later look these up from the global proxy, which can be mutated by users.
|
later look these up from the global proxy, which can be mutated by users.
|
||||||
|
|
||||||
Usage of primordials should be preferred for any new code, but replacing current
|
For some area of the codebase, performance and code readability are deemed more
|
||||||
code with primordials should be
|
important than reliability against prototype pollution:
|
||||||
|
|
||||||
|
* `node:http2`
|
||||||
|
|
||||||
|
Usage of primordials should be preferred for new code in other areas, but
|
||||||
|
replacing current code with primordials should be
|
||||||
[done with care](#primordials-with-known-performance-issues). It is highly
|
[done with care](#primordials-with-known-performance-issues). It is highly
|
||||||
recommended to ping the relevant team when reviewing a pull request that touches
|
recommended to ping the relevant team when reviewing a pull request that touches
|
||||||
one of the subsystems they "own".
|
one of the subsystems they "own".
|
||||||
|
@ -5,6 +5,32 @@ import {
|
|||||||
noRestrictedSyntaxCommonLib,
|
noRestrictedSyntaxCommonLib,
|
||||||
} from '../tools/eslint/eslint.config_utils.mjs';
|
} from '../tools/eslint/eslint.config_utils.mjs';
|
||||||
|
|
||||||
|
const noRestrictedSyntax = [
|
||||||
|
'error',
|
||||||
|
...noRestrictedSyntaxCommonAll,
|
||||||
|
...noRestrictedSyntaxCommonLib,
|
||||||
|
{
|
||||||
|
selector: "CallExpression[callee.object.name='assert']:not([callee.property.name='ok']):not([callee.property.name='fail']):not([callee.property.name='ifError'])",
|
||||||
|
message: 'Please only use simple assertions in ./lib',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: 'NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])',
|
||||||
|
message: 'Use an error exported by the internal/errors module.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']",
|
||||||
|
message: "Please use `require('internal/errors').hideStackFrames()` instead.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "AssignmentExpression:matches([left.object.name='Error']):matches([left.name='prepareStackTrace'], [left.property.name='prepareStackTrace'])",
|
||||||
|
message: "Use 'overrideStackTrace' from 'lib/internal/errors.js' instead of 'Error.prepareStackTrace'.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "ThrowStatement > NewExpression[callee.name=/^ERR_[A-Z_]+$/] > ObjectExpression:first-child:not(:has([key.name='message']):has([key.name='code']):has([key.name='syscall']))",
|
||||||
|
message: 'The context passed into SystemError constructor must have .code, .syscall and .message.',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
files: ['lib/**/*.js'],
|
files: ['lib/**/*.js'],
|
||||||
@ -22,31 +48,7 @@ export default [
|
|||||||
rules: {
|
rules: {
|
||||||
'prefer-object-spread': 'error',
|
'prefer-object-spread': 'error',
|
||||||
'no-buffer-constructor': 'error',
|
'no-buffer-constructor': 'error',
|
||||||
'no-restricted-syntax': [
|
'no-restricted-syntax': noRestrictedSyntax,
|
||||||
'error',
|
|
||||||
...noRestrictedSyntaxCommonAll,
|
|
||||||
...noRestrictedSyntaxCommonLib,
|
|
||||||
{
|
|
||||||
selector: "CallExpression[callee.object.name='assert']:not([callee.property.name='ok']):not([callee.property.name='fail']):not([callee.property.name='ifError'])",
|
|
||||||
message: 'Please only use simple assertions in ./lib',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selector: 'NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])',
|
|
||||||
message: 'Use an error exported by the internal/errors module.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selector: "CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']",
|
|
||||||
message: "Please use `require('internal/errors').hideStackFrames()` instead.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selector: "AssignmentExpression:matches([left.object.name='Error']):matches([left.name='prepareStackTrace'], [left.property.name='prepareStackTrace'])",
|
|
||||||
message: "Use 'overrideStackTrace' from 'lib/internal/errors.js' instead of 'Error.prepareStackTrace'.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selector: "ThrowStatement > NewExpression[callee.name=/^ERR_[A-Z_]+$/] > ObjectExpression:first-child:not(:has([key.name='message']):has([key.name='code']):has([key.name='syscall']))",
|
|
||||||
message: 'The context passed into SystemError constructor must have .code, .syscall and .message.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-restricted-globals': [
|
'no-restricted-globals': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
@ -487,4 +489,19 @@ export default [
|
|||||||
'node-core/set-proto-to-null-in-object': 'error',
|
'node-core/set-proto-to-null-in-object': 'error',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'lib/internal/http2/*.js',
|
||||||
|
'lib/http2.js',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'no-restricted-syntax': [
|
||||||
|
...noRestrictedSyntax,
|
||||||
|
{
|
||||||
|
selector: 'VariableDeclarator:has(.init[name="primordials"]) Identifier[name=/Prototype/]:not([name=/^(Object|Reflect)(Get|Set)PrototypeOf$/])',
|
||||||
|
message: 'We do not use prototype primordials in this file',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
@ -2,19 +2,13 @@
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
ArrayIsArray,
|
ArrayIsArray,
|
||||||
ArrayPrototypePush,
|
|
||||||
Boolean,
|
Boolean,
|
||||||
FunctionPrototypeBind,
|
|
||||||
ObjectAssign,
|
ObjectAssign,
|
||||||
|
ObjectHasOwn,
|
||||||
ObjectKeys,
|
ObjectKeys,
|
||||||
ObjectPrototypeHasOwnProperty,
|
|
||||||
Proxy,
|
Proxy,
|
||||||
ReflectApply,
|
ReflectApply,
|
||||||
ReflectGetPrototypeOf,
|
ReflectGetPrototypeOf,
|
||||||
SafeArrayIterator,
|
|
||||||
StringPrototypeIncludes,
|
|
||||||
StringPrototypeToLowerCase,
|
|
||||||
StringPrototypeTrim,
|
|
||||||
Symbol,
|
Symbol,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
@ -89,7 +83,7 @@ let statusConnectionHeaderWarned = false;
|
|||||||
const assertValidHeader = hideStackFrames((name, value) => {
|
const assertValidHeader = hideStackFrames((name, value) => {
|
||||||
if (name === '' ||
|
if (name === '' ||
|
||||||
typeof name !== 'string' ||
|
typeof name !== 'string' ||
|
||||||
StringPrototypeIncludes(name, ' ')) {
|
name.includes(' ')) {
|
||||||
throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError('Header name', name);
|
throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError('Header name', name);
|
||||||
}
|
}
|
||||||
if (isPseudoHeader(name)) {
|
if (isPseudoHeader(name)) {
|
||||||
@ -153,8 +147,7 @@ function onStreamTrailers(trailers, flags, rawTrailers) {
|
|||||||
const request = this[kRequest];
|
const request = this[kRequest];
|
||||||
if (request !== undefined) {
|
if (request !== undefined) {
|
||||||
ObjectAssign(request[kTrailers], trailers);
|
ObjectAssign(request[kTrailers], trailers);
|
||||||
ArrayPrototypePush(request[kRawTrailers],
|
request[kRawTrailers].push(...rawTrailers);
|
||||||
...new SafeArrayIterator(rawTrailers));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +209,7 @@ const proxySocketHandler = {
|
|||||||
case 'end':
|
case 'end':
|
||||||
case 'emit':
|
case 'emit':
|
||||||
case 'destroy':
|
case 'destroy':
|
||||||
return FunctionPrototypeBind(stream[prop], stream);
|
return stream[prop].bind(stream);
|
||||||
case 'writable':
|
case 'writable':
|
||||||
case 'destroyed':
|
case 'destroyed':
|
||||||
return stream[prop];
|
return stream[prop];
|
||||||
@ -229,8 +222,8 @@ const proxySocketHandler = {
|
|||||||
case 'setTimeout': {
|
case 'setTimeout': {
|
||||||
const session = stream.session;
|
const session = stream.session;
|
||||||
if (session !== undefined)
|
if (session !== undefined)
|
||||||
return FunctionPrototypeBind(session.setTimeout, session);
|
return session.setTimeout.bind(session);
|
||||||
return FunctionPrototypeBind(stream.setTimeout, stream);
|
return stream.setTimeout.bind(stream);
|
||||||
}
|
}
|
||||||
case 'write':
|
case 'write':
|
||||||
case 'read':
|
case 'read':
|
||||||
@ -242,7 +235,7 @@ const proxySocketHandler = {
|
|||||||
stream.session[kSocket] : stream;
|
stream.session[kSocket] : stream;
|
||||||
const value = ref[prop];
|
const value = ref[prop];
|
||||||
return typeof value === 'function' ?
|
return typeof value === 'function' ?
|
||||||
FunctionPrototypeBind(value, ref) :
|
value.bind(ref) :
|
||||||
value;
|
value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,7 +410,7 @@ class Http2ServerRequest extends Readable {
|
|||||||
|
|
||||||
set method(method) {
|
set method(method) {
|
||||||
validateString(method, 'method');
|
validateString(method, 'method');
|
||||||
if (StringPrototypeTrim(method) === '')
|
if (method.trim() === '')
|
||||||
throw new ERR_INVALID_ARG_VALUE('method', method);
|
throw new ERR_INVALID_ARG_VALUE('method', method);
|
||||||
|
|
||||||
this[kHeaders][HTTP2_HEADER_METHOD] = method;
|
this[kHeaders][HTTP2_HEADER_METHOD] = method;
|
||||||
@ -578,7 +571,7 @@ class Http2ServerResponse extends Stream {
|
|||||||
|
|
||||||
setTrailer(name, value) {
|
setTrailer(name, value) {
|
||||||
validateString(name, 'name');
|
validateString(name, 'name');
|
||||||
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
|
name = name.trim().toLowerCase();
|
||||||
assertValidHeader(name, value);
|
assertValidHeader(name, value);
|
||||||
this[kTrailers][name] = value;
|
this[kTrailers][name] = value;
|
||||||
}
|
}
|
||||||
@ -594,7 +587,7 @@ class Http2ServerResponse extends Stream {
|
|||||||
|
|
||||||
getHeader(name) {
|
getHeader(name) {
|
||||||
validateString(name, 'name');
|
validateString(name, 'name');
|
||||||
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
|
name = name.trim().toLowerCase();
|
||||||
return this[kHeaders][name];
|
return this[kHeaders][name];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,8 +602,8 @@ class Http2ServerResponse extends Stream {
|
|||||||
|
|
||||||
hasHeader(name) {
|
hasHeader(name) {
|
||||||
validateString(name, 'name');
|
validateString(name, 'name');
|
||||||
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
|
name = name.trim().toLowerCase();
|
||||||
return ObjectPrototypeHasOwnProperty(this[kHeaders], name);
|
return ObjectHasOwn(this[kHeaders], name);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeHeader(name) {
|
removeHeader(name) {
|
||||||
@ -618,7 +611,7 @@ class Http2ServerResponse extends Stream {
|
|||||||
if (this[kStream].headersSent)
|
if (this[kStream].headersSent)
|
||||||
throw new ERR_HTTP2_HEADERS_SENT();
|
throw new ERR_HTTP2_HEADERS_SENT();
|
||||||
|
|
||||||
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
|
name = name.trim().toLowerCase();
|
||||||
|
|
||||||
if (name === 'date') {
|
if (name === 'date') {
|
||||||
this[kState].sendDate = false;
|
this[kState].sendDate = false;
|
||||||
@ -638,7 +631,7 @@ class Http2ServerResponse extends Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[kSetHeader](name, value) {
|
[kSetHeader](name, value) {
|
||||||
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
|
name = name.trim().toLowerCase();
|
||||||
assertValidHeader(name, value);
|
assertValidHeader(name, value);
|
||||||
|
|
||||||
if (!isConnectionHeaderAllowed(name, value)) {
|
if (!isConnectionHeaderAllowed(name, value)) {
|
||||||
@ -662,7 +655,7 @@ class Http2ServerResponse extends Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[kAppendHeader](name, value) {
|
[kAppendHeader](name, value) {
|
||||||
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
|
name = name.trim().toLowerCase();
|
||||||
assertValidHeader(name, value);
|
assertValidHeader(name, value);
|
||||||
|
|
||||||
if (!isConnectionHeaderAllowed(name, value)) {
|
if (!isConnectionHeaderAllowed(name, value)) {
|
||||||
|
@ -3,34 +3,24 @@
|
|||||||
const {
|
const {
|
||||||
ArrayFrom,
|
ArrayFrom,
|
||||||
ArrayIsArray,
|
ArrayIsArray,
|
||||||
ArrayPrototypeForEach,
|
|
||||||
ArrayPrototypePush,
|
|
||||||
ArrayPrototypeUnshift,
|
|
||||||
FunctionPrototypeBind,
|
|
||||||
FunctionPrototypeCall,
|
|
||||||
MathMin,
|
MathMin,
|
||||||
Number,
|
Number,
|
||||||
ObjectAssign,
|
ObjectAssign,
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ObjectEntries,
|
ObjectEntries,
|
||||||
|
ObjectHasOwn,
|
||||||
ObjectKeys,
|
ObjectKeys,
|
||||||
ObjectPrototypeHasOwnProperty,
|
|
||||||
Promise,
|
Promise,
|
||||||
PromisePrototypeThen,
|
|
||||||
Proxy,
|
Proxy,
|
||||||
ReflectApply,
|
ReflectApply,
|
||||||
ReflectGet,
|
ReflectGet,
|
||||||
ReflectGetPrototypeOf,
|
ReflectGetPrototypeOf,
|
||||||
ReflectSet,
|
ReflectSet,
|
||||||
RegExpPrototypeExec,
|
|
||||||
SafeArrayIterator,
|
|
||||||
SafeMap,
|
SafeMap,
|
||||||
SafeSet,
|
SafeSet,
|
||||||
StringPrototypeSlice,
|
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolAsyncDispose,
|
SymbolAsyncDispose,
|
||||||
SymbolDispose,
|
SymbolDispose,
|
||||||
TypedArrayPrototypeGetLength,
|
|
||||||
Uint32Array,
|
Uint32Array,
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
@ -205,22 +195,22 @@ function debugStream(id, sessionType, message, ...args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debug('Http2Stream %s [Http2Session %s]: ' + message,
|
debug('Http2Stream %s [Http2Session %s]: ' + message,
|
||||||
id, sessionName(sessionType), ...new SafeArrayIterator(args));
|
id, sessionName(sessionType), ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugStreamObj(stream, message, ...args) {
|
function debugStreamObj(stream, message, ...args) {
|
||||||
const session = stream[kSession];
|
const session = stream[kSession];
|
||||||
const type = session ? session[kType] : undefined;
|
const type = session ? session[kType] : undefined;
|
||||||
debugStream(stream[kID], type, message, ...new SafeArrayIterator(args));
|
debugStream(stream[kID], type, message, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugSession(sessionType, message, ...args) {
|
function debugSession(sessionType, message, ...args) {
|
||||||
debug('Http2Session %s: ' + message, sessionName(sessionType),
|
debug('Http2Session %s: ' + message, sessionName(sessionType),
|
||||||
...new SafeArrayIterator(args));
|
...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugSessionObj(session, message, ...args) {
|
function debugSessionObj(session, message, ...args) {
|
||||||
debugSession(session[kType], message, ...new SafeArrayIterator(args));
|
debugSession(session[kType], message, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
const kMaxFrameSize = (2 ** 24) - 1;
|
const kMaxFrameSize = (2 ** 24) - 1;
|
||||||
@ -826,8 +816,7 @@ function submitSettings(settings, callback) {
|
|||||||
debugSessionObj(this, 'submitting settings');
|
debugSessionObj(this, 'submitting settings');
|
||||||
this[kUpdateTimer]();
|
this[kUpdateTimer]();
|
||||||
updateSettingsBuffer(settings);
|
updateSettingsBuffer(settings);
|
||||||
if (!this[kHandle].settings(FunctionPrototypeBind(settingsCallback,
|
if (!this[kHandle].settings(settingsCallback.bind(this, callback))) {
|
||||||
this, callback))) {
|
|
||||||
this.destroy(new ERR_HTTP2_MAX_PENDING_SETTINGS_ACK());
|
this.destroy(new ERR_HTTP2_MAX_PENDING_SETTINGS_ACK());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -869,7 +858,7 @@ const proxySocketHandler = {
|
|||||||
case 'setTimeout':
|
case 'setTimeout':
|
||||||
case 'ref':
|
case 'ref':
|
||||||
case 'unref':
|
case 'unref':
|
||||||
return FunctionPrototypeBind(session[prop], session);
|
return session[prop].bind(session);
|
||||||
case 'destroy':
|
case 'destroy':
|
||||||
case 'emit':
|
case 'emit':
|
||||||
case 'end':
|
case 'end':
|
||||||
@ -887,7 +876,7 @@ const proxySocketHandler = {
|
|||||||
throw new ERR_HTTP2_SOCKET_UNBOUND();
|
throw new ERR_HTTP2_SOCKET_UNBOUND();
|
||||||
const value = socket[prop];
|
const value = socket[prop];
|
||||||
return typeof value === 'function' ?
|
return typeof value === 'function' ?
|
||||||
FunctionPrototypeBind(value, socket) :
|
value.bind(socket) :
|
||||||
value;
|
value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -998,7 +987,7 @@ const validateSettings = hideStackFrames((settings) => {
|
|||||||
// Wrap a typed array in a proxy, and allow selectively copying the entries
|
// Wrap a typed array in a proxy, and allow selectively copying the entries
|
||||||
// that have explicitly been set to another typed array.
|
// that have explicitly been set to another typed array.
|
||||||
function trackAssignmentsTypedArray(typedArray) {
|
function trackAssignmentsTypedArray(typedArray) {
|
||||||
const typedArrayLength = TypedArrayPrototypeGetLength(typedArray);
|
const typedArrayLength = typedArray.length;
|
||||||
const modifiedEntries = new Uint8Array(typedArrayLength);
|
const modifiedEntries = new Uint8Array(typedArrayLength);
|
||||||
|
|
||||||
function copyAssigned(target) {
|
function copyAssigned(target) {
|
||||||
@ -1183,8 +1172,7 @@ function closeSession(session, code, error) {
|
|||||||
|
|
||||||
// Destroy the handle if it exists at this point.
|
// Destroy the handle if it exists at this point.
|
||||||
if (handle !== undefined) {
|
if (handle !== undefined) {
|
||||||
handle.ondone = FunctionPrototypeBind(finishSessionClose,
|
handle.ondone = finishSessionClose.bind(null, session, error);
|
||||||
null, session, error);
|
|
||||||
handle.destroy(code, socket.destroyed);
|
handle.destroy(code, socket.destroyed);
|
||||||
} else {
|
} else {
|
||||||
finishSessionClose(session, error);
|
finishSessionClose(session, error);
|
||||||
@ -1276,8 +1264,7 @@ class Http2Session extends EventEmitter {
|
|||||||
if (typeof socket.disableRenegotiation === 'function')
|
if (typeof socket.disableRenegotiation === 'function')
|
||||||
socket.disableRenegotiation();
|
socket.disableRenegotiation();
|
||||||
|
|
||||||
const setupFn = FunctionPrototypeBind(setupHandle, this,
|
const setupFn = setupHandle.bind(this, socket, type, options);
|
||||||
socket, type, options);
|
|
||||||
if (socket.connecting || socket.secureConnecting) {
|
if (socket.connecting || socket.secureConnecting) {
|
||||||
const connectEvent =
|
const connectEvent =
|
||||||
socket instanceof tls.TLSSocket ? 'secureConnect' : 'connect';
|
socket instanceof tls.TLSSocket ? 'secureConnect' : 'connect';
|
||||||
@ -1512,8 +1499,7 @@ class Http2Session extends EventEmitter {
|
|||||||
|
|
||||||
this[kState].pendingAck++;
|
this[kState].pendingAck++;
|
||||||
|
|
||||||
const settingsFn = FunctionPrototypeBind(submitSettings, this,
|
const settingsFn = submitSettings.bind(this, { ...settings }, callback);
|
||||||
{ ...settings }, callback);
|
|
||||||
if (this.connecting) {
|
if (this.connecting) {
|
||||||
this.once('connect', settingsFn);
|
this.once('connect', settingsFn);
|
||||||
return;
|
return;
|
||||||
@ -1535,9 +1521,7 @@ class Http2Session extends EventEmitter {
|
|||||||
validateNumber(code, 'code');
|
validateNumber(code, 'code');
|
||||||
validateNumber(lastStreamID, 'lastStreamID');
|
validateNumber(lastStreamID, 'lastStreamID');
|
||||||
|
|
||||||
const goawayFn = FunctionPrototypeBind(submitGoaway,
|
const goawayFn = submitGoaway.bind(this, code, lastStreamID, opaqueData);
|
||||||
this,
|
|
||||||
code, lastStreamID, opaqueData);
|
|
||||||
if (this.connecting) {
|
if (this.connecting) {
|
||||||
this.once('connect', goawayFn);
|
this.once('connect', goawayFn);
|
||||||
return;
|
return;
|
||||||
@ -1693,7 +1677,7 @@ class ServerHttp2Session extends Http2Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validateString(alt, 'alt');
|
validateString(alt, 'alt');
|
||||||
if (RegExpPrototypeExec(kQuotedString, alt) === null)
|
if (!kQuotedString.test(alt))
|
||||||
throw new ERR_INVALID_CHAR('alt');
|
throw new ERR_INVALID_CHAR('alt');
|
||||||
|
|
||||||
// Max length permitted for ALTSVC
|
// Max length permitted for ALTSVC
|
||||||
@ -1786,8 +1770,7 @@ class ClientHttp2Session extends Http2Session {
|
|||||||
if (getAuthority(headers) === undefined)
|
if (getAuthority(headers) === undefined)
|
||||||
headers[HTTP2_HEADER_AUTHORITY] = this[kAuthority];
|
headers[HTTP2_HEADER_AUTHORITY] = this[kAuthority];
|
||||||
if (headers[HTTP2_HEADER_SCHEME] === undefined)
|
if (headers[HTTP2_HEADER_SCHEME] === undefined)
|
||||||
headers[HTTP2_HEADER_SCHEME] = StringPrototypeSlice(this[kProtocol],
|
headers[HTTP2_HEADER_SCHEME] = this[kProtocol].slice(0, -1);
|
||||||
0, -1);
|
|
||||||
if (headers[HTTP2_HEADER_PATH] === undefined)
|
if (headers[HTTP2_HEADER_PATH] === undefined)
|
||||||
headers[HTTP2_HEADER_PATH] = '/';
|
headers[HTTP2_HEADER_PATH] = '/';
|
||||||
} else {
|
} else {
|
||||||
@ -1839,15 +1822,14 @@ class ClientHttp2Session extends Http2Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onConnect = FunctionPrototypeBind(requestOnConnect,
|
const onConnect = requestOnConnect.bind(stream, headersList, options);
|
||||||
stream, headersList, options);
|
|
||||||
if (this.connecting) {
|
if (this.connecting) {
|
||||||
if (this[kPendingRequestCalls] !== null) {
|
if (this[kPendingRequestCalls] !== null) {
|
||||||
ArrayPrototypePush(this[kPendingRequestCalls], onConnect);
|
this[kPendingRequestCalls].push(onConnect);
|
||||||
} else {
|
} else {
|
||||||
this[kPendingRequestCalls] = [onConnect];
|
this[kPendingRequestCalls] = [onConnect];
|
||||||
this.once('connect', () => {
|
this.once('connect', () => {
|
||||||
ArrayPrototypeForEach(this[kPendingRequestCalls], (f) => f());
|
this[kPendingRequestCalls].forEach((f) => f());
|
||||||
this[kPendingRequestCalls] = null;
|
this[kPendingRequestCalls] = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1951,7 +1933,7 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rstStreamStatus !== kNoRstStream) {
|
if (rstStreamStatus !== kNoRstStream) {
|
||||||
const finishFn = FunctionPrototypeBind(finishCloseStream, stream, code);
|
const finishFn = finishCloseStream.bind(stream, code);
|
||||||
if (!ending || stream.writableFinished || code !== NGHTTP2_NO_ERROR ||
|
if (!ending || stream.writableFinished || code !== NGHTTP2_NO_ERROR ||
|
||||||
rstStreamStatus === kForceRstStream)
|
rstStreamStatus === kForceRstStream)
|
||||||
finishFn();
|
finishFn();
|
||||||
@ -1961,7 +1943,7 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function finishCloseStream(code) {
|
function finishCloseStream(code) {
|
||||||
const rstStreamFn = FunctionPrototypeBind(submitRstStream, this, code);
|
const rstStreamFn = submitRstStream.bind(this, code);
|
||||||
// If the handle has not yet been assigned, queue up the request to
|
// If the handle has not yet been assigned, queue up the request to
|
||||||
// ensure that the RST_STREAM frame is sent after the stream ID has
|
// ensure that the RST_STREAM frame is sent after the stream ID has
|
||||||
// been determined.
|
// been determined.
|
||||||
@ -2145,8 +2127,7 @@ class Http2Stream extends Duplex {
|
|||||||
if (this.pending) {
|
if (this.pending) {
|
||||||
this.once(
|
this.once(
|
||||||
'ready',
|
'ready',
|
||||||
FunctionPrototypeBind(this[kWriteGeneric],
|
this[kWriteGeneric].bind(this, writev, data, encoding, cb),
|
||||||
this, writev, data, encoding, cb),
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2238,7 +2219,7 @@ class Http2Stream extends Duplex {
|
|||||||
this[kState].didRead = true;
|
this[kState].didRead = true;
|
||||||
}
|
}
|
||||||
if (!this.pending) {
|
if (!this.pending) {
|
||||||
FunctionPrototypeCall(streamOnResume, this);
|
streamOnResume.call(this);
|
||||||
} else {
|
} else {
|
||||||
this.once('ready', streamOnResume);
|
this.once('ready', streamOnResume);
|
||||||
}
|
}
|
||||||
@ -2252,7 +2233,7 @@ class Http2Stream extends Duplex {
|
|||||||
options = { ...options };
|
options = { ...options };
|
||||||
setAndValidatePriorityOptions(options);
|
setAndValidatePriorityOptions(options);
|
||||||
|
|
||||||
const priorityFn = FunctionPrototypeBind(submitPriority, this, options);
|
const priorityFn = submitPriority.bind(this, options);
|
||||||
|
|
||||||
// If the handle has not yet been assigned, queue up the priority
|
// If the handle has not yet been assigned, queue up the priority
|
||||||
// frame to be sent as soon as the ready event is emitted.
|
// frame to be sent as soon as the ready event is emitted.
|
||||||
@ -2455,7 +2436,7 @@ function processHeaders(oldHeaders, options) {
|
|||||||
if (oldHeaders !== null && oldHeaders !== undefined) {
|
if (oldHeaders !== null && oldHeaders !== undefined) {
|
||||||
// This loop is here for performance reason. Do not change.
|
// This loop is here for performance reason. Do not change.
|
||||||
for (const key in oldHeaders) {
|
for (const key in oldHeaders) {
|
||||||
if (ObjectPrototypeHasOwnProperty(oldHeaders, key)) {
|
if (ObjectHasOwn(oldHeaders, key)) {
|
||||||
headers[key] = oldHeaders[key];
|
headers[key] = oldHeaders[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2493,8 +2474,7 @@ function processHeaders(oldHeaders, options) {
|
|||||||
function onFileUnpipe() {
|
function onFileUnpipe() {
|
||||||
const stream = this.sink[kOwner];
|
const stream = this.sink[kOwner];
|
||||||
if (stream.ownsFd)
|
if (stream.ownsFd)
|
||||||
PromisePrototypeThen(this.source.close(), undefined,
|
this.source.close().catch(stream.destroy.bind(stream));
|
||||||
FunctionPrototypeBind(stream.destroy, stream));
|
|
||||||
else
|
else
|
||||||
this.source.releaseFD();
|
this.source.releaseFD();
|
||||||
}
|
}
|
||||||
@ -2677,9 +2657,7 @@ function afterOpen(session, options, headers, streamOptions, err, fd) {
|
|||||||
state.fd = fd;
|
state.fd = fd;
|
||||||
|
|
||||||
fs.fstat(fd,
|
fs.fstat(fd,
|
||||||
FunctionPrototypeBind(doSendFileFD, this,
|
doSendFileFD.bind(this, session, options, fd, headers, streamOptions));
|
||||||
session, options, fd,
|
|
||||||
headers, streamOptions));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServerHttp2Stream extends Http2Stream {
|
class ServerHttp2Stream extends Http2Stream {
|
||||||
@ -2882,9 +2860,7 @@ class ServerHttp2Stream extends Http2Stream {
|
|||||||
|
|
||||||
if (options.statCheck !== undefined) {
|
if (options.statCheck !== undefined) {
|
||||||
fs.fstat(fd,
|
fs.fstat(fd,
|
||||||
FunctionPrototypeBind(doSendFD, this,
|
doSendFD.bind(this, session, options, fd, headers, streamOptions));
|
||||||
session, options, fd,
|
|
||||||
headers, streamOptions));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2943,8 +2919,7 @@ class ServerHttp2Stream extends Http2Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs.open(path, 'r',
|
fs.open(path, 'r',
|
||||||
FunctionPrototypeBind(afterOpen, this,
|
afterOpen.bind(this, session, options, headers, streamOptions));
|
||||||
session, options, headers, streamOptions));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a block of informational headers. In theory, the HTTP/2 spec
|
// Sends a block of informational headers. In theory, the HTTP/2 spec
|
||||||
@ -2980,7 +2955,7 @@ class ServerHttp2Stream extends Http2Stream {
|
|||||||
if (!this[kInfoHeaders])
|
if (!this[kInfoHeaders])
|
||||||
this[kInfoHeaders] = [headers];
|
this[kInfoHeaders] = [headers];
|
||||||
else
|
else
|
||||||
ArrayPrototypePush(this[kInfoHeaders], headers);
|
this[kInfoHeaders].push(headers);
|
||||||
|
|
||||||
const ret = this[kHandle].info(headersList);
|
const ret = this[kHandle].info(headersList);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -3066,7 +3041,7 @@ function connectionListener(socket) {
|
|||||||
if (options.allowHTTP1 === true) {
|
if (options.allowHTTP1 === true) {
|
||||||
socket.server[kIncomingMessage] = options.Http1IncomingMessage;
|
socket.server[kIncomingMessage] = options.Http1IncomingMessage;
|
||||||
socket.server[kServerResponse] = options.Http1ServerResponse;
|
socket.server[kServerResponse] = options.Http1ServerResponse;
|
||||||
return FunctionPrototypeCall(httpConnectionListener, this, socket);
|
return httpConnectionListener.call(this, socket);
|
||||||
}
|
}
|
||||||
// Let event handler deal with the socket
|
// Let event handler deal with the socket
|
||||||
debug('Unknown protocol from %s:%s',
|
debug('Unknown protocol from %s:%s',
|
||||||
@ -3164,7 +3139,7 @@ function initializeTLSOptions(options, servername) {
|
|||||||
options = initializeOptions(options);
|
options = initializeOptions(options);
|
||||||
options.ALPNProtocols = ['h2'];
|
options.ALPNProtocols = ['h2'];
|
||||||
if (options.allowHTTP1 === true)
|
if (options.allowHTTP1 === true)
|
||||||
ArrayPrototypePush(options.ALPNProtocols, 'http/1.1');
|
options.ALPNProtocols.push('http/1.1');
|
||||||
if (servername !== undefined && !options.servername)
|
if (servername !== undefined && !options.servername)
|
||||||
options.servername = servername;
|
options.servername = servername;
|
||||||
return options;
|
return options;
|
||||||
@ -3249,7 +3224,7 @@ class Http2Server extends NETServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async [SymbolAsyncDispose]() {
|
async [SymbolAsyncDispose]() {
|
||||||
return FunctionPrototypeCall(promisify(super.close), this);
|
return promisify(super.close).call(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3284,7 +3259,7 @@ Http2Server.prototype[EventEmitter.captureRejectionSymbol] = function(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
ArrayPrototypeUnshift(args, err, event);
|
args.unshift(err, event);
|
||||||
ReflectApply(net.Server.prototype[EventEmitter.captureRejectionSymbol],
|
ReflectApply(net.Server.prototype[EventEmitter.captureRejectionSymbol],
|
||||||
this, args);
|
this, args);
|
||||||
}
|
}
|
||||||
@ -3293,11 +3268,8 @@ Http2Server.prototype[EventEmitter.captureRejectionSymbol] = function(
|
|||||||
function setupCompat(ev) {
|
function setupCompat(ev) {
|
||||||
if (ev === 'request') {
|
if (ev === 'request') {
|
||||||
this.removeListener('newListener', setupCompat);
|
this.removeListener('newListener', setupCompat);
|
||||||
this.on('stream', FunctionPrototypeBind(onServerStream,
|
this.on('stream', onServerStream.bind(this, this[kOptions].Http2ServerRequest,
|
||||||
this,
|
this[kOptions].Http2ServerResponse));
|
||||||
this[kOptions].Http2ServerRequest,
|
|
||||||
this[kOptions].Http2ServerResponse),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3344,7 +3316,7 @@ function connect(authority, options, listener) {
|
|||||||
host = authority.hostname;
|
host = authority.hostname;
|
||||||
|
|
||||||
if (host[0] === '[')
|
if (host[0] === '[')
|
||||||
host = StringPrototypeSlice(host, 1, -1);
|
host = host.slice(1, -1);
|
||||||
} else if (authority.host) {
|
} else if (authority.host) {
|
||||||
host = authority.host;
|
host = authority.host;
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
ArrayIsArray,
|
ArrayIsArray,
|
||||||
ArrayPrototypeIncludes,
|
|
||||||
ArrayPrototypeMap,
|
|
||||||
ArrayPrototypePush,
|
|
||||||
Error,
|
Error,
|
||||||
MathMax,
|
MathMax,
|
||||||
Number,
|
Number,
|
||||||
@ -13,8 +10,6 @@ const {
|
|||||||
SafeSet,
|
SafeSet,
|
||||||
String,
|
String,
|
||||||
StringFromCharCode,
|
StringFromCharCode,
|
||||||
StringPrototypeIncludes,
|
|
||||||
StringPrototypeToLowerCase,
|
|
||||||
Symbol,
|
Symbol,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
@ -602,15 +597,13 @@ function mapToHeaders(map,
|
|||||||
let value;
|
let value;
|
||||||
let isSingleValueHeader;
|
let isSingleValueHeader;
|
||||||
let err;
|
let err;
|
||||||
const neverIndex =
|
const neverIndex = (map[kSensitiveHeaders] || emptyArray).map((v) => v.toLowerCase());
|
||||||
ArrayPrototypeMap(map[kSensitiveHeaders] || emptyArray,
|
|
||||||
StringPrototypeToLowerCase);
|
|
||||||
for (i = 0; i < keys.length; ++i) {
|
for (i = 0; i < keys.length; ++i) {
|
||||||
key = keys[i];
|
key = keys[i];
|
||||||
value = map[key];
|
value = map[key];
|
||||||
if (value === undefined || key === '')
|
if (value === undefined || key === '')
|
||||||
continue;
|
continue;
|
||||||
key = StringPrototypeToLowerCase(key);
|
key = key.toLowerCase();
|
||||||
isSingleValueHeader = kSingleValueHeaders.has(key);
|
isSingleValueHeader = kSingleValueHeaders.has(key);
|
||||||
isArray = ArrayIsArray(value);
|
isArray = ArrayIsArray(value);
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
@ -633,7 +626,7 @@ function mapToHeaders(map,
|
|||||||
throw new ERR_HTTP2_HEADER_SINGLE_VALUE(key);
|
throw new ERR_HTTP2_HEADER_SINGLE_VALUE(key);
|
||||||
singles.add(key);
|
singles.add(key);
|
||||||
}
|
}
|
||||||
const flags = ArrayPrototypeIncludes(neverIndex, key) ?
|
const flags = neverIndex.includes(key) ?
|
||||||
kNeverIndexFlag :
|
kNeverIndexFlag :
|
||||||
kNoHeaderFlags;
|
kNoHeaderFlags;
|
||||||
if (key[0] === ':') {
|
if (key[0] === ':') {
|
||||||
@ -644,7 +637,7 @@ function mapToHeaders(map,
|
|||||||
count++;
|
count++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (StringPrototypeIncludes(key, ' ')) {
|
if (key.includes(' ')) {
|
||||||
throw new ERR_INVALID_HTTP_TOKEN('Header name', key);
|
throw new ERR_INVALID_HTTP_TOKEN('Header name', key);
|
||||||
}
|
}
|
||||||
if (isIllegalConnectionSpecificHeader(key, value)) {
|
if (isIllegalConnectionSpecificHeader(key, value)) {
|
||||||
@ -738,7 +731,7 @@ function toHeaderObject(headers, sensitiveHeaders) {
|
|||||||
// fields with the same name. Since it cannot be combined into a
|
// fields with the same name. Since it cannot be combined into a
|
||||||
// single field-value, recipients ought to handle "Set-Cookie" as a
|
// single field-value, recipients ought to handle "Set-Cookie" as a
|
||||||
// special case while processing header fields."
|
// special case while processing header fields."
|
||||||
ArrayPrototypePush(existing, value);
|
existing.push(value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// https://tools.ietf.org/html/rfc7230#section-3.2.2
|
// https://tools.ietf.org/html/rfc7230#section-3.2.2
|
||||||
|
Loading…
Reference in New Issue
Block a user