http: Clean up parser usage
Move parsers.free(parser) to a single function, which also nulls all of the various references we hang on them. Also, move the parser.on* methods out of the closure, so that there's one shared definition of each, instead of re-defining for each parser in a spot where they can close over references to other request-specific objects.
This commit is contained in:
parent
62c12d2161
commit
2fc528ce00
117
lib/http.js
117
lib/http.js
@ -35,29 +35,18 @@ if (process.env.NODE_DEBUG && /http/.test(process.env.NODE_DEBUG)) {
|
|||||||
debug = function() { };
|
debug = function() { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parserOnHeaders(headers, url) {
|
||||||
|
this._headers = this._headers.concat(headers);
|
||||||
|
this._url += url;
|
||||||
|
}
|
||||||
|
|
||||||
var parsers = new FreeList('parsers', 1000, function() {
|
// info.headers and info.url are set only if .onHeaders()
|
||||||
var parser = new HTTPParser(HTTPParser.REQUEST);
|
// has not been called for this request.
|
||||||
|
//
|
||||||
parser._headers = [];
|
// info.url is not set for response parsers but that's not
|
||||||
parser._url = '';
|
// applicable here since all our parsers are request parsers.
|
||||||
|
function parserOnHeadersComplete(info) {
|
||||||
// Only called in the slow case where slow means
|
var parser = this;
|
||||||
// that the request headers were either fragmented
|
|
||||||
// across multiple TCP packets or too large to be
|
|
||||||
// processed in a single run. This method is also
|
|
||||||
// called to process trailing HTTP headers.
|
|
||||||
parser.onHeaders = function(headers, url) {
|
|
||||||
parser._headers = parser._headers.concat(headers);
|
|
||||||
parser._url += url;
|
|
||||||
};
|
|
||||||
|
|
||||||
// info.headers and info.url are set only if .onHeaders()
|
|
||||||
// has not been called for this request.
|
|
||||||
//
|
|
||||||
// info.url is not set for response parsers but that's not
|
|
||||||
// applicable here since all our parsers are request parsers.
|
|
||||||
parser.onHeadersComplete = function(info) {
|
|
||||||
var headers = info.headers;
|
var headers = info.headers;
|
||||||
var url = info.url;
|
var url = info.url;
|
||||||
|
|
||||||
@ -103,9 +92,10 @@ var parsers = new FreeList('parsers', 1000, function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return isHeadResponse;
|
return isHeadResponse;
|
||||||
};
|
}
|
||||||
|
|
||||||
parser.onBody = function(b, start, len) {
|
function parserOnBody(b, start, len) {
|
||||||
|
var parser = this;
|
||||||
// TODO body encoding?
|
// TODO body encoding?
|
||||||
var slice = b.slice(start, start + len);
|
var slice = b.slice(start, start + len);
|
||||||
if (parser.incoming._decoder) {
|
if (parser.incoming._decoder) {
|
||||||
@ -114,9 +104,9 @@ var parsers = new FreeList('parsers', 1000, function() {
|
|||||||
} else {
|
} else {
|
||||||
parser.incoming.emit('data', slice);
|
parser.incoming.emit('data', slice);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
function parserOnMessageComplete() {
|
||||||
parser.onMessageComplete = function() {
|
var parser = this;
|
||||||
parser.incoming.complete = true;
|
parser.incoming.complete = true;
|
||||||
|
|
||||||
// Emit any trailing headers.
|
// Emit any trailing headers.
|
||||||
@ -141,7 +131,24 @@ var parsers = new FreeList('parsers', 1000, function() {
|
|||||||
// force to read the next incoming message
|
// force to read the next incoming message
|
||||||
parser.socket.resume();
|
parser.socket.resume();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var parsers = new FreeList('parsers', 1000, function() {
|
||||||
|
var parser = new HTTPParser(HTTPParser.REQUEST);
|
||||||
|
|
||||||
|
parser._headers = [];
|
||||||
|
parser._url = '';
|
||||||
|
|
||||||
|
// Only called in the slow case where slow means
|
||||||
|
// that the request headers were either fragmented
|
||||||
|
// across multiple TCP packets or too large to be
|
||||||
|
// processed in a single run. This method is also
|
||||||
|
// called to process trailing HTTP headers.
|
||||||
|
parser.onHeaders = parserOnHeaders;
|
||||||
|
parser.onHeadersComplete = parserOnHeadersComplete;
|
||||||
|
parser.onBody = parserOnBody;
|
||||||
|
parser.onMessageComplete = parserOnMessageComplete;
|
||||||
|
|
||||||
return parser;
|
return parser;
|
||||||
});
|
});
|
||||||
@ -1110,6 +1117,31 @@ function createHangUpError() {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Free the parser and also break any links that it
|
||||||
|
// might have to any other things.
|
||||||
|
// TODO: All parser data should be attached to a
|
||||||
|
// single object, so that it can be easily cleaned
|
||||||
|
// up by doing `parser.data = {}`, which should
|
||||||
|
// be done in FreeList.free. `parsers.free(parser)`
|
||||||
|
// should be all that is needed.
|
||||||
|
function freeParser(parser, req) {
|
||||||
|
if (parser) {
|
||||||
|
parser._headers = [];
|
||||||
|
parser.onIncoming = null;
|
||||||
|
if (parser.socket) {
|
||||||
|
parser.socket.onend = null;
|
||||||
|
parser.socket.ondata = null;
|
||||||
|
}
|
||||||
|
parser.socket = null;
|
||||||
|
parser.incoming = null;
|
||||||
|
parsers.free(parser);
|
||||||
|
parser = null;
|
||||||
|
}
|
||||||
|
if (req) {
|
||||||
|
req.parser = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ClientRequest.prototype.onSocket = function(socket) {
|
ClientRequest.prototype.onSocket = function(socket) {
|
||||||
var req = this;
|
var req = this;
|
||||||
@ -1126,21 +1158,6 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
// Setup "drain" propogation.
|
// Setup "drain" propogation.
|
||||||
httpSocketSetup(socket);
|
httpSocketSetup(socket);
|
||||||
|
|
||||||
var freeParser = function() {
|
|
||||||
if (parser) {
|
|
||||||
parser.onIncoming = null;
|
|
||||||
parser.socket.onend = null;
|
|
||||||
parser.socket.ondata = null;
|
|
||||||
parser.socket = null;
|
|
||||||
parser.incoming = null;
|
|
||||||
parsers.free(parser);
|
|
||||||
parser = null;
|
|
||||||
}
|
|
||||||
if (req) {
|
|
||||||
req.parser = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var errorListener = function(err) {
|
var errorListener = function(err) {
|
||||||
debug('HTTP SOCKET ERROR: ' + err.message + '\n' + err.stack);
|
debug('HTTP SOCKET ERROR: ' + err.message + '\n' + err.stack);
|
||||||
req.emit('error', err);
|
req.emit('error', err);
|
||||||
@ -1149,7 +1166,7 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
req._hadError = true;
|
req._hadError = true;
|
||||||
if (parser) {
|
if (parser) {
|
||||||
parser.finish();
|
parser.finish();
|
||||||
freeParser();
|
freeParser(parser, req);
|
||||||
}
|
}
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
}
|
}
|
||||||
@ -1159,7 +1176,7 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
var ret = parser.execute(d, start, end - start);
|
var ret = parser.execute(d, start, end - start);
|
||||||
if (ret instanceof Error) {
|
if (ret instanceof Error) {
|
||||||
debug('parse error');
|
debug('parse error');
|
||||||
freeParser();
|
freeParser(parser, req);
|
||||||
socket.destroy(ret);
|
socket.destroy(ret);
|
||||||
} else if (parser.incoming && parser.incoming.upgrade) {
|
} else if (parser.incoming && parser.incoming.upgrade) {
|
||||||
var bytesParsed = ret;
|
var bytesParsed = ret;
|
||||||
@ -1180,13 +1197,13 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
// Got upgrade header, but have no handler.
|
// Got upgrade header, but have no handler.
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
}
|
}
|
||||||
freeParser();
|
freeParser(parser, req);
|
||||||
} else if (parser.incoming && parser.incoming.complete &&
|
} else if (parser.incoming && parser.incoming.complete &&
|
||||||
// When the status code is 100 (Continue), the server will
|
// When the status code is 100 (Continue), the server will
|
||||||
// send a final response after this client sends a request
|
// send a final response after this client sends a request
|
||||||
// body. So, we must not free the parser.
|
// body. So, we must not free the parser.
|
||||||
parser.incoming.statusCode !== 100) {
|
parser.incoming.statusCode !== 100) {
|
||||||
freeParser();
|
freeParser(parser, req);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1199,7 +1216,7 @@ ClientRequest.prototype.onSocket = function(socket) {
|
|||||||
}
|
}
|
||||||
if (parser) {
|
if (parser) {
|
||||||
parser.finish();
|
parser.finish();
|
||||||
freeParser();
|
freeParser(parser, req);
|
||||||
}
|
}
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
};
|
};
|
||||||
@ -1494,8 +1511,8 @@ function connectionListener(socket) {
|
|||||||
|
|
||||||
socket.addListener('close', function() {
|
socket.addListener('close', function() {
|
||||||
debug('server socket close');
|
debug('server socket close');
|
||||||
// unref the parser for easy gc
|
// mark this parser as reusable
|
||||||
parsers.free(parser);
|
freeParser(parser);
|
||||||
|
|
||||||
abortIncoming();
|
abortIncoming();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user