diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 0ca04bd1437..1524f4abd32 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -68,6 +68,15 @@ static Persistent 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* 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(p->data); \ - assert(parser->buffer_); \ + assert(current_buffer); \ Local cb_value = parser->handle_->Get(name##_sym); \ if (!cb_value->IsFunction()) return 0; \ Local cb = Local::Cast(cb_value); \ - Local argv[3] = { Local::New(parser->buffer_->handle_) \ - , Integer::New(at - parser->buffer_->data()) \ + Local argv[3] = { *current_buffer \ + , Integer::New(at - current_buffer_data) \ , Integer::New(length) \ }; \ Local 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(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 buffer_v = args[0]; + + if (!Buffer::HasInstance(buffer_v)) { return ThrowException(Exception::TypeError( String::New("Argument should be a buffer"))); } - Buffer * buffer = ObjectWrap::Unwrap(args[0]->ToObject()); + Local 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(); @@ -282,7 +298,7 @@ class Parser : public ObjectWrap { Parser *parser = ObjectWrap::Unwrap(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_; };