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:
Antoine du Hamel 2020-11-17 12:54:37 +01:00
parent e57d8af7e2
commit 8cf5ae07e9
8 changed files with 147 additions and 88 deletions

View File

@ -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];

View File

@ -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();

View File

@ -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) {

View File

@ -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];
}

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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() {