Break up huge function in ClientRequest.onSocket
This commit is contained in:
parent
884499d37e
commit
07d8a4650e
266
lib/http.js
266
lib/http.js
@ -105,6 +105,7 @@ function parserOnBody(b, start, len) {
|
|||||||
parser.incoming.emit('data', slice);
|
parser.incoming.emit('data', slice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parserOnMessageComplete() {
|
function parserOnMessageComplete() {
|
||||||
var parser = this;
|
var parser = this;
|
||||||
parser.incoming.complete = true;
|
parser.incoming.complete = true;
|
||||||
@ -490,7 +491,9 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
|
|||||||
// keep-alive logic
|
// keep-alive logic
|
||||||
if (sentConnectionHeader === false) {
|
if (sentConnectionHeader === false) {
|
||||||
if (this.shouldKeepAlive &&
|
if (this.shouldKeepAlive &&
|
||||||
(sentContentLengthHeader || this.useChunkedEncodingByDefault || this.agent)) {
|
(sentContentLengthHeader ||
|
||||||
|
this.useChunkedEncodingByDefault ||
|
||||||
|
this.agent)) {
|
||||||
messageHeader += 'Connection: keep-alive\r\n';
|
messageHeader += 'Connection: keep-alive\r\n';
|
||||||
} else {
|
} else {
|
||||||
this._last = true;
|
this._last = true;
|
||||||
@ -523,7 +526,7 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
|
|||||||
|
|
||||||
OutgoingMessage.prototype.setHeader = function(name, value) {
|
OutgoingMessage.prototype.setHeader = function(name, value) {
|
||||||
if (arguments.length < 2) {
|
if (arguments.length < 2) {
|
||||||
throw new Error("`name` and `value` are required for setHeader().");
|
throw new Error('`name` and `value` are required for setHeader().');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._header) {
|
if (this._header) {
|
||||||
@ -540,7 +543,7 @@ OutgoingMessage.prototype.setHeader = function(name, value) {
|
|||||||
|
|
||||||
OutgoingMessage.prototype.getHeader = function(name) {
|
OutgoingMessage.prototype.getHeader = function(name) {
|
||||||
if (arguments.length < 1) {
|
if (arguments.length < 1) {
|
||||||
throw new Error("`name` is required for getHeader().");
|
throw new Error('`name` is required for getHeader().');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._headers) return;
|
if (!this._headers) return;
|
||||||
@ -552,7 +555,7 @@ OutgoingMessage.prototype.getHeader = function(name) {
|
|||||||
|
|
||||||
OutgoingMessage.prototype.removeHeader = function(name) {
|
OutgoingMessage.prototype.removeHeader = function(name) {
|
||||||
if (arguments.length < 1) {
|
if (arguments.length < 1) {
|
||||||
throw new Error("`name` is required for removeHeader().");
|
throw new Error('`name` is required for removeHeader().');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._header) {
|
if (this._header) {
|
||||||
@ -1078,7 +1081,9 @@ function ClientRequest(options, cb) {
|
|||||||
self._last = true;
|
self._last = true;
|
||||||
self.shouldKeepAlive = false;
|
self.shouldKeepAlive = false;
|
||||||
if (options.createConnection) {
|
if (options.createConnection) {
|
||||||
self.onSocket(options.createConnection(options.port, options.host, options));
|
self.onSocket(options.createConnection(options.port,
|
||||||
|
options.host,
|
||||||
|
options));
|
||||||
} else {
|
} else {
|
||||||
self.onSocket(net.createConnection(options.port, options.host));
|
self.onSocket(net.createConnection(options.port, options.host));
|
||||||
}
|
}
|
||||||
@ -1095,7 +1100,8 @@ util.inherits(ClientRequest, OutgoingMessage);
|
|||||||
exports.ClientRequest = ClientRequest;
|
exports.ClientRequest = ClientRequest;
|
||||||
|
|
||||||
ClientRequest.prototype._implicitHeader = function() {
|
ClientRequest.prototype._implicitHeader = function() {
|
||||||
this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', this._renderHeaders());
|
this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
|
||||||
|
this._renderHeaders());
|
||||||
};
|
};
|
||||||
|
|
||||||
ClientRequest.prototype.abort = function() {
|
ClientRequest.prototype.abort = function() {
|
||||||
@ -1131,6 +1137,7 @@ function freeParser(parser, req) {
|
|||||||
if (parser.socket) {
|
if (parser.socket) {
|
||||||
parser.socket.onend = null;
|
parser.socket.onend = null;
|
||||||
parser.socket.ondata = null;
|
parser.socket.ondata = null;
|
||||||
|
parser.socket.parser = null;
|
||||||
}
|
}
|
||||||
parser.socket = null;
|
parser.socket = null;
|
||||||
parser.incoming = null;
|
parser.incoming = null;
|
||||||
@ -1140,91 +1147,12 @@ function freeParser(parser, req) {
|
|||||||
if (req) {
|
if (req) {
|
||||||
req.parser = null;
|
req.parser = null;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ClientRequest.prototype.onSocket = function(socket) {
|
|
||||||
var req = this;
|
|
||||||
process.nextTick(function() {
|
|
||||||
var parser = parsers.alloc();
|
|
||||||
req.socket = socket;
|
|
||||||
req.connection = socket;
|
|
||||||
parser.reinitialize(HTTPParser.RESPONSE);
|
|
||||||
parser.socket = socket;
|
|
||||||
parser.incoming = null;
|
|
||||||
req.parser = parser;
|
|
||||||
|
|
||||||
socket._httpMessage = req;
|
|
||||||
// Setup "drain" propogation.
|
|
||||||
httpSocketSetup(socket);
|
|
||||||
|
|
||||||
function errorListener(err) {
|
|
||||||
debug('HTTP SOCKET ERROR: ' + err.message + '\n' + err.stack);
|
|
||||||
if (req) {
|
|
||||||
req.emit('error', err);
|
|
||||||
// For Safety. Some additional errors might fire later on
|
|
||||||
// and we need to make sure we don't double-fire the error event.
|
|
||||||
req._hadError = true;
|
|
||||||
}
|
|
||||||
if (parser) {
|
|
||||||
parser.finish();
|
|
||||||
freeParser(parser, req);
|
|
||||||
}
|
|
||||||
socket.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.on('error', errorListener);
|
function socketCloseListener() {
|
||||||
|
var socket = this;
|
||||||
socket.ondata = function(d, start, end) {
|
var parser = socket.parser;
|
||||||
var ret = parser.execute(d, start, end - start);
|
var req = socket._httpMessage;
|
||||||
if (ret instanceof Error) {
|
|
||||||
debug('parse error');
|
|
||||||
freeParser(parser, req);
|
|
||||||
socket.destroy(ret);
|
|
||||||
} else if (parser.incoming && parser.incoming.upgrade) {
|
|
||||||
var bytesParsed = ret;
|
|
||||||
socket.ondata = null;
|
|
||||||
socket.onend = null;
|
|
||||||
|
|
||||||
var res = parser.incoming;
|
|
||||||
req.res = res;
|
|
||||||
|
|
||||||
// This is start + byteParsed
|
|
||||||
var upgradeHead = d.slice(start + bytesParsed, end);
|
|
||||||
if (req.listeners('upgrade').length) {
|
|
||||||
// Emit 'upgrade' on the Agent.
|
|
||||||
req.upgraded = true;
|
|
||||||
req.emit('upgrade', res, socket, upgradeHead);
|
|
||||||
socket.emit('agentRemove');
|
|
||||||
} else {
|
|
||||||
// Got upgrade header, but have no handler.
|
|
||||||
socket.destroy();
|
|
||||||
}
|
|
||||||
freeParser(parser, req);
|
|
||||||
} else if (parser.incoming && parser.incoming.complete &&
|
|
||||||
// When the status code is 100 (Continue), the server will
|
|
||||||
// send a final response after this client sends a request
|
|
||||||
// body. So, we must not free the parser.
|
|
||||||
parser.incoming.statusCode !== 100) {
|
|
||||||
freeParser(parser, req);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.onend = function() {
|
|
||||||
if (!req.res) {
|
|
||||||
// If we don't have a response then we know that the socket
|
|
||||||
// ended prematurely and we need to emit an error on the request.
|
|
||||||
req.emit('error', createHangUpError());
|
|
||||||
req._hadError = true;
|
|
||||||
}
|
|
||||||
if (parser) {
|
|
||||||
parser.finish();
|
|
||||||
freeParser(parser, req);
|
|
||||||
}
|
|
||||||
socket.destroy();
|
|
||||||
};
|
|
||||||
|
|
||||||
var closeListener = function() {
|
|
||||||
debug('HTTP socket close');
|
debug('HTTP socket close');
|
||||||
req.emit('close');
|
req.emit('close');
|
||||||
if (req.res && req.res.readable) {
|
if (req.res && req.res.readable) {
|
||||||
@ -1239,16 +1167,53 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
req.emit('error', createHangUpError());
|
req.emit('error', createHangUpError());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing more to be done with this req, since the socket
|
if (parser) {
|
||||||
// is closed, and we've emitted the appropriate abort/end/close/error
|
parser.finish();
|
||||||
// events. Disavow all knowledge, and break the references to
|
freeParser(parser, req);
|
||||||
// the variables trapped by closures and on the socket object.
|
}
|
||||||
req = null;
|
|
||||||
socket._httpMessage = null;
|
|
||||||
}
|
}
|
||||||
socket.on('close', closeListener);
|
|
||||||
|
|
||||||
parser.onIncoming = function(res, shouldKeepAlive) {
|
function socketErrorListener(err) {
|
||||||
|
var socket = this;
|
||||||
|
var parser = socket.parser;
|
||||||
|
var req = socket._httpMessage;
|
||||||
|
debug('HTTP SOCKET ERROR: ' + err.message + '\n' + err.stack);
|
||||||
|
if (req) {
|
||||||
|
req.emit('error', err);
|
||||||
|
// For Safety. Some additional errors might fire later on
|
||||||
|
// and we need to make sure we don't double-fire the error event.
|
||||||
|
req._hadError = true;
|
||||||
|
}
|
||||||
|
if (parser) {
|
||||||
|
parser.finish();
|
||||||
|
freeParser(parser, req);
|
||||||
|
}
|
||||||
|
socket.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function responseOnEnd() {
|
||||||
|
var req = this.req;
|
||||||
|
var socket = req.socket;
|
||||||
|
|
||||||
|
if (req.shouldKeepAlive) {
|
||||||
|
debug('AGENT socket keep-alive');
|
||||||
|
socket.removeListener('close', socketCloseListener);
|
||||||
|
socket.removeListener('error', socketErrorListener);
|
||||||
|
socket.emit('free');
|
||||||
|
} else {
|
||||||
|
if (socket.writable) {
|
||||||
|
debug('AGENT socket.destroySoon()');
|
||||||
|
socket.destroySoon();
|
||||||
|
}
|
||||||
|
assert(!socket.writable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parserOnIncomingClient(res, shouldKeepAlive) {
|
||||||
|
var parser = this;
|
||||||
|
var socket = this.socket;
|
||||||
|
var req = socket._httpMessage;
|
||||||
|
|
||||||
debug('AGENT incoming response!');
|
debug('AGENT incoming response!');
|
||||||
|
|
||||||
if (req.res) {
|
if (req.res) {
|
||||||
@ -1281,34 +1246,99 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
req.shouldKeepAlive = false;
|
req.shouldKeepAlive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.addListener('end', function() {
|
|
||||||
if (!req.shouldKeepAlive) {
|
|
||||||
if (socket.writable) {
|
|
||||||
debug('AGENT socket.destroySoon()');
|
|
||||||
socket.destroySoon();
|
|
||||||
}
|
|
||||||
assert(!socket.writable);
|
|
||||||
} else {
|
|
||||||
debug('AGENT socket keep-alive');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
|
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
|
||||||
req.emit('response', res);
|
req.emit('response', res);
|
||||||
|
req.res = res;
|
||||||
|
res.req = req;
|
||||||
|
|
||||||
res.on('end', function() {
|
res.on('end', responseOnEnd);
|
||||||
if (req.shouldKeepAlive) {
|
|
||||||
socket.removeListener('close', closeListener);
|
|
||||||
socket.removeListener('error', errorListener);
|
|
||||||
socket.emit('free');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return isHeadResponse;
|
return isHeadResponse;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function socketOnEnd() {
|
||||||
|
var socket = this;
|
||||||
|
var req = this._httpMessage;
|
||||||
|
var parser = this.parser;
|
||||||
|
if (!req.res) {
|
||||||
|
// If we don't have a response then we know that the socket
|
||||||
|
// ended prematurely and we need to emit an error on the request.
|
||||||
|
req.emit('error', createHangUpError());
|
||||||
|
req._hadError = true;
|
||||||
|
}
|
||||||
|
if (parser) {
|
||||||
|
parser.finish();
|
||||||
|
freeParser(parser, req);
|
||||||
|
}
|
||||||
|
socket.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function socketOnData(d, start, end) {
|
||||||
|
var socket = this;
|
||||||
|
var req = this._httpMessage;
|
||||||
|
var parser = this.parser;
|
||||||
|
|
||||||
|
var ret = parser.execute(d, start, end - start);
|
||||||
|
if (ret instanceof Error) {
|
||||||
|
debug('parse error');
|
||||||
|
freeParser(parser, req);
|
||||||
|
socket.destroy(ret);
|
||||||
|
} else if (parser.incoming && parser.incoming.upgrade) {
|
||||||
|
var bytesParsed = ret;
|
||||||
|
socket.ondata = null;
|
||||||
|
socket.onend = null;
|
||||||
|
|
||||||
|
var res = parser.incoming;
|
||||||
|
req.res = res;
|
||||||
|
|
||||||
|
// This is start + byteParsed
|
||||||
|
var upgradeHead = d.slice(start + bytesParsed, end);
|
||||||
|
if (req.listeners('upgrade').length) {
|
||||||
|
// Emit 'upgrade' on the Agent.
|
||||||
|
req.upgraded = true;
|
||||||
|
req.emit('upgrade', res, socket, upgradeHead);
|
||||||
|
socket.emit('agentRemove');
|
||||||
|
} else {
|
||||||
|
// Got upgrade header, but have no handler.
|
||||||
|
socket.destroy();
|
||||||
|
}
|
||||||
|
freeParser(parser, req);
|
||||||
|
} else if (parser.incoming && parser.incoming.complete &&
|
||||||
|
// When the status code is 100 (Continue), the server will
|
||||||
|
// send a final response after this client sends a request
|
||||||
|
// body. So, we must not free the parser.
|
||||||
|
parser.incoming.statusCode !== 100) {
|
||||||
|
freeParser(parser, req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientRequest.prototype.onSocket = function(socket) {
|
||||||
|
var req = this;
|
||||||
|
|
||||||
|
process.nextTick(function() {
|
||||||
|
var parser = parsers.alloc();
|
||||||
|
|
||||||
|
req.socket = socket;
|
||||||
|
req.connection = socket;
|
||||||
|
parser.socket = socket;
|
||||||
|
socket.parser = parser;
|
||||||
|
parser.reinitialize(HTTPParser.RESPONSE);
|
||||||
|
parser.incoming = null;
|
||||||
|
req.parser = parser;
|
||||||
|
|
||||||
|
socket._httpMessage = req;
|
||||||
|
|
||||||
|
// Setup "drain" propogation.
|
||||||
|
httpSocketSetup(socket);
|
||||||
|
socket.ondata = socketOnData;
|
||||||
|
socket.onend = socketOnEnd;
|
||||||
|
socket.on('error', socketErrorListener);
|
||||||
|
socket.on('close', socketCloseListener);
|
||||||
|
parser.onIncoming = parserOnIncomingClient;
|
||||||
|
|
||||||
req.emit('socket', socket);
|
req.emit('socket', socket);
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) {
|
ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user