You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
6.9 KiB

#include "node.h"
#include "http.h"
#include <http_parser.h>
#include <assert.h>
#include <stdio.h>
#include <strings.h>
#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<FunctionTemplate> HTTPConnection::client_constructor_template;
Persistent<FunctionTemplate> HTTPConnection::server_constructor_template;
void
HTTPConnection::Initialize (Handle<Object> target)
{
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(NewClient);
client_constructor_template = Persistent<FunctionTemplate>::New(t);
client_constructor_template->Inherit(Connection::constructor_template);
client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction());
t = FunctionTemplate::New(NewServer);
server_constructor_template = Persistent<FunctionTemplate>::New(t);
server_constructor_template->Inherit(Connection::constructor_template);
server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
}
Handle<Value>
HTTPConnection::NewClient (const Arguments& args)
{
HandleScope scope;
HTTPConnection *connection = new HTTPConnection(HTTP_RESPONSE);
connection->Wrap(args.This());
return args.This();
}
Handle<Value>
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<const char*>(buf), len);
if (http_parser_has_error(&parser_)) ForceClose();
}
int
HTTPConnection::on_message_begin (http_parser *parser)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
assert(connection->attached_);
connection->Emit("message_begin", 0, NULL);
return 0;
}
int
HTTPConnection::on_message_complete (http_parser *parser)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
assert(connection->attached_);
connection->Emit("message_complete", 0, NULL);
return 0;
}
int
HTTPConnection::on_uri (http_parser *parser, const char *buf, size_t len)
{
HandleScope scope;
HTTPConnection *connection = static_cast<HTTPConnection*>(parser->data);
assert(connection->attached_);
Local<Value> argv[1] = { String::New(buf, len) };
connection->Emit("uri", 1, argv);
return 0;
}
int
HTTPConnection::on_header_field (http_parser *parser, const char *buf, size_t len)
{
HandleScope scope;
HTTPConnection *connection = static_cast<HTTPConnection*>(parser->data);
assert(connection->attached_);
Local<Value> argv[1] = { String::New(buf, len) };
connection->Emit("header_field", 1, argv);
return 0;
}
int
HTTPConnection::on_header_value (http_parser *parser, const char *buf, size_t len)
{
HandleScope scope;
HTTPConnection *connection = static_cast<HTTPConnection*>(parser->data);
assert(connection->attached_);
Local<Value> argv[1] = { String::New(buf, len) };
connection->Emit("header_value", 1, argv);
return 0;
}
static inline Local<String>
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<String> method = String::NewSymbol(s);
return scope.Close(method);
}
int
HTTPConnection::on_headers_complete (http_parser *parser)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
assert(connection->attached_);
HandleScope scope;
Local<Object> 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<Value> argv[1] = { message_info };
connection->Emit("headers_complete", 1, argv);
return 0;
}
int
HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len)
{
assert(len != 0);
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
assert(connection->attached_);
HandleScope scope;
Handle<Value> argv[1];
// TODO each message should have their encoding.
// don't look at the conneciton for encoding
if (connection->encoding_ == RAW) {
// raw encoding
Local<Array> array = Array::New(len);
for (size_t i = 0; i < len; i++) {
unsigned char val = reinterpret_cast<const unsigned char*>(buf)[i];
array->Set(Integer::New(i), Integer::New(val));
}
argv[0] = array;
} else {
// utf8 or ascii encoding
Handle<String> chunk = String::New((const char*)buf, len);
argv[0] = chunk;
}
connection->Emit("body", 1, argv);
return 0;
}
Persistent<FunctionTemplate> HTTPServer::constructor_template;
void
HTTPServer::Initialize (Handle<Object> target)
{
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
constructor_template = Persistent<FunctionTemplate>::New(t);
constructor_template->Inherit(Server::constructor_template);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
target->Set(String::NewSymbol("Server"), constructor_template->GetFunction());
}
Handle<Value>
HTTPServer::New (const Arguments& args)
{
HandleScope scope;
HTTPServer *server = new HTTPServer();
server->Wrap(args.This());
return args.This();
}
Handle<FunctionTemplate>
HTTPServer::GetConnectionTemplate (void)
{
return HTTPConnection::server_constructor_template;
}
Connection*
HTTPServer::UnwrapConnection (Local<Object> connection)
{
HandleScope scope;
return ObjectWrap::Unwrap<HTTPConnection>(connection);
}