diff options
Diffstat (limited to 'src/node_http_parser.cc')
-rw-r--r-- | src/node_http_parser.cc | 192 |
1 files changed, 93 insertions, 99 deletions
diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 80485ec05f..80046a9b7b 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -22,6 +22,9 @@ #include "node.h" #include "node_buffer.h" #include "node_http_parser.h" + +#include "env.h" +#include "env-inl.h" #include "v8.h" #include <stdlib.h> // free() @@ -48,6 +51,7 @@ namespace node { using v8::Array; +using v8::Context; using v8::Exception; using v8::Function; using v8::FunctionCallbackInfo; @@ -65,32 +69,6 @@ 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; -static Cached<String> http_version_sym; -static Cached<String> version_major_sym; -static Cached<String> version_minor_sym; -static Cached<String> should_keep_alive_sym; -static Cached<String> upgrade_sym; -static Cached<String> headers_sym; -static Cached<String> url_sym; - -static Cached<String> unknown_method_sym; - -#define X(num, name, string) static Cached<String> name##_sym; -HTTP_METHOD_MAP(X) -#undef X - -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; - #define HTTP_CB(name) \ static int name(http_parser* p_) { \ @@ -108,14 +86,30 @@ static size_t current_buffer_len; int name##_(const char* at, size_t length) -static inline Handle<String> -method_to_str(unsigned short m) { - switch (m) { -#define X(num, name, string) case HTTP_##name: return name##_sym; - HTTP_METHOD_MAP(X) -#undef X +// Call this function only when there is a valid HandleScope on the stack +// somewhere. +inline Local<String> MethodToString(Environment* env, uint32_t method) { + // XXX(bnoordhuis) Predicated on the observation that 99.9% of all HTTP + // requests are either GET, HEAD or POST. I threw in DELETE and PUT for + // good measure. + switch (method) { + case HTTP_DELETE: return env->DELETE_string(); + case HTTP_GET: return env->GET_string(); + case HTTP_HEAD: return env->HEAD_string(); + case HTTP_POST: return env->POST_string(); + case HTTP_PUT: return env->PUT_string(); } - return unknown_method_sym; + + switch (method) { +#define V(num, name, string) \ + case HTTP_ ## name: \ + return FIXED_ONE_BYTE_STRING(node_isolate, #string); + HTTP_METHOD_MAP(V) +#undef V + } + + // Unreachable, http_parser parses only a restricted set of request methods. + return FIXED_ONE_BYTE_STRING(node_isolate, "UNKNOWN_METHOD"); } @@ -193,7 +187,11 @@ struct StringPtr { class Parser : public ObjectWrap { public: - explicit Parser(enum http_parser_type type) : ObjectWrap() { + Parser(Environment* env, enum http_parser_type type) + : ObjectWrap() + , env_(env) + , current_buffer_len_(0) + , current_buffer_data_(NULL) { Init(type); } @@ -267,34 +265,35 @@ class Parser : public ObjectWrap { Flush(); } else { // Fast case, pass headers and URL to JS land. - message_info->Set(headers_sym, CreateHeaders()); + message_info->Set(env()->headers_string(), CreateHeaders()); if (parser_.type == HTTP_REQUEST) - message_info->Set(url_sym, url_.ToString()); + message_info->Set(env()->url_string(), url_.ToString()); } num_fields_ = num_values_ = 0; // METHOD if (parser_.type == HTTP_REQUEST) { - message_info->Set(method_sym, method_to_str(parser_.method)); + message_info->Set(env()->method_string(), + MethodToString(env(), parser_.method)); } // STATUS if (parser_.type == HTTP_RESPONSE) { - message_info->Set(status_code_sym, + message_info->Set(env()->status_code_string(), Integer::New(parser_.status_code, node_isolate)); } // VERSION - message_info->Set(version_major_sym, + message_info->Set(env()->version_major_string(), Integer::New(parser_.http_major, node_isolate)); - message_info->Set(version_minor_sym, + message_info->Set(env()->version_minor_string(), Integer::New(parser_.http_minor, node_isolate)); - message_info->Set(should_keep_alive_sym, + message_info->Set(env()->should_keep_alive_string(), http_should_keep_alive(&parser_) ? True(node_isolate) : False(node_isolate)); - message_info->Set(upgrade_sym, + message_info->Set(env()->upgrade_string(), parser_.upgrade ? True(node_isolate) : False(node_isolate)); @@ -321,9 +320,9 @@ class Parser : public ObjectWrap { return 0; Local<Value> argv[3] = { - *current_buffer, - Integer::New(at - current_buffer_data, node_isolate), - Integer::New(length, node_isolate) + current_buffer_, + Integer::NewFromUnsigned(at - current_buffer_data_, node_isolate), + Integer::NewFromUnsigned(length, node_isolate) }; Local<Value> r = cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv); @@ -361,13 +360,14 @@ class Parser : public ObjectWrap { static void New(const FunctionCallbackInfo<Value>& args) { - HandleScope scope(node_isolate); + Environment* env = Environment::GetCurrent(args.GetIsolate()); + HandleScope handle_scope(args.GetIsolate()); http_parser_type type = static_cast<http_parser_type>(args[0]->Int32Value()); assert(type == HTTP_REQUEST || type == HTTP_RESPONSE); - Parser* parser = new Parser(type); + Parser* parser = new Parser(env, type); parser->Wrap(args.This()); } @@ -390,28 +390,21 @@ class Parser : public ObjectWrap { HandleScope scope(node_isolate); Parser* parser = ObjectWrap::Unwrap<Parser>(args.This()); + assert(parser->current_buffer_.IsEmpty()); + assert(parser->current_buffer_len_ == 0); + assert(parser->current_buffer_data_ == NULL); + assert(Buffer::HasInstance(args[0]) == true); - assert(!current_buffer); - assert(!current_buffer_data); - - if (current_buffer) { - return ThrowTypeError("Already parsing a buffer"); - } - - Local<Value> buffer_v = args[0]; - - if (!Buffer::HasInstance(buffer_v)) { - return ThrowTypeError("Argument should be a buffer"); - } - - Local<Object> buffer_obj = buffer_v->ToObject(); - char *buffer_data = Buffer::Data(buffer_obj); + Local<Object> buffer_obj = args[0].As<Object>(); + char* buffer_data = Buffer::Data(buffer_obj); size_t buffer_len = Buffer::Length(buffer_obj); - // Assign 'buffer_' while we parse. The callbacks will access that varible. - current_buffer = &buffer_v; - current_buffer_data = buffer_data; - current_buffer_len = buffer_len; + // 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. + parser->current_buffer_ = buffer_obj; + parser->current_buffer_len_ = buffer_len; + parser->current_buffer_data_ = buffer_data; parser->got_exception_ = false; size_t nparsed = @@ -420,9 +413,9 @@ class Parser : public ObjectWrap { parser->Save(); // Unassign the 'buffer_' variable - assert(current_buffer); - current_buffer = NULL; - current_buffer_data = NULL; + parser->current_buffer_.Clear(); + parser->current_buffer_len_ = 0; + parser->current_buffer_data_ = NULL; // If there was an exception in one of the callbacks if (parser->got_exception_) return; @@ -439,6 +432,7 @@ class Parser : public ObjectWrap { obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "bytesParsed"), nparsed_obj); obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "code"), OneByteString(node_isolate, http_errno_name(err))); + args.GetReturnValue().Set(e); } else { args.GetReturnValue().Set(nparsed_obj); @@ -451,7 +445,7 @@ class Parser : public ObjectWrap { Parser* parser = ObjectWrap::Unwrap<Parser>(args.This()); - assert(!current_buffer); + assert(parser->current_buffer_.IsEmpty()); parser->got_exception_ = false; int rv = http_parser_execute(&(parser->parser_), &settings, NULL, 0); @@ -468,19 +462,23 @@ class Parser : public ObjectWrap { Integer::New(0, node_isolate)); obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "code"), OneByteString(node_isolate, http_errno_name(err))); + args.GetReturnValue().Set(e); } } static void Reinitialize(const FunctionCallbackInfo<Value>& args) { - HandleScope scope(node_isolate); + Environment* env = Environment::GetCurrent(args.GetIsolate()); + HandleScope handle_scope(args.GetIsolate()); http_parser_type type = static_cast<http_parser_type>(args[0]->Int32Value()); assert(type == HTTP_REQUEST || type == HTTP_RESPONSE); Parser* parser = ObjectWrap::Unwrap<Parser>(args.This()); + // Should always be called from the same context. + assert(env == parser->env()); parser->Init(type); } @@ -536,6 +534,12 @@ class Parser : public ObjectWrap { } + inline Environment* env() const { + return env_; + } + + + Environment* const env_; http_parser parser_; StringPtr fields_[32]; // header fields StringPtr values_[32]; // header values @@ -544,12 +548,27 @@ class Parser : public ObjectWrap { int num_values_; bool have_flushed_; bool got_exception_; + Local<Object> current_buffer_; + size_t current_buffer_len_; + char* current_buffer_data_; + static const struct http_parser_settings settings; }; -void InitHttpParser(Handle<Object> target) { - HandleScope scope(node_isolate); +const struct http_parser_settings Parser::settings = { + Parser::on_message_begin, + Parser::on_url, + Parser::on_header_field, + Parser::on_header_value, + Parser::on_headers_complete, + Parser::on_body, + Parser::on_message_complete +}; + +void InitHttpParser(Handle<Object> target, + Handle<Value> unused, + Handle<Context> context) { Local<FunctionTemplate> t = FunctionTemplate::New(Parser::New); t->InstanceTemplate()->SetInternalFieldCount(1); t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "HTTPParser")); @@ -573,33 +592,8 @@ void InitHttpParser(Handle<Object> target) { target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "HTTPParser"), t->GetFunction()); - -#define X(num, name, string) \ - name ## _sym = OneByteString(node_isolate, #string); - HTTP_METHOD_MAP(X) -#undef X - unknown_method_sym = FIXED_ONE_BYTE_STRING(node_isolate, "UNKNOWN_METHOD"); - - method_sym = FIXED_ONE_BYTE_STRING(node_isolate, "method"); - status_code_sym = FIXED_ONE_BYTE_STRING(node_isolate, "statusCode"); - http_version_sym = FIXED_ONE_BYTE_STRING(node_isolate, "httpVersion"); - version_major_sym = FIXED_ONE_BYTE_STRING(node_isolate, "versionMajor"); - version_minor_sym = FIXED_ONE_BYTE_STRING(node_isolate, "versionMinor"); - should_keep_alive_sym = - FIXED_ONE_BYTE_STRING(node_isolate, "shouldKeepAlive"); - upgrade_sym = FIXED_ONE_BYTE_STRING(node_isolate, "upgrade"); - headers_sym = FIXED_ONE_BYTE_STRING(node_isolate, "headers"); - url_sym = FIXED_ONE_BYTE_STRING(node_isolate, "url"); - - settings.on_message_begin = Parser::on_message_begin; - settings.on_url = Parser::on_url; - settings.on_header_field = Parser::on_header_field; - settings.on_header_value = Parser::on_header_value; - settings.on_headers_complete = Parser::on_headers_complete; - settings.on_body = Parser::on_body; - settings.on_message_complete = Parser::on_message_complete; } } // namespace node -NODE_MODULE(node_http_parser, node::InitHttpParser) +NODE_MODULE_CONTEXT_AWARE(node_http_parser, node::InitHttpParser) |