http: speed up callbacks, use array indices
Use array indices rather than named properties to store callbacks on the HTTPParser object. Speeds up the http benchmarks by a few percent.
This commit is contained in:
parent
d684f50acb
commit
2669966e76
@ -27,7 +27,6 @@ var IncomingMessage = incoming.IncomingMessage;
|
||||
var readStart = incoming.readStart;
|
||||
var readStop = incoming.readStop;
|
||||
|
||||
|
||||
var debug = require('util').debuglog('http');
|
||||
exports.debug = debug;
|
||||
|
||||
@ -35,6 +34,11 @@ exports.CRLF = '\r\n';
|
||||
exports.chunkExpression = /chunk/i;
|
||||
exports.continueExpression = /100-continue/i;
|
||||
|
||||
var kOnHeaders = HTTPParser.kOnHeaders | 0;
|
||||
var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
|
||||
var kOnBody = HTTPParser.kOnBody | 0;
|
||||
var kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
|
||||
|
||||
// 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
|
||||
@ -180,10 +184,10 @@ var parsers = new FreeList('parsers', 1000, function() {
|
||||
// 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;
|
||||
parser[kOnHeaders] = parserOnHeaders;
|
||||
parser[kOnHeadersComplete] = parserOnHeadersComplete;
|
||||
parser[kOnBody] = parserOnBody;
|
||||
parser[kOnMessageComplete] = parserOnMessageComplete;
|
||||
|
||||
return parser;
|
||||
});
|
||||
|
@ -60,10 +60,10 @@ using v8::Object;
|
||||
using v8::String;
|
||||
using v8::Value;
|
||||
|
||||
static Cached<String> on_headers_sym;
|
||||
static Cached<String> on_headers_complete_sym;
|
||||
static Cached<String> on_body_sym;
|
||||
static Cached<String> on_message_complete_sym;
|
||||
const uint32_t kOnHeaders = 0;
|
||||
const uint32_t kOnHeadersComplete = 1;
|
||||
const uint32_t kOnBody = 2;
|
||||
const uint32_t kOnMessageComplete = 3;
|
||||
|
||||
static Cached<String> method_sym;
|
||||
static Cached<String> status_code_sym;
|
||||
@ -255,7 +255,7 @@ class Parser : public ObjectWrap {
|
||||
|
||||
HTTP_CB(on_headers_complete) {
|
||||
Local<Object> obj = handle(node_isolate);
|
||||
Local<Value> cb = obj->Get(on_headers_complete_sym);
|
||||
Local<Value> cb = obj->Get(kOnHeadersComplete);
|
||||
|
||||
if (!cb->IsFunction())
|
||||
return 0;
|
||||
@ -315,7 +315,7 @@ class Parser : public ObjectWrap {
|
||||
HandleScope scope(node_isolate);
|
||||
|
||||
Local<Object> obj = handle(node_isolate);
|
||||
Local<Value> cb = obj->Get(on_body_sym);
|
||||
Local<Value> cb = obj->Get(kOnBody);
|
||||
|
||||
if (!cb->IsFunction())
|
||||
return 0;
|
||||
@ -344,7 +344,7 @@ class Parser : public ObjectWrap {
|
||||
Flush(); // Flush trailing HTTP headers.
|
||||
|
||||
Local<Object> obj = handle(node_isolate);
|
||||
Local<Value> cb = obj->Get(on_message_complete_sym);
|
||||
Local<Value> cb = obj->Get(kOnMessageComplete);
|
||||
|
||||
if (!cb->IsFunction())
|
||||
return 0;
|
||||
@ -506,7 +506,7 @@ class Parser : public ObjectWrap {
|
||||
HandleScope scope(node_isolate);
|
||||
|
||||
Local<Object> obj = handle(node_isolate);
|
||||
Local<Value> cb = obj->Get(on_headers_sym);
|
||||
Local<Value> cb = obj->Get(kOnHeaders);
|
||||
|
||||
if (!cb->IsFunction())
|
||||
return;
|
||||
@ -558,6 +558,14 @@ void InitHttpParser(Handle<Object> target) {
|
||||
Integer::New(HTTP_REQUEST, node_isolate));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(node_isolate, "RESPONSE"),
|
||||
Integer::New(HTTP_RESPONSE, node_isolate));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(node_isolate, "kOnHeaders"),
|
||||
Integer::NewFromUnsigned(kOnHeaders, node_isolate));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(node_isolate, "kOnHeadersComplete"),
|
||||
Integer::NewFromUnsigned(kOnHeadersComplete, node_isolate));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(node_isolate, "kOnBody"),
|
||||
Integer::NewFromUnsigned(kOnBody, node_isolate));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(node_isolate, "kOnMessageComplete"),
|
||||
Integer::NewFromUnsigned(kOnMessageComplete, node_isolate));
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "execute", Parser::Execute);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "finish", Parser::Finish);
|
||||
@ -566,15 +574,6 @@ void InitHttpParser(Handle<Object> target) {
|
||||
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "HTTPParser"),
|
||||
t->GetFunction());
|
||||
|
||||
on_headers_sym =
|
||||
FIXED_ONE_BYTE_STRING(node_isolate, "onHeaders");
|
||||
on_headers_complete_sym =
|
||||
FIXED_ONE_BYTE_STRING(node_isolate, "onHeadersComplete");
|
||||
on_body_sym =
|
||||
FIXED_ONE_BYTE_STRING(node_isolate, "onBody");
|
||||
on_message_complete_sym =
|
||||
FIXED_ONE_BYTE_STRING(node_isolate, "onMessageComplete");
|
||||
|
||||
#define X(num, name, string) \
|
||||
name ## _sym = OneByteString(node_isolate, #string);
|
||||
HTTP_METHOD_MAP(X)
|
||||
|
@ -7,6 +7,11 @@ var common = require('../common');
|
||||
var assert = require('assert');
|
||||
var HTTPParser = process.binding('http_parser').HTTPParser;
|
||||
|
||||
var kOnHeaders = HTTPParser.kOnHeaders | 0;
|
||||
var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
|
||||
var kOnBody = HTTPParser.kOnBody | 0;
|
||||
var kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
|
||||
|
||||
var headersComplete = 0;
|
||||
var messagesComplete = 0;
|
||||
|
||||
@ -23,19 +28,19 @@ function demoBug(part1, part2) {
|
||||
parser.headers = [];
|
||||
parser.url = '';
|
||||
|
||||
parser.onHeaders = function(headers, url) {
|
||||
parser[kOnHeaders] = function(headers, url) {
|
||||
parser.headers = parser.headers.concat(headers);
|
||||
parser.url += url;
|
||||
};
|
||||
|
||||
parser.onHeadersComplete = function(info) {
|
||||
parser[kOnHeadersComplete] = function(info) {
|
||||
headersComplete++;
|
||||
console.log('url', info.url);
|
||||
};
|
||||
|
||||
parser.onBody = function(b, start, len) { };
|
||||
parser[kOnBody] = function(b, start, len) { };
|
||||
|
||||
parser.onMessageComplete = function() {
|
||||
parser[kOnMessageComplete] = function() {
|
||||
messagesComplete++;
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,11 @@ var CRLF = '\r\n';
|
||||
var REQUEST = HTTPParser.REQUEST;
|
||||
var RESPONSE = HTTPParser.RESPONSE;
|
||||
|
||||
var kOnHeaders = HTTPParser.kOnHeaders | 0;
|
||||
var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
|
||||
var kOnBody = HTTPParser.kOnBody | 0;
|
||||
var kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
|
||||
|
||||
// The purpose of this test is not to check HTTP compliance but to test the
|
||||
// binding. Tests for pathological http messages should be submitted
|
||||
// upstream to https://github.com/joyent/http-parser for inclusion into
|
||||
@ -40,19 +45,19 @@ function newParser(type) {
|
||||
parser.headers = [];
|
||||
parser.url = '';
|
||||
|
||||
parser.onHeaders = function(headers, url) {
|
||||
parser[kOnHeaders] = function(headers, url) {
|
||||
parser.headers = parser.headers.concat(headers);
|
||||
parser.url += url;
|
||||
};
|
||||
|
||||
parser.onHeadersComplete = function(info) {
|
||||
parser[kOnHeadersComplete] = function(info) {
|
||||
};
|
||||
|
||||
parser.onBody = function(b, start, len) {
|
||||
parser[kOnBody] = function(b, start, len) {
|
||||
assert.ok(false, 'Function should not be called.');
|
||||
};
|
||||
|
||||
parser.onMessageComplete = function() {
|
||||
parser[kOnMessageComplete] = function() {
|
||||
};
|
||||
|
||||
return parser;
|
||||
@ -92,7 +97,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'GET');
|
||||
assert.equal(info.url || parser.url, '/hello');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
@ -106,7 +111,7 @@ function expectBody(expected) {
|
||||
// thrown from parser.execute()
|
||||
//
|
||||
|
||||
parser.onHeadersComplete = function(info) {
|
||||
parser[kOnHeadersComplete] = function(info) {
|
||||
throw new Error('hello world');
|
||||
};
|
||||
|
||||
@ -131,14 +136,14 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(RESPONSE);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, undefined);
|
||||
assert.equal(info.versionMajor, 1);
|
||||
assert.equal(info.versionMinor, 1);
|
||||
assert.equal(info.statusCode, 200);
|
||||
});
|
||||
|
||||
parser.onBody = mustCall(function(buf, start, len) {
|
||||
parser[kOnBody] = mustCall(function(buf, start, len) {
|
||||
var body = '' + buf.slice(start, start + len);
|
||||
assert.equal(body, 'pong');
|
||||
});
|
||||
@ -157,7 +162,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(RESPONSE);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, undefined);
|
||||
assert.equal(info.versionMajor, 1);
|
||||
assert.equal(info.versionMinor, 0);
|
||||
@ -194,16 +199,16 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'POST');
|
||||
assert.equal(info.url || parser.url, '/it');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
assert.equal(info.versionMinor, 1);
|
||||
// expect to see trailing headers now
|
||||
parser.onHeaders = mustCall(onHeaders);
|
||||
parser[kOnHeaders] = mustCall(onHeaders);
|
||||
});
|
||||
|
||||
parser.onBody = mustCall(function(buf, start, len) {
|
||||
parser[kOnBody] = mustCall(function(buf, start, len) {
|
||||
var body = '' + buf.slice(start, start + len);
|
||||
assert.equal(body, 'ping');
|
||||
seen_body = true;
|
||||
@ -226,7 +231,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'GET');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
assert.equal(info.versionMinor, 0);
|
||||
@ -255,7 +260,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'GET');
|
||||
assert.equal(info.url || parser.url, '/foo/bar/baz?quux=42#1337');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
@ -287,14 +292,14 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'POST');
|
||||
assert.equal(info.url || parser.url, '/it');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
assert.equal(info.versionMinor, 1);
|
||||
});
|
||||
|
||||
parser.onBody = mustCall(function(buf, start, len) {
|
||||
parser[kOnBody] = mustCall(function(buf, start, len) {
|
||||
var body = '' + buf.slice(start, start + len);
|
||||
assert.equal(body, 'foo=42&bar=1337');
|
||||
});
|
||||
@ -322,7 +327,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'POST');
|
||||
assert.equal(info.url || parser.url, '/it');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
@ -337,7 +342,7 @@ function expectBody(expected) {
|
||||
assert.equal(body, body_parts[body_part++]);
|
||||
}
|
||||
|
||||
parser.onBody = mustCall(onBody, body_parts.length);
|
||||
parser[kOnBody] = mustCall(onBody, body_parts.length);
|
||||
parser.execute(request, 0, request.length);
|
||||
})();
|
||||
|
||||
@ -358,7 +363,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'POST');
|
||||
assert.equal(info.url || parser.url, '/it');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
@ -375,7 +380,7 @@ function expectBody(expected) {
|
||||
assert.equal(body, body_parts[body_part++]);
|
||||
}
|
||||
|
||||
parser.onBody = mustCall(onBody, body_parts.length);
|
||||
parser[kOnBody] = mustCall(onBody, body_parts.length);
|
||||
parser.execute(request, 0, request.length);
|
||||
|
||||
request = Buffer(
|
||||
@ -415,7 +420,7 @@ function expectBody(expected) {
|
||||
function test(a, b) {
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'POST');
|
||||
assert.equal(info.url || parser.url, '/helpme');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
@ -424,7 +429,7 @@ function expectBody(expected) {
|
||||
|
||||
var expected_body = '123123456123456789123456789ABC123456789ABCDEF';
|
||||
|
||||
parser.onBody = function(buf, start, len) {
|
||||
parser[kOnBody] = function(buf, start, len) {
|
||||
var chunk = '' + buf.slice(start, start + len);
|
||||
assert.equal(expected_body.indexOf(chunk), 0);
|
||||
expected_body = expected_body.slice(chunk.length);
|
||||
@ -471,7 +476,7 @@ function expectBody(expected) {
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
|
||||
parser.onHeadersComplete = mustCall(function(info) {
|
||||
parser[kOnHeadersComplete] = mustCall(function(info) {
|
||||
assert.equal(info.method, 'POST');
|
||||
assert.equal(info.url || parser.url, '/it');
|
||||
assert.equal(info.versionMajor, 1);
|
||||
@ -483,7 +488,7 @@ function expectBody(expected) {
|
||||
|
||||
var expected_body = '123123456123456789123456789ABC123456789ABCDEF';
|
||||
|
||||
parser.onBody = function(buf, start, len) {
|
||||
parser[kOnBody] = function(buf, start, len) {
|
||||
var chunk = '' + buf.slice(start, start + len);
|
||||
assert.equal(expected_body.indexOf(chunk), 0);
|
||||
expected_body = expected_body.slice(chunk.length);
|
||||
@ -538,12 +543,12 @@ function expectBody(expected) {
|
||||
};
|
||||
|
||||
var parser = newParser(REQUEST);
|
||||
parser.onHeadersComplete = onHeadersComplete1;
|
||||
parser.onBody = expectBody('ping');
|
||||
parser[kOnHeadersComplete] = onHeadersComplete1;
|
||||
parser[kOnBody] = expectBody('ping');
|
||||
parser.execute(req1, 0, req1.length);
|
||||
|
||||
parser.reinitialize(REQUEST);
|
||||
parser.onBody = expectBody('pong');
|
||||
parser.onHeadersComplete = onHeadersComplete2;
|
||||
parser[kOnBody] = expectBody('pong');
|
||||
parser[kOnHeadersComplete] = onHeadersComplete2;
|
||||
parser.execute(req2, 0, req2.length);
|
||||
})();
|
||||
|
Loading…
x
Reference in New Issue
Block a user