Browse Source

Fast buffers for http-parser

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
5f935f6c14
  1. 55
      src/node_http_parser.cc

55
src/node_http_parser.cc

@ -68,6 +68,15 @@ static Persistent<String> upgrade_sym;
static struct http_parser_settings settings;
// This is a hack to get the current_buffer to the callbacks with the least
// amount of overhead. Nothing else will run while http_parser_execute()
// runs, therefore this pointer can be set and used for the execution.
static Local<Value>* current_buffer;
static char* current_buffer_data;
static size_t current_buffer_len;
// Callback prototype for http_cb
#define DEFINE_HTTP_CB(name) \
static int name(http_parser *p) { \
@ -88,16 +97,16 @@ static struct http_parser_settings settings;
#define DEFINE_HTTP_DATA_CB(name) \
static int name(http_parser *p, const char *at, size_t length) { \
Parser *parser = static_cast<Parser*>(p->data); \
assert(parser->buffer_); \
assert(current_buffer); \
Local<Value> cb_value = parser->handle_->Get(name##_sym); \
if (!cb_value->IsFunction()) return 0; \
Local<Function> cb = Local<Function>::Cast(cb_value); \
Local<Value> argv[3] = { Local<Value>::New(parser->buffer_->handle_) \
, Integer::New(at - parser->buffer_->data()) \
Local<Value> argv[3] = { *current_buffer \
, Integer::New(at - current_buffer_data) \
, Integer::New(length) \
}; \
Local<Value> ret = cb->Call(parser->handle_, 3, argv); \
assert(parser->buffer_); \
assert(current_buffer); \
if (ret.IsEmpty()) { \
parser->got_exception_ = true; \
return -1; \
@ -137,12 +146,10 @@ method_to_str(unsigned short m) {
class Parser : public ObjectWrap {
public:
Parser(enum http_parser_type type) : ObjectWrap() {
buffer_ = NULL;
Init(type);
}
~Parser() {
assert(buffer_ == NULL && "Destroying a parser while it's parsing");
}
DEFINE_HTTP_CB(on_message_begin)
@ -214,7 +221,7 @@ class Parser : public ObjectWrap {
}
parser->Wrap(args.This());
assert(!parser->buffer_);
assert(!current_buffer);
return args.This();
}
@ -225,41 +232,50 @@ class Parser : public ObjectWrap {
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
assert(!parser->buffer_);
if (parser->buffer_) {
assert(!current_buffer);
assert(!current_buffer_data);
if (current_buffer) {
return ThrowException(Exception::TypeError(
String::New("Already parsing a buffer")));
}
if (!Buffer::HasInstance(args[0])) {
Local<Value> buffer_v = args[0];
if (!Buffer::HasInstance(buffer_v)) {
return ThrowException(Exception::TypeError(
String::New("Argument should be a buffer")));
}
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
Local<Object> buffer_obj = buffer_v->ToObject();
char *buffer_data = Buffer::Data(buffer_obj);
size_t buffer_len = Buffer::Length(buffer_obj);
size_t off = args[1]->Int32Value();
if (off >= buffer->length()) {
if (off >= buffer_len) {
return ThrowException(Exception::Error(
String::New("Offset is out of bounds")));
}
size_t len = args[2]->Int32Value();
if (off+len > buffer->length()) {
if (off+len > buffer_len) {
return ThrowException(Exception::Error(
String::New("Length is extends beyond buffer")));
}
// Assign 'buffer_' while we parse. The callbacks will access that varible.
parser->buffer_ = buffer;
current_buffer = &buffer_v;
current_buffer_data = buffer_data;
current_buffer_len = buffer_len;
parser->got_exception_ = false;
size_t nparsed =
http_parser_execute(&parser->parser_, &settings, buffer->data()+off, len);
http_parser_execute(&parser->parser_, &settings, buffer_data + off, len);
// Unassign the 'buffer_' variable
assert(parser->buffer_);
parser->buffer_ = NULL;
assert(current_buffer);
current_buffer = NULL;
current_buffer_data = NULL;
// If there was an exception in one of the callbacks
if (parser->got_exception_) return Local<Value>();
@ -282,7 +298,7 @@ class Parser : public ObjectWrap {
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
assert(!parser->buffer_);
assert(!current_buffer);
parser->got_exception_ = false;
http_parser_execute(&(parser->parser_), &settings, NULL, 0);
@ -313,13 +329,10 @@ class Parser : public ObjectWrap {
private:
void Init (enum http_parser_type type) {
assert(buffer_ == NULL); // don't call this during Execute()
http_parser_init(&parser_, type);
parser_.data = this;
}
Buffer * buffer_; // The buffer currently being parsed.
bool got_exception_;
http_parser parser_;
};

Loading…
Cancel
Save