#include #include #include #include #define METHOD_SYMBOL String::NewSymbol("method") #define STATUS_CODE_SYMBOL String::NewSymbol("statusCode") #define HTTP_VERSION_SYMBOL String::NewSymbol("httpVersion") #define SHOULD_KEEP_ALIVE_SYMBOL String::NewSymbol("should_keep_alive") using namespace v8; using namespace node; Persistent HTTPConnection::client_constructor_template; Persistent HTTPConnection::server_constructor_template; 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")); 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); server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection")); } 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(); } void HTTPConnection::OnReceive (const void *buf, size_t len) { assert(attached_); http_parser_execute(&parser_, static_cast(buf), len); if (http_parser_has_error(&parser_)) ForceClose(); } int HTTPConnection::on_message_begin (http_parser *parser) { HTTPConnection *connection = static_cast (parser->data); assert(connection->attached_); connection->Emit("messageBegin", 0, NULL); return 0; } int HTTPConnection::on_message_complete (http_parser *parser) { HTTPConnection *connection = static_cast (parser->data); assert(connection->attached_); connection->Emit("messageComplete", 0, NULL); return 0; } int HTTPConnection::on_uri (http_parser *parser, const char *buf, size_t len) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); Local argv[1] = { String::New(buf, len) }; connection->Emit("uri", 1, argv); return 0; } int HTTPConnection::on_query_string (http_parser *parser, const char *buf, size_t len) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); Local argv[1] = { String::New(buf, len) }; connection->Emit("queryString", 1, argv); return 0; } int HTTPConnection::on_path (http_parser *parser, const char *buf, size_t len) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); Local argv[1] = { String::New(buf, len) }; connection->Emit("path", 1, argv); return 0; } int HTTPConnection::on_fragment (http_parser *parser, const char *buf, size_t len) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); Local argv[1] = { String::New(buf, len) }; connection->Emit("fragment", 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) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); // 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("headerField", 1, argv); return 0; } int HTTPConnection::on_header_value (http_parser *parser, const char *buf, size_t len) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); Local argv[1] = { String::New(buf, len) }; connection->Emit("headerValue", 1, argv); return 0; } static inline Local GetMethod (int method) { const char *s; switch (method) { case HTTP_COPY: s = "COPY"; break; case HTTP_DELETE: s = "DELETE"; break; case HTTP_GET: s = "GET"; break; case HTTP_HEAD: s = "HEAD"; break; case HTTP_LOCK: s = "LOCK"; break; case HTTP_MKCOL: s = "MKCOL"; break; case HTTP_MOVE: s = "MOVE"; break; case HTTP_OPTIONS: s = "OPTIONS"; break; case HTTP_POST: s = "POST"; break; case HTTP_PROPFIND: s = "PROPFIND"; break; case HTTP_PROPPATCH: s = "PROPPATCH"; break; case HTTP_PUT: s = "PUT"; break; case HTTP_TRACE: s = "TRACE"; break; case HTTP_UNLOCK: s = "UNLOCK"; break; } HandleScope scope; Local method = String::NewSymbol(s); return scope.Close(method); } int HTTPConnection::on_headers_complete (http_parser *parser) { HTTPConnection *connection = static_cast (parser->data); assert(connection->attached_); HandleScope scope; Local message_info = Object::New(); // METHOD if (connection->parser_.type == HTTP_REQUEST) message_info->Set(METHOD_SYMBOL, GetMethod(connection->parser_.method)); // STATUS if (connection->parser_.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_.version_major , connection->parser_.version_minor ); message_info->Set(HTTP_VERSION_SYMBOL, String::New(version)); message_info->Set(SHOULD_KEEP_ALIVE_SYMBOL, http_parser_should_keep_alive(&connection->parser_) ? True() : False()); Local argv[1] = { message_info }; connection->Emit("headerComplete", 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->attached_); HandleScope scope; // 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", 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); }