Browse Source

Break up huge function in ClientRequest.onSocket

v0.8.7-release
isaacs 13 years ago
parent
commit
07d8a4650e
  1. 256
      lib/http.js

256
lib/http.js

@ -105,6 +105,7 @@ function parserOnBody(b, start, len) {
parser.incoming.emit('data', slice);
}
}
function parserOnMessageComplete() {
var parser = this;
parser.incoming.complete = true;
@ -490,7 +491,9 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
// keep-alive logic
if (sentConnectionHeader === false) {
if (this.shouldKeepAlive &&
(sentContentLengthHeader || this.useChunkedEncodingByDefault || this.agent)) {
(sentContentLengthHeader ||
this.useChunkedEncodingByDefault ||
this.agent)) {
messageHeader += 'Connection: keep-alive\r\n';
} else {
this._last = true;
@ -523,7 +526,7 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
OutgoingMessage.prototype.setHeader = function(name, value) {
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) {
@ -540,7 +543,7 @@ OutgoingMessage.prototype.setHeader = function(name, value) {
OutgoingMessage.prototype.getHeader = function(name) {
if (arguments.length < 1) {
throw new Error("`name` is required for getHeader().");
throw new Error('`name` is required for getHeader().');
}
if (!this._headers) return;
@ -552,7 +555,7 @@ OutgoingMessage.prototype.getHeader = function(name) {
OutgoingMessage.prototype.removeHeader = function(name) {
if (arguments.length < 1) {
throw new Error("`name` is required for removeHeader().");
throw new Error('`name` is required for removeHeader().');
}
if (this._header) {
@ -1078,7 +1081,9 @@ function ClientRequest(options, cb) {
self._last = true;
self.shouldKeepAlive = false;
if (options.createConnection) {
self.onSocket(options.createConnection(options.port, options.host, options));
self.onSocket(options.createConnection(options.port,
options.host,
options));
} else {
self.onSocket(net.createConnection(options.port, options.host));
}
@ -1095,7 +1100,8 @@ util.inherits(ClientRequest, OutgoingMessage);
exports.ClientRequest = ClientRequest;
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() {
@ -1131,6 +1137,7 @@ function freeParser(parser, req) {
if (parser.socket) {
parser.socket.onend = null;
parser.socket.ondata = null;
parser.socket.parser = null;
}
parser.socket = null;
parser.incoming = null;
@ -1140,25 +1147,36 @@ function freeParser(parser, req) {
if (req) {
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;
function socketCloseListener() {
var socket = this;
var parser = socket.parser;
var req = socket._httpMessage;
debug('HTTP socket close');
req.emit('close');
if (req.res && req.res.readable) {
// Socket closed before we emitted "end" below.
req.res.emit('aborted');
req.res.emit('end');
req.res.emit('close');
} else if (!req.res && !req._hadError) {
// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());
}
socket._httpMessage = req;
// Setup "drain" propogation.
httpSocketSetup(socket);
if (parser) {
parser.finish();
freeParser(parser, req);
}
}
function errorListener(err) {
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);
@ -1171,84 +1189,31 @@ ClientRequest.prototype.onSocket = function(socket) {
freeParser(parser, req);
}
socket.destroy();
}
socket.on('error', errorListener);
socket.ondata = function(d, start, end) {
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;
function responseOnEnd() {
var req = this.req;
var socket = req.socket;
// 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');
if (req.shouldKeepAlive) {
debug('AGENT socket keep-alive');
socket.removeListener('close', socketCloseListener);
socket.removeListener('error', socketErrorListener);
socket.emit('free');
} 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);
if (socket.writable) {
debug('AGENT socket.destroySoon()');
socket.destroySoon();
}
socket.destroy();
};
var closeListener = function() {
debug('HTTP socket close');
req.emit('close');
if (req.res && req.res.readable) {
// Socket closed before we emitted "end" below.
req.res.emit('aborted');
req.res.emit('end');
req.res.emit('close');
} else if (!req.res && !req._hadError) {
// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());
assert(!socket.writable);
}
}
// Nothing more to be done with this req, since the socket
// is closed, and we've emitted the appropriate abort/end/close/error
// events. Disavow all knowledge, and break the references to
// the variables trapped by closures and on the socket object.
req = null;
socket._httpMessage = null;
}
socket.on('close', closeListener);
function parserOnIncomingClient(res, shouldKeepAlive) {
var parser = this;
var socket = this.socket;
var req = socket._httpMessage;
parser.onIncoming = function(res, shouldKeepAlive) {
debug('AGENT incoming response!');
if (req.res) {
@ -1281,34 +1246,99 @@ ClientRequest.prototype.onSocket = function(socket) {
req.shouldKeepAlive = false;
}
res.addListener('end', function() {
if (!req.shouldKeepAlive) {
if (socket.writable) {
debug('AGENT socket.destroySoon()');
socket.destroySoon();
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
req.emit('response', res);
req.res = res;
res.req = req;
res.on('end', responseOnEnd);
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;
}
assert(!socket.writable);
} else {
debug('AGENT socket keep-alive');
if (parser) {
parser.finish();
freeParser(parser, req);
}
});
socket.destroy();
}
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
req.emit('response', res);
res.on('end', function() {
if (req.shouldKeepAlive) {
socket.removeListener('close', closeListener);
socket.removeListener('error', errorListener);
socket.emit('free');
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;
return isHeadResponse;
};
req.emit('socket', socket);
});
};
ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) {

Loading…
Cancel
Save