#include #include #include #include using namespace v8; using namespace node; Persistent HTTPConnection::client_constructor_template; Persistent HTTPConnection::server_constructor_template; static Persistent method_symbol; static Persistent status_code_symbol; static Persistent http_version_symbol; static Persistent version_major_symbol; static Persistent version_minor_symbol; static Persistent should_keep_alive_symbol; static Persistent message_begin_symbol; static Persistent message_complete_symbol; static Persistent url_symbol; static Persistent query_string_symbol; static Persistent path_symbol; static Persistent fragment_symbol; static Persistent header_field_symbol; static Persistent header_value_symbol; static Persistent header_complete_symbol; static Persistent body_symbol; static Persistent end_symbol; static Persistent delete_sym; static Persistent get_sym; static Persistent head_sym; static Persistent post_sym; static Persistent put_sym; static Persistent connect_sym; static Persistent options_sym; static Persistent trace_sym; static Persistent copy_sym; static Persistent lock_sym; static Persistent mkcol_sym; static Persistent move_sym; static Persistent propfind_sym; static Persistent proppatch_sym; static Persistent unlock_sym; static Persistent unknown_method_sym; void HTTPConnection::Initialize (Handle target) { HandleScope scope; Local t = FunctionTemplate::New(NewClient); client_constructor_template = Persistent::New(t); client_constructor_template->Inherit(Connection::constructor_template); client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1); client_constructor_template->SetClassName(String::NewSymbol("Client")); NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "resetParser", ResetParser); target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction()); t = FunctionTemplate::New(NewServer); server_constructor_template = Persistent::New(t); server_constructor_template->Inherit(Connection::constructor_template); server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1); NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "resetParser", ResetParser); server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection")); end_symbol = NODE_PSYMBOL("end"); } Handle HTTPConnection::NewClient (const Arguments& args) { HandleScope scope; HTTPConnection *connection = new HTTPConnection(HTTP_RESPONSE); connection->Wrap(args.This()); return args.This(); } Handle HTTPConnection::NewServer (const Arguments& args) { HandleScope scope; HTTPConnection *connection = new HTTPConnection(HTTP_REQUEST); connection->Wrap(args.This()); return args.This(); } Handle HTTPConnection::ResetParser(const Arguments& args) { HandleScope scope; HTTPConnection *connection = ObjectWrap::Unwrap(args.Holder()); connection->ResetParser(); return Undefined(); } void HTTPConnection::OnReceive (const void *buf, size_t len) { HandleScope scope; assert(refs_); size_t nparsed; nparsed = http_parser_execute(&parser_, static_cast(buf), len); if (nparsed != len) { ForceClose(); } } void HTTPConnection::OnEOF () { HandleScope scope; assert(refs_); size_t nparsed; nparsed = http_parser_execute(&parser_, NULL, 0); Emit(end_symbol, 0, NULL); } int HTTPConnection::on_message_begin (http_parser *parser) { if (message_begin_symbol.IsEmpty()) { method_symbol = NODE_PSYMBOL("method"); status_code_symbol = NODE_PSYMBOL("statusCode"); http_version_symbol = NODE_PSYMBOL("httpVersion"); version_major_symbol = NODE_PSYMBOL("versionMajor"); version_minor_symbol = NODE_PSYMBOL("versionMinor"); should_keep_alive_symbol = NODE_PSYMBOL("should_keep_alive"); message_begin_symbol = NODE_PSYMBOL("messageBegin"); message_complete_symbol = NODE_PSYMBOL("messageComplete"); url_symbol = NODE_PSYMBOL("url"); query_string_symbol = NODE_PSYMBOL("queryString"); path_symbol = NODE_PSYMBOL("path"); fragment_symbol = NODE_PSYMBOL("fragment"); header_field_symbol = NODE_PSYMBOL("headerField"); header_value_symbol = NODE_PSYMBOL("headerValue"); header_complete_symbol = NODE_PSYMBOL("headerComplete"); body_symbol = NODE_PSYMBOL("body"); delete_sym = NODE_PSYMBOL("DELETE"); get_sym = NODE_PSYMBOL("GET"); head_sym = NODE_PSYMBOL("HEAD"); post_sym = NODE_PSYMBOL("POST"); put_sym = NODE_PSYMBOL("PUT"); connect_sym = NODE_PSYMBOL("CONNECT"); options_sym = NODE_PSYMBOL("OPTIONS"); trace_sym = NODE_PSYMBOL("TRACE"); copy_sym = NODE_PSYMBOL("COPY"); lock_sym = NODE_PSYMBOL("LOCK"); mkcol_sym = NODE_PSYMBOL("MKCOL"); move_sym = NODE_PSYMBOL("MOVE"); propfind_sym = NODE_PSYMBOL("PROPFIND"); proppatch_sym = NODE_PSYMBOL("PROPPATCH"); unlock_sym = NODE_PSYMBOL("UNLOCK"); unknown_method_sym = NODE_PSYMBOL("UNKNOWN_METHOD"); } HTTPConnection *connection = static_cast (parser->data); assert(connection->refs_); connection->Emit(message_begin_symbol, 0, NULL); return 0; } int HTTPConnection::on_message_complete (http_parser *parser) { HTTPConnection *connection = static_cast (parser->data); assert(connection->refs_); connection->Emit(message_complete_symbol, 0, NULL); return 0; } int HTTPConnection::on_url (http_parser *parser, const char *buf, size_t len) { HTTPConnection *connection = static_cast(parser->data); assert(connection->refs_); Local argv[1] = { String::New(buf, len) }; connection->Emit(url_symbol, 1, argv); return 0; } int HTTPConnection::on_query_string (http_parser *parser, const char *buf, size_t len) { HTTPConnection *connection = static_cast(parser->data); assert(connection->refs_); Local argv[1] = { String::New(buf, len) }; connection->Emit(query_string_symbol, 1, argv); return 0; } int HTTPConnection::on_path (http_parser *parser, const char *buf, size_t len) { HTTPConnection *connection = static_cast(parser->data); assert(connection->refs_); Local argv[1] = { String::New(buf, len) }; connection->Emit(path_symbol, 1, argv); return 0; } int HTTPConnection::on_fragment (http_parser *parser, const char *buf, size_t len) { HTTPConnection *connection = static_cast(parser->data); assert(connection->refs_); Local argv[1] = { String::New(buf, len) }; connection->Emit(fragment_symbol, 1, argv); return 0; } const static char normalizer[] = "\0------------------------------" "-----------------0123456789-----" "--abcdefghijklmnopqrstuvwxyz----" "--abcdefghijklmnopqrstuvwxyz----" "--------------------------------" "--------------------------------" "--------------------------------" "--------------------------------"; int HTTPConnection::on_header_field (http_parser *parser, const char *buf, size_t len) { HTTPConnection *connection = static_cast(parser->data); assert(connection->refs_); // NORMALIZE size_t i; char *nonconstbuf = (char*)buf; // FIXME for (i = 0; i < len; i++) { nonconstbuf[i] = normalizer[buf[i]]; } Local argv[1] = { String::New(buf, len) }; connection->Emit(header_field_symbol, 1, argv); return 0; } int HTTPConnection::on_header_value (http_parser *parser, const char *buf, size_t len) { HTTPConnection *connection = static_cast(parser->data); assert(connection->refs_); Local argv[1] = { String::New(buf, len) }; connection->Emit(header_value_symbol, 1, argv); return 0; } static inline Persistent method_to_str(enum http_method m) { switch (m) { case HTTP_DELETE: return delete_sym; case HTTP_GET: return get_sym; case HTTP_HEAD: return head_sym; case HTTP_POST: return post_sym; case HTTP_PUT: return put_sym; case HTTP_CONNECT: return connect_sym; case HTTP_OPTIONS: return options_sym; case HTTP_TRACE: return trace_sym; case HTTP_COPY: return copy_sym; case HTTP_LOCK: return lock_sym; case HTTP_MKCOL: return mkcol_sym; case HTTP_MOVE: return move_sym; case HTTP_PROPFIND: return propfind_sym; case HTTP_PROPPATCH: return proppatch_sym; case HTTP_UNLOCK: return unlock_sym; default: return unknown_method_sym; } } int HTTPConnection::on_headers_complete (http_parser *parser) { HTTPConnection *connection = static_cast (parser->data); assert(connection->refs_); Local message_info = Object::New(); // METHOD if (connection->type_ == HTTP_REQUEST) { message_info->Set(method_symbol, method_to_str(connection->parser_.method)); } // STATUS if (connection->type_ == HTTP_RESPONSE) { message_info->Set(status_code_symbol, Integer::New(connection->parser_.status_code)); } // VERSION char version[10]; snprintf( version , 10 , "%d.%d" , connection->parser_.http_major , connection->parser_.http_minor ); message_info->Set(http_version_symbol, String::New(version)); message_info->Set(version_major_symbol, Integer::New(connection->parser_.http_major)); message_info->Set(version_minor_symbol, Integer::New(connection->parser_.http_minor)); message_info->Set(should_keep_alive_symbol, http_should_keep_alive(&connection->parser_) ? True() : False()); Local argv[1] = { message_info }; connection->Emit(header_complete_symbol, 1, argv); return 0; } int HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len) { assert(len != 0); HTTPConnection *connection = static_cast (parser->data); assert(connection->refs_); // TODO each message should have their encoding. // don't look at the conneciton for encoding Local data = Encode(buf, len, connection->encoding_); connection->Emit(body_symbol, 1, &data); return 0; } Persistent HTTPServer::constructor_template; void HTTPServer::Initialize (Handle target) { HandleScope scope; Local t = FunctionTemplate::New(New); constructor_template = Persistent::New(t); constructor_template->Inherit(Server::constructor_template); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); constructor_template->SetClassName(String::NewSymbol("Server")); target->Set(String::NewSymbol("Server"), constructor_template->GetFunction()); } Handle HTTPServer::New (const Arguments& args) { HandleScope scope; HTTPServer *server = new HTTPServer(); server->Wrap(args.This()); return args.This(); } Handle HTTPServer::GetConnectionTemplate (void) { return HTTPConnection::server_constructor_template; } Connection* HTTPServer::UnwrapConnection (Local connection) { HandleScope scope; return ObjectWrap::Unwrap(connection); }