mirror of
https://github.com/nodejs/node.git
synced 2025-12-28 07:50:41 +00:00
http: refactor to use more primordials
PR-URL: https://github.com/nodejs/node/pull/36194 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
parent
e57d8af7e2
commit
8cf5ae07e9
@ -22,11 +22,22 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
ArrayPrototypeIncludes,
|
||||
ArrayPrototypeIndexOf,
|
||||
ArrayPrototypePop,
|
||||
ArrayPrototypePush,
|
||||
ArrayPrototypeShift,
|
||||
ArrayPrototypeSplice,
|
||||
FunctionPrototypeCall,
|
||||
NumberIsNaN,
|
||||
ObjectCreate,
|
||||
ObjectKeys,
|
||||
ObjectSetPrototypeOf,
|
||||
ObjectValues,
|
||||
StringPrototypeIndexOf,
|
||||
StringPrototypeSplit,
|
||||
StringPrototypeStartsWith,
|
||||
StringPrototypeSubstr,
|
||||
Symbol,
|
||||
} = primordials;
|
||||
|
||||
@ -79,7 +90,7 @@ function Agent(options) {
|
||||
if (!(this instanceof Agent))
|
||||
return new Agent(options);
|
||||
|
||||
EventEmitter.call(this);
|
||||
FunctionPrototypeCall(EventEmitter, this);
|
||||
|
||||
this.defaultPort = 80;
|
||||
this.protocol = 'http:';
|
||||
@ -126,7 +137,7 @@ function Agent(options) {
|
||||
|
||||
const requests = this.requests[name];
|
||||
if (requests && requests.length) {
|
||||
const req = requests.shift();
|
||||
const req = ArrayPrototypeShift(requests);
|
||||
const reqAsyncRes = req[kRequestAsyncResource];
|
||||
if (reqAsyncRes) {
|
||||
// Run request within the original async context.
|
||||
@ -172,7 +183,7 @@ function Agent(options) {
|
||||
this.removeSocket(socket, options);
|
||||
|
||||
socket.once('error', freeSocketErrorListener);
|
||||
freeSockets.push(socket);
|
||||
ArrayPrototypePush(freeSockets, socket);
|
||||
});
|
||||
|
||||
// Don't emit keylog events unless there is a listener for them.
|
||||
@ -251,11 +262,11 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */,
|
||||
let socket;
|
||||
if (freeSockets) {
|
||||
while (freeSockets.length && freeSockets[0].destroyed) {
|
||||
freeSockets.shift();
|
||||
ArrayPrototypeShift(freeSockets);
|
||||
}
|
||||
socket = this.scheduling === 'fifo' ?
|
||||
freeSockets.shift() :
|
||||
freeSockets.pop();
|
||||
ArrayPrototypeShift(freeSockets) :
|
||||
ArrayPrototypePop(freeSockets);
|
||||
if (!freeSockets.length)
|
||||
delete this.freeSockets[name];
|
||||
}
|
||||
@ -267,7 +278,7 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */,
|
||||
asyncResetHandle(socket);
|
||||
this.reuseSocket(socket, req);
|
||||
setRequestSocket(this, req, socket);
|
||||
this.sockets[name].push(socket);
|
||||
ArrayPrototypePush(this.sockets[name], socket);
|
||||
this.totalSocketCount++;
|
||||
} else if (sockLen < this.maxSockets &&
|
||||
this.totalSocketCount < this.maxTotalSockets) {
|
||||
@ -291,7 +302,7 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */,
|
||||
// Used to capture the original async context.
|
||||
req[kRequestAsyncResource] = new AsyncResource('QueuedRequest');
|
||||
|
||||
this.requests[name].push(req);
|
||||
ArrayPrototypePush(this.requests[name], req);
|
||||
}
|
||||
};
|
||||
|
||||
@ -315,7 +326,7 @@ Agent.prototype.createSocket = function createSocket(req, options, cb) {
|
||||
if (!this.sockets[name]) {
|
||||
this.sockets[name] = [];
|
||||
}
|
||||
this.sockets[name].push(s);
|
||||
ArrayPrototypePush(this.sockets[name], s);
|
||||
this.totalSocketCount++;
|
||||
debug('sockets', name, this.sockets[name].length, this.totalSocketCount);
|
||||
installListeners(this, s, options);
|
||||
@ -340,16 +351,16 @@ function calculateServerName(options, req) {
|
||||
// abc:123 => abc
|
||||
// [::1] => ::1
|
||||
// [::1]:123 => ::1
|
||||
if (hostHeader.startsWith('[')) {
|
||||
const index = hostHeader.indexOf(']');
|
||||
if (StringPrototypeStartsWith(hostHeader, '[')) {
|
||||
const index = StringPrototypeIndexOf(hostHeader, ']');
|
||||
if (index === -1) {
|
||||
// Leading '[', but no ']'. Need to do something...
|
||||
servername = hostHeader;
|
||||
} else {
|
||||
servername = hostHeader.substr(1, index - 1);
|
||||
servername = StringPrototypeSubstr(hostHeader, 1, index - 1);
|
||||
}
|
||||
} else {
|
||||
servername = hostHeader.split(':', 1)[0];
|
||||
servername = StringPrototypeSplit(hostHeader, ':', 1)[0];
|
||||
}
|
||||
}
|
||||
// Don't implicitly set invalid (IP) servernames.
|
||||
@ -381,7 +392,7 @@ function installListeners(agent, s, options) {
|
||||
// TODO(ronag): Always destroy, even if not in free list.
|
||||
const sockets = agent.freeSockets;
|
||||
for (const name of ObjectKeys(sockets)) {
|
||||
if (sockets[name].includes(s)) {
|
||||
if (ArrayPrototypeIncludes(sockets[name], s)) {
|
||||
return s.destroy();
|
||||
}
|
||||
}
|
||||
@ -413,13 +424,13 @@ Agent.prototype.removeSocket = function removeSocket(s, options) {
|
||||
|
||||
// If the socket was destroyed, remove it from the free buffers too.
|
||||
if (!s.writable)
|
||||
sets.push(this.freeSockets);
|
||||
ArrayPrototypePush(sets, this.freeSockets);
|
||||
|
||||
for (const sockets of sets) {
|
||||
if (sockets[name]) {
|
||||
const index = sockets[name].indexOf(s);
|
||||
const index = ArrayPrototypeIndexOf(sockets[name], s);
|
||||
if (index !== -1) {
|
||||
sockets[name].splice(index, 1);
|
||||
ArrayPrototypeSplice(sockets[name], index, 1);
|
||||
// Don't leak
|
||||
if (sockets[name].length === 0)
|
||||
delete sockets[name];
|
||||
|
||||
@ -25,12 +25,20 @@ const {
|
||||
ArrayIsArray,
|
||||
Boolean,
|
||||
Error,
|
||||
FunctionPrototypeCall,
|
||||
NumberIsFinite,
|
||||
ObjectAssign,
|
||||
ObjectKeys,
|
||||
ObjectSetPrototypeOf,
|
||||
ReflectApply,
|
||||
RegExpPrototypeTest,
|
||||
String,
|
||||
Symbol
|
||||
StringPrototypeCharCodeAt,
|
||||
StringPrototypeIncludes,
|
||||
StringPrototypeIndexOf,
|
||||
StringPrototypeToUpperCase,
|
||||
Symbol,
|
||||
TypedArrayPrototypeSlice,
|
||||
} = primordials;
|
||||
|
||||
const net = require('net');
|
||||
@ -91,7 +99,7 @@ class HTTPClientAsyncResource {
|
||||
|
||||
let urlWarningEmitted = false;
|
||||
function ClientRequest(input, options, cb) {
|
||||
OutgoingMessage.call(this);
|
||||
FunctionPrototypeCall(OutgoingMessage, this);
|
||||
|
||||
if (typeof input === 'string') {
|
||||
const urlStr = input;
|
||||
@ -151,7 +159,7 @@ function ClientRequest(input, options, cb) {
|
||||
|
||||
if (options.path) {
|
||||
const path = String(options.path);
|
||||
if (INVALID_PATH_REGEX.test(path))
|
||||
if (RegExpPrototypeTest(INVALID_PATH_REGEX, path))
|
||||
throw new ERR_UNESCAPED_CHARACTERS('Request path');
|
||||
}
|
||||
|
||||
@ -187,7 +195,7 @@ function ClientRequest(input, options, cb) {
|
||||
if (!checkIsHttpToken(method)) {
|
||||
throw new ERR_INVALID_HTTP_TOKEN('Method', method);
|
||||
}
|
||||
method = this.method = method.toUpperCase();
|
||||
method = this.method = StringPrototypeToUpperCase(method);
|
||||
} else {
|
||||
method = this.method = 'GET';
|
||||
}
|
||||
@ -266,10 +274,10 @@ function ClientRequest(input, options, cb) {
|
||||
// For the Host header, ensure that IPv6 addresses are enclosed
|
||||
// in square brackets, as defined by URI formatting
|
||||
// https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
const posColon = hostHeader.indexOf(':');
|
||||
const posColon = StringPrototypeIndexOf(hostHeader, ':');
|
||||
if (posColon !== -1 &&
|
||||
hostHeader.includes(':', posColon + 1) &&
|
||||
hostHeader.charCodeAt(0) !== 91/* '[' */) {
|
||||
StringPrototypeIncludes(hostHeader, ':', posColon + 1) &&
|
||||
StringPrototypeCharCodeAt(hostHeader, 0) !== 91/* '[' */) {
|
||||
hostHeader = `[${hostHeader}]`;
|
||||
}
|
||||
|
||||
@ -337,7 +345,7 @@ ObjectSetPrototypeOf(ClientRequest, OutgoingMessage);
|
||||
|
||||
ClientRequest.prototype._finish = function _finish() {
|
||||
DTRACE_HTTP_CLIENT_REQUEST(this, this.socket);
|
||||
OutgoingMessage.prototype._finish.call(this);
|
||||
FunctionPrototypeCall(OutgoingMessage.prototype._finish, this);
|
||||
};
|
||||
|
||||
ClientRequest.prototype._implicitHeader = function _implicitHeader() {
|
||||
@ -535,7 +543,7 @@ function socketOnData(d) {
|
||||
parser.finish();
|
||||
freeParser(parser, req, socket);
|
||||
|
||||
const bodyHead = d.slice(bytesParsed, d.length);
|
||||
const bodyHead = TypedArrayPrototypeSlice(d, bytesParsed, d.length);
|
||||
|
||||
const eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
|
||||
if (req.listenerCount(eventName) > 0) {
|
||||
@ -831,7 +839,7 @@ function _deferToConnect(method, arguments_, cb) {
|
||||
|
||||
const callSocketMethod = () => {
|
||||
if (method)
|
||||
this.socket[method].apply(this.socket, arguments_);
|
||||
ReflectApply(this.socket[method], this.socket, arguments_);
|
||||
|
||||
if (typeof cb === 'function')
|
||||
cb();
|
||||
|
||||
@ -22,8 +22,11 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
ArrayPrototypeConcat,
|
||||
MathMin,
|
||||
Symbol,
|
||||
RegExpPrototypeTest,
|
||||
TypedArrayPrototypeSlice,
|
||||
} = primordials;
|
||||
const { setImmediate } = require('timers');
|
||||
|
||||
@ -63,7 +66,7 @@ function parserOnHeaders(headers, url) {
|
||||
// Once we exceeded headers limit - stop collecting them
|
||||
if (this.maxHeaderPairs <= 0 ||
|
||||
this._headers.length < this.maxHeaderPairs) {
|
||||
this._headers = this._headers.concat(headers);
|
||||
this._headers = ArrayPrototypeConcat(this._headers, headers);
|
||||
}
|
||||
this._url += url;
|
||||
}
|
||||
@ -135,7 +138,7 @@ function parserOnBody(b, start, len) {
|
||||
|
||||
// Pretend this was the result of a stream._read call.
|
||||
if (len > 0 && !stream._dumped) {
|
||||
const slice = b.slice(start, start + len);
|
||||
const slice = TypedArrayPrototypeSlice(b, start, start + len);
|
||||
const ret = stream.push(slice);
|
||||
if (!ret)
|
||||
readStop(this.socket);
|
||||
@ -217,7 +220,7 @@ const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
|
||||
* See https://tools.ietf.org/html/rfc7230#section-3.2.6
|
||||
*/
|
||||
function checkIsHttpToken(val) {
|
||||
return tokenRegExp.test(val);
|
||||
return RegExpPrototypeTest(tokenRegExp, val);
|
||||
}
|
||||
|
||||
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
|
||||
@ -228,7 +231,7 @@ const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
|
||||
* field-vchar = VCHAR / obs-text
|
||||
*/
|
||||
function checkInvalidHeaderChar(val) {
|
||||
return headerCharRegex.test(val);
|
||||
return RegExpPrototypeTest(headerCharRegex, val);
|
||||
}
|
||||
|
||||
function cleanParser(parser) {
|
||||
|
||||
@ -22,8 +22,13 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
ArrayPrototypePush,
|
||||
FunctionPrototypeCall,
|
||||
ObjectDefineProperty,
|
||||
ObjectSetPrototypeOf,
|
||||
StringPrototypeCharCodeAt,
|
||||
StringPrototypeSlice,
|
||||
StringPrototypeToLowerCase,
|
||||
Symbol
|
||||
} = primordials;
|
||||
|
||||
@ -54,7 +59,7 @@ function IncomingMessage(socket) {
|
||||
};
|
||||
}
|
||||
|
||||
Readable.call(this, streamOptions);
|
||||
FunctionPrototypeCall(Readable, this, streamOptions);
|
||||
|
||||
this._readableState.readingMore = true;
|
||||
|
||||
@ -312,7 +317,7 @@ function matchKnownFields(field, lowercased) {
|
||||
if (lowercased) {
|
||||
return '\u0000' + field;
|
||||
}
|
||||
return matchKnownFields(field.toLowerCase(), true);
|
||||
return matchKnownFields(StringPrototypeToLowerCase(field), true);
|
||||
}
|
||||
// Add the given (field, value) pair to the message
|
||||
//
|
||||
@ -326,9 +331,9 @@ function matchKnownFields(field, lowercased) {
|
||||
IncomingMessage.prototype._addHeaderLine = _addHeaderLine;
|
||||
function _addHeaderLine(field, value, dest) {
|
||||
field = matchKnownFields(field);
|
||||
const flag = field.charCodeAt(0);
|
||||
const flag = StringPrototypeCharCodeAt(field, 0);
|
||||
if (flag === 0 || flag === 2) {
|
||||
field = field.slice(1);
|
||||
field = StringPrototypeSlice(field, 1);
|
||||
// Make a delimited list
|
||||
if (typeof dest[field] === 'string') {
|
||||
dest[field] += (flag === 0 ? ', ' : '; ') + value;
|
||||
@ -338,7 +343,7 @@ function _addHeaderLine(field, value, dest) {
|
||||
} else if (flag === 1) {
|
||||
// Array header -- only Set-Cookie at the moment
|
||||
if (dest['set-cookie'] !== undefined) {
|
||||
dest['set-cookie'].push(value);
|
||||
ArrayPrototypePush(dest['set-cookie'], value);
|
||||
} else {
|
||||
dest['set-cookie'] = [value];
|
||||
}
|
||||
|
||||
@ -23,12 +23,21 @@
|
||||
|
||||
const {
|
||||
ArrayIsArray,
|
||||
ArrayPrototypeJoin,
|
||||
ArrayPrototypePush,
|
||||
ArrayPrototypeUnshift,
|
||||
FunctionPrototype,
|
||||
FunctionPrototypeBind,
|
||||
FunctionPrototypeCall,
|
||||
MathFloor,
|
||||
NumberPrototypeToString,
|
||||
ObjectCreate,
|
||||
ObjectDefineProperty,
|
||||
ObjectKeys,
|
||||
ObjectPrototypeHasOwnProperty,
|
||||
ObjectSetPrototypeOf,
|
||||
MathFloor,
|
||||
RegExpPrototypeTest,
|
||||
StringPrototypeToLowerCase,
|
||||
Symbol,
|
||||
} = primordials;
|
||||
|
||||
@ -72,7 +81,7 @@ const { CRLF, debug } = common;
|
||||
|
||||
const kCorked = Symbol('corked');
|
||||
|
||||
function nop() {}
|
||||
const nop = FunctionPrototype;
|
||||
|
||||
const RE_CONN_CLOSE = /(?:^|\W)close(?:$|\W)/i;
|
||||
const RE_TE_CHUNKED = common.chunkExpression;
|
||||
@ -81,13 +90,11 @@ const RE_TE_CHUNKED = common.chunkExpression;
|
||||
// against the word "cookie." As of V8 6.6 this is faster than handrolling or
|
||||
// using a case-insensitive RegExp.
|
||||
function isCookieField(s) {
|
||||
return s.length === 6 && s.toLowerCase() === 'cookie';
|
||||
return s.length === 6 && StringPrototypeToLowerCase(s) === 'cookie';
|
||||
}
|
||||
|
||||
function noopPendingOutput(amount) {}
|
||||
|
||||
function OutgoingMessage() {
|
||||
Stream.call(this);
|
||||
FunctionPrototypeCall(Stream, this);
|
||||
|
||||
// Queue that holds all currently pending data, until the response will be
|
||||
// assigned to the socket (until it will its turn in the HTTP pipeline).
|
||||
@ -128,7 +135,7 @@ function OutgoingMessage() {
|
||||
|
||||
this._keepAliveTimeout = 0;
|
||||
|
||||
this._onPendingData = noopPendingOutput;
|
||||
this._onPendingData = nop;
|
||||
}
|
||||
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
|
||||
ObjectSetPrototypeOf(OutgoingMessage, Stream);
|
||||
@ -182,7 +189,7 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headers', {
|
||||
// Refs: https://github.com/nodejs/node/pull/30958
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const name = keys[i];
|
||||
headers[name.toLowerCase()] = [name, val[name]];
|
||||
headers[StringPrototypeToLowerCase(name)] = [name, val[name]];
|
||||
}
|
||||
}
|
||||
}, 'OutgoingMessage.prototype._headers is deprecated', 'DEP0066')
|
||||
@ -317,7 +324,7 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) {
|
||||
data = this._header + data;
|
||||
} else {
|
||||
const header = this._header;
|
||||
this.outputData.unshift({
|
||||
ArrayPrototypeUnshift(this.outputData, {
|
||||
data: header,
|
||||
encoding: 'latin1',
|
||||
callback: null
|
||||
@ -354,7 +361,7 @@ function _writeRaw(data, encoding, callback) {
|
||||
return conn.write(data, encoding, callback);
|
||||
}
|
||||
// Buffer, as long as we're not destroyed.
|
||||
this.outputData.push({ data, encoding, callback });
|
||||
ArrayPrototypePush(this.outputData, { data, encoding, callback });
|
||||
this.outputSize += data.length;
|
||||
this._onPendingData(data.length);
|
||||
return this.outputSize < HIGH_WATER_MARK;
|
||||
@ -497,7 +504,7 @@ function processHeader(self, state, key, value, validate) {
|
||||
storeHeader(self, state, key, value[i], validate);
|
||||
return;
|
||||
}
|
||||
value = value.join('; ');
|
||||
value = ArrayPrototypeJoin(value, '; ');
|
||||
}
|
||||
storeHeader(self, state, key, value, validate);
|
||||
}
|
||||
@ -512,12 +519,12 @@ function storeHeader(self, state, key, value, validate) {
|
||||
function matchHeader(self, state, field, value) {
|
||||
if (field.length < 4 || field.length > 17)
|
||||
return;
|
||||
field = field.toLowerCase();
|
||||
field = StringPrototypeToLowerCase(field);
|
||||
switch (field) {
|
||||
case 'connection':
|
||||
state.connection = true;
|
||||
self._removedConnection = false;
|
||||
if (RE_CONN_CLOSE.test(value))
|
||||
if (RegExpPrototypeTest(RE_CONN_CLOSE, value))
|
||||
self._last = true;
|
||||
else
|
||||
self.shouldKeepAlive = true;
|
||||
@ -525,7 +532,8 @@ function matchHeader(self, state, field, value) {
|
||||
case 'transfer-encoding':
|
||||
state.te = true;
|
||||
self._removedTE = false;
|
||||
if (RE_TE_CHUNKED.test(value)) self.chunkedEncoding = true;
|
||||
if (RegExpPrototypeTest(RE_TE_CHUNKED, value))
|
||||
self.chunkedEncoding = true;
|
||||
break;
|
||||
case 'content-length':
|
||||
state.contLen = true;
|
||||
@ -569,7 +577,7 @@ OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
|
||||
if (headers === null)
|
||||
this[kOutHeaders] = headers = ObjectCreate(null);
|
||||
|
||||
headers[name.toLowerCase()] = [name, value];
|
||||
headers[StringPrototypeToLowerCase(name)] = [name, value];
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -581,7 +589,7 @@ OutgoingMessage.prototype.getHeader = function getHeader(name) {
|
||||
if (headers === null)
|
||||
return;
|
||||
|
||||
const entry = headers[name.toLowerCase()];
|
||||
const entry = headers[StringPrototypeToLowerCase(name)];
|
||||
return entry && entry[1];
|
||||
};
|
||||
|
||||
@ -613,7 +621,7 @@ OutgoingMessage.prototype.getHeaders = function getHeaders() {
|
||||
OutgoingMessage.prototype.hasHeader = function hasHeader(name) {
|
||||
validateString(name, 'name');
|
||||
return this[kOutHeaders] !== null &&
|
||||
!!this[kOutHeaders][name.toLowerCase()];
|
||||
!!this[kOutHeaders][StringPrototypeToLowerCase(name)];
|
||||
};
|
||||
|
||||
|
||||
@ -624,7 +632,7 @@ OutgoingMessage.prototype.removeHeader = function removeHeader(name) {
|
||||
throw new ERR_HTTP_HEADERS_SENT('remove');
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
const key = StringPrototypeToLowerCase(name);
|
||||
|
||||
switch (key) {
|
||||
case 'connection':
|
||||
@ -750,7 +758,7 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
|
||||
|
||||
let ret;
|
||||
if (msg.chunkedEncoding && chunk.length !== 0) {
|
||||
msg._send(len.toString(16), 'latin1', null);
|
||||
msg._send(NumberPrototypeToString(len, 16), 'latin1', null);
|
||||
msg._send(crlf_buf, null, null);
|
||||
msg._send(chunk, encoding, null);
|
||||
ret = msg._send(crlf_buf, null, callback);
|
||||
@ -839,7 +847,7 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
|
||||
if (typeof callback === 'function')
|
||||
this.once('finish', callback);
|
||||
|
||||
const finish = onFinish.bind(undefined, this);
|
||||
const finish = FunctionPrototypeBind(onFinish, undefined, this);
|
||||
|
||||
if (this._hasBody && this.chunkedEncoding) {
|
||||
this._send('0\r\n' + this._trailer + '\r\n', 'latin1', finish);
|
||||
|
||||
@ -23,11 +23,19 @@
|
||||
|
||||
const {
|
||||
ArrayIsArray,
|
||||
ArrayPrototypePush,
|
||||
ArrayPrototypeShift,
|
||||
Error,
|
||||
FunctionPrototype,
|
||||
FunctionPrototypeBind,
|
||||
FunctionPrototypeCall,
|
||||
ObjectKeys,
|
||||
ObjectSetPrototypeOf,
|
||||
ReflectApply,
|
||||
RegExpPrototypeTest,
|
||||
Symbol,
|
||||
SymbolFor,
|
||||
TypedArrayPrototypeSlice,
|
||||
} = primordials;
|
||||
|
||||
const net = require('net');
|
||||
@ -169,7 +177,7 @@ class HTTPServerAsyncResource {
|
||||
}
|
||||
|
||||
function ServerResponse(req) {
|
||||
OutgoingMessage.call(this);
|
||||
FunctionPrototypeCall(OutgoingMessage, this);
|
||||
|
||||
if (req.method === 'HEAD') this._hasBody = false;
|
||||
|
||||
@ -178,7 +186,8 @@ function ServerResponse(req) {
|
||||
this._expect_continue = false;
|
||||
|
||||
if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) {
|
||||
this.useChunkedEncodingByDefault = chunkExpression.test(req.headers.te);
|
||||
this.useChunkedEncodingByDefault = RegExpPrototypeTest(chunkExpression,
|
||||
req.headers.te);
|
||||
this.shouldKeepAlive = false;
|
||||
}
|
||||
|
||||
@ -197,7 +206,7 @@ ServerResponse.prototype._finish = function _finish() {
|
||||
if (this[kServerResponseStatistics] !== undefined) {
|
||||
emitStatistics(this[kServerResponseStatistics]);
|
||||
}
|
||||
OutgoingMessage.prototype._finish.call(this);
|
||||
FunctionPrototypeCall(OutgoingMessage.prototype._finish, this);
|
||||
};
|
||||
|
||||
|
||||
@ -371,7 +380,7 @@ function Server(options, requestListener) {
|
||||
validateBoolean(insecureHTTPParser, 'options.insecureHTTPParser');
|
||||
this.insecureHTTPParser = insecureHTTPParser;
|
||||
|
||||
net.Server.call(this, { allowHalfOpen: true });
|
||||
FunctionPrototypeCall(net.Server, this, { allowHalfOpen: true });
|
||||
|
||||
if (requestListener) {
|
||||
this.on('request', requestListener);
|
||||
@ -417,8 +426,8 @@ Server.prototype[EE.captureRejectionSymbol] = function(err, event, ...args) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
net.Server.prototype[SymbolFor('nodejs.rejection')]
|
||||
.call(this, err, event, ...args);
|
||||
ReflectApply(net.Server.prototype[SymbolFor('nodejs.rejection')],
|
||||
this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
@ -477,16 +486,21 @@ function connectionListenerInternal(server, socket) {
|
||||
outgoingData: 0,
|
||||
keepAliveTimeoutSet: false
|
||||
};
|
||||
state.onData = socketOnData.bind(undefined, server, socket, parser, state);
|
||||
state.onEnd = socketOnEnd.bind(undefined, server, socket, parser, state);
|
||||
state.onClose = socketOnClose.bind(undefined, socket, state);
|
||||
state.onDrain = socketOnDrain.bind(undefined, socket, state);
|
||||
state.onData = FunctionPrototypeBind(socketOnData, undefined,
|
||||
server, socket, parser, state);
|
||||
state.onEnd = FunctionPrototypeBind(socketOnEnd, undefined,
|
||||
server, socket, parser, state);
|
||||
state.onClose = FunctionPrototypeBind(socketOnClose, undefined,
|
||||
socket, state);
|
||||
state.onDrain = FunctionPrototypeBind(socketOnDrain, undefined,
|
||||
socket, state);
|
||||
socket.on('data', state.onData);
|
||||
socket.on('error', socketOnError);
|
||||
socket.on('end', state.onEnd);
|
||||
socket.on('close', state.onClose);
|
||||
socket.on('drain', state.onDrain);
|
||||
parser.onIncoming = parserOnIncoming.bind(undefined, server, socket, state);
|
||||
parser.onIncoming = FunctionPrototypeBind(parserOnIncoming, undefined,
|
||||
server, socket, state);
|
||||
|
||||
// We are consuming socket, so it won't get any actual data
|
||||
socket.on('resume', onSocketResume);
|
||||
@ -506,15 +520,18 @@ function connectionListenerInternal(server, socket) {
|
||||
parser.consume(socket._handle);
|
||||
}
|
||||
parser[kOnExecute] =
|
||||
onParserExecute.bind(undefined, server, socket, parser, state);
|
||||
FunctionPrototypeBind(onParserExecute, undefined,
|
||||
server, socket, parser, state);
|
||||
|
||||
parser[kOnTimeout] =
|
||||
onParserTimeout.bind(undefined, server, socket);
|
||||
FunctionPrototypeBind(onParserTimeout, undefined,
|
||||
server, socket);
|
||||
|
||||
// When receiving new requests on the same socket (pipelining or keep alive)
|
||||
// make sure the requestTimeout is active.
|
||||
parser[kOnMessageBegin] =
|
||||
setRequestTimeout.bind(undefined, server, socket);
|
||||
FunctionPrototypeBind(setRequestTimeout, undefined,
|
||||
server, socket);
|
||||
|
||||
// This protects from DOS attack where an attacker establish the connection
|
||||
// without sending any data on applications where server.timeout is left to
|
||||
@ -574,7 +591,7 @@ function socketOnClose(socket, state) {
|
||||
|
||||
function abortIncoming(incoming) {
|
||||
while (incoming.length) {
|
||||
const req = incoming.shift();
|
||||
const req = ArrayPrototypeShift(incoming);
|
||||
req.destroy(connResetException('aborted'));
|
||||
}
|
||||
// Abort socket._httpMessage ?
|
||||
@ -585,7 +602,7 @@ function socketOnEnd(server, socket, parser, state) {
|
||||
|
||||
if (ret instanceof Error) {
|
||||
debug('parse error');
|
||||
socketOnError.call(socket, ret);
|
||||
FunctionPrototypeCall(socketOnError, socket, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -611,7 +628,7 @@ function socketOnData(server, socket, parser, state, d) {
|
||||
|
||||
function onRequestTimeout(socket) {
|
||||
socket[kRequestTimeout] = undefined;
|
||||
socketOnError.call(socket, new ERR_HTTP_REQUEST_TIMEOUT());
|
||||
ReflectApply(socketOnError, socket, [new ERR_HTTP_REQUEST_TIMEOUT()]);
|
||||
}
|
||||
|
||||
function onParserExecute(server, socket, parser, state, ret) {
|
||||
@ -631,7 +648,7 @@ function onParserTimeout(server, socket) {
|
||||
socket.destroy();
|
||||
}
|
||||
|
||||
const noop = () => {};
|
||||
const noop = FunctionPrototype;
|
||||
const badRequestResponse = Buffer.from(
|
||||
`HTTP/1.1 400 ${STATUS_CODES[400]}${CRLF}` +
|
||||
`Connection: close${CRLF}${CRLF}`, 'ascii'
|
||||
@ -678,7 +695,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
|
||||
prepareError(ret, parser, d);
|
||||
ret.rawPacket = d || parser.getCurrentBuffer();
|
||||
debug('parse error', ret);
|
||||
socketOnError.call(socket, ret);
|
||||
FunctionPrototypeCall(socketOnError, socket, ret);
|
||||
} else if (parser.incoming && parser.incoming.upgrade) {
|
||||
// Upgrade or CONNECT
|
||||
const req = parser.incoming;
|
||||
@ -701,7 +718,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
|
||||
const eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
|
||||
if (eventName === 'upgrade' || server.listenerCount(eventName) > 0) {
|
||||
debug('SERVER have listener for %s', eventName);
|
||||
const bodyHead = d.slice(ret, d.length);
|
||||
const bodyHead = TypedArrayPrototypeSlice(d, ret, d.length);
|
||||
|
||||
socket.readableFlowing = null;
|
||||
|
||||
@ -717,7 +734,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
|
||||
// When receiving new requests on the same socket (pipelining or keep alive)
|
||||
// make sure the requestTimeout is active.
|
||||
parser[kOnMessageBegin] =
|
||||
setRequestTimeout.bind(undefined, server, socket);
|
||||
FunctionPrototypeBind(setRequestTimeout, undefined, server, socket);
|
||||
}
|
||||
|
||||
if (socket._paused && socket.parser) {
|
||||
@ -781,7 +798,7 @@ function resOnFinish(req, res, socket, state, server) {
|
||||
// array will be empty.
|
||||
assert(state.incoming.length === 0 || state.incoming[0] === req);
|
||||
|
||||
state.incoming.shift();
|
||||
ArrayPrototypeShift(state.incoming);
|
||||
|
||||
// If the user never called req.read(), and didn't pipe() or
|
||||
// .resume() or .on('data'), then we call req._dump() so that the
|
||||
@ -814,7 +831,7 @@ function resOnFinish(req, res, socket, state, server) {
|
||||
}
|
||||
} else {
|
||||
// Start sending the next message
|
||||
const m = state.outgoing.shift();
|
||||
const m = ArrayPrototypeShift(state.outgoing);
|
||||
if (m) {
|
||||
m.assignSocket(socket);
|
||||
}
|
||||
@ -840,7 +857,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
state.incoming.push(req);
|
||||
ArrayPrototypePush(state.incoming, req);
|
||||
|
||||
// If the writable end isn't consuming, then stop reading
|
||||
// so that we don't become overwhelmed by a flood of
|
||||
@ -858,7 +875,8 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
|
||||
|
||||
const res = new server[kServerResponse](req);
|
||||
res._keepAliveTimeout = server.keepAliveTimeout;
|
||||
res._onPendingData = updateOutgoingData.bind(undefined, socket, state);
|
||||
res._onPendingData = FunctionPrototypeBind(updateOutgoingData, undefined,
|
||||
socket, state);
|
||||
|
||||
res.shouldKeepAlive = keepAlive;
|
||||
DTRACE_HTTP_SERVER_REQUEST(req, socket);
|
||||
@ -874,7 +892,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
|
||||
|
||||
if (socket._httpMessage) {
|
||||
// There are already pending outgoing res, append.
|
||||
state.outgoing.push(res);
|
||||
ArrayPrototypePush(state.outgoing, res);
|
||||
} else {
|
||||
res.assignSocket(socket);
|
||||
}
|
||||
@ -882,11 +900,12 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
|
||||
// When we're finished writing the response, check if this is the last
|
||||
// response, if so destroy the socket.
|
||||
res.on('finish',
|
||||
resOnFinish.bind(undefined, req, res, socket, state, server));
|
||||
FunctionPrototypeBind(resOnFinish, undefined,
|
||||
req, res, socket, state, server));
|
||||
|
||||
if (req.headers.expect !== undefined &&
|
||||
(req.httpVersionMajor === 1 && req.httpVersionMinor === 1)) {
|
||||
if (continueExpression.test(req.headers.expect)) {
|
||||
if (RegExpPrototypeTest(continueExpression, req.headers.expect)) {
|
||||
res._expect_continue = true;
|
||||
|
||||
if (server.listenerCount('checkContinue') > 0) {
|
||||
@ -954,7 +973,8 @@ function unconsume(parser, socket) {
|
||||
|
||||
function generateSocketListenerWrapper(originalFnName) {
|
||||
return function socketListenerWrap(ev, fn) {
|
||||
const res = net.Socket.prototype[originalFnName].call(this, ev, fn);
|
||||
const res = ReflectApply(net.Socket.prototype[originalFnName], this,
|
||||
[ev, fn]);
|
||||
if (!this.parser) {
|
||||
this.on = net.Socket.prototype.on;
|
||||
this.addListener = net.Socket.prototype.addListener;
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
ArrayPrototypeSlice,
|
||||
ArrayPrototypeSort,
|
||||
ObjectDefineProperty,
|
||||
} = primordials;
|
||||
|
||||
@ -58,7 +60,7 @@ function get(url, options, cb) {
|
||||
|
||||
module.exports = {
|
||||
_connectionListener,
|
||||
METHODS: methods.slice().sort(),
|
||||
METHODS: ArrayPrototypeSort(ArrayPrototypeSlice(methods)),
|
||||
STATUS_CODES,
|
||||
Agent: httpAgent.Agent,
|
||||
ClientRequest,
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
const {
|
||||
Symbol,
|
||||
Date,
|
||||
DatePrototypeGetMilliseconds,
|
||||
DatePrototypeToUTCString,
|
||||
} = primordials;
|
||||
|
||||
const { setUnrefTimeout } = require('internal/timers');
|
||||
@ -17,8 +19,8 @@ function utcDate() {
|
||||
|
||||
function cache() {
|
||||
const d = new Date();
|
||||
utcCache = d.toUTCString();
|
||||
setUnrefTimeout(resetCache, 1000 - d.getMilliseconds());
|
||||
utcCache = DatePrototypeToUTCString(d);
|
||||
setUnrefTimeout(resetCache, 1000 - DatePrototypeGetMilliseconds(d));
|
||||
}
|
||||
|
||||
function resetCache() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user