2009-03-04 00:31:37 +01:00
|
|
|
#include "node.h"
|
2009-04-18 15:35:42 +02:00
|
|
|
#include "http.h"
|
2009-05-03 14:09:16 +02:00
|
|
|
#include <http_parser.h>
|
2009-02-16 01:34:45 +01:00
|
|
|
|
2009-04-04 14:50:15 +02:00
|
|
|
#include <assert.h>
|
2009-05-03 14:09:16 +02:00
|
|
|
#include <stdio.h>
|
2009-05-07 12:15:01 +02:00
|
|
|
#include <strings.h>
|
2009-04-04 14:50:15 +02:00
|
|
|
|
2009-05-07 12:15:01 +02:00
|
|
|
#define ENCODING_SYMBOL String::NewSymbol("encoding")
|
2009-05-03 21:06:20 +02:00
|
|
|
|
2009-05-07 12:15:01 +02:00
|
|
|
#define MESSAGE_HANDLER_SYMBOL String::NewSymbol("messageHandler")
|
|
|
|
|
|
|
|
#define ON_MESSAGE_SYMBOL String::NewSymbol("onMessage")
|
|
|
|
#define ON_PATH_SYMBOL String::NewSymbol("onPath")
|
|
|
|
#define ON_QUERY_STRING_SYMBOL String::NewSymbol("onQueryString")
|
|
|
|
#define ON_URI_SYMBOL String::NewSymbol("onURI")
|
|
|
|
#define ON_FRAGMENT_SYMBOL String::NewSymbol("onFragment")
|
|
|
|
#define ON_HEADER_FIELD_SYMBOL String::NewSymbol("onHeaderField")
|
|
|
|
#define ON_HEADER_VALUE_SYMBOL String::NewSymbol("onHeaderValue")
|
|
|
|
#define ON_HEADERS_COMPLETE_SYMBOL String::NewSymbol("onHeadersComplete")
|
|
|
|
#define ON_BODY_SYMBOL String::NewSymbol("onBody")
|
|
|
|
#define ON_MESSAGE_COMPLETE_SYMBOL String::NewSymbol("onMessageComplete")
|
2009-05-04 12:08:13 +02:00
|
|
|
|
2009-05-12 11:39:42 +02:00
|
|
|
#define STATUS_CODE_SYMBOL String::NewSymbol("status_code")
|
|
|
|
#define HTTP_VERSION_SYMBOL String::NewSymbol("http_version")
|
|
|
|
#define SHOULD_KEEP_ALIVE_SYMBOL String::NewSymbol("should_keep_alive")
|
2009-05-03 21:06:20 +02:00
|
|
|
|
2009-02-16 01:34:45 +01:00
|
|
|
using namespace v8;
|
2009-05-03 14:09:16 +02:00
|
|
|
using namespace node;
|
2009-02-16 01:34:45 +01:00
|
|
|
using namespace std;
|
|
|
|
|
2009-05-04 17:19:04 +02:00
|
|
|
Persistent<FunctionTemplate> HTTPConnection::client_constructor_template;
|
|
|
|
Persistent<FunctionTemplate> HTTPConnection::server_constructor_template;
|
2009-05-04 15:39:36 +02:00
|
|
|
|
2009-05-06 14:54:28 +02:00
|
|
|
static Persistent<Object> http_module;
|
|
|
|
|
2009-03-06 19:49:52 +01:00
|
|
|
void
|
2009-05-03 21:06:20 +02:00
|
|
|
HTTPConnection::Initialize (Handle<Object> target)
|
2009-02-24 19:13:58 +01:00
|
|
|
{
|
2009-03-03 02:36:08 +01:00
|
|
|
HandleScope scope;
|
2009-02-23 13:48:34 +01:00
|
|
|
|
2009-05-04 17:38:17 +02:00
|
|
|
Local<FunctionTemplate> t = FunctionTemplate::New(v8NewClient);
|
2009-05-04 17:19:04 +02:00
|
|
|
client_constructor_template = Persistent<FunctionTemplate>::New(t);
|
|
|
|
client_constructor_template->Inherit(Connection::constructor_template);
|
|
|
|
client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
2009-05-15 16:28:10 +02:00
|
|
|
target->Set(String::NewSymbol("LowLevelClient"), client_constructor_template->GetFunction());
|
2009-05-04 17:19:04 +02:00
|
|
|
|
2009-05-04 17:38:17 +02:00
|
|
|
t = FunctionTemplate::New(v8NewServer);
|
2009-05-04 17:19:04 +02:00
|
|
|
server_constructor_template = Persistent<FunctionTemplate>::New(t);
|
|
|
|
server_constructor_template->Inherit(Connection::constructor_template);
|
|
|
|
server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
2009-05-06 14:54:28 +02:00
|
|
|
target->Set(String::NewSymbol("ServerSideSocket"),
|
2009-05-04 17:19:04 +02:00
|
|
|
server_constructor_template->GetFunction());
|
2009-02-16 01:34:45 +01:00
|
|
|
}
|
|
|
|
|
2009-05-03 14:09:16 +02:00
|
|
|
Handle<Value>
|
2009-05-04 15:39:36 +02:00
|
|
|
HTTPConnection::v8NewClient (const Arguments& args)
|
2009-03-03 19:17:33 +01:00
|
|
|
{
|
|
|
|
HandleScope scope;
|
2009-05-15 16:28:10 +02:00
|
|
|
|
|
|
|
HTTPConnection *connection = new HTTPConnection(args.This(), HTTP_RESPONSE);
|
|
|
|
ObjectWrap::InformV8ofAllocation(connection);
|
|
|
|
|
2009-05-04 15:39:36 +02:00
|
|
|
return args.This();
|
|
|
|
}
|
2009-03-03 01:56:15 +01:00
|
|
|
|
2009-05-04 15:39:36 +02:00
|
|
|
Handle<Value>
|
|
|
|
HTTPConnection::v8NewServer (const Arguments& args)
|
|
|
|
{
|
|
|
|
HandleScope scope;
|
2009-05-15 16:28:10 +02:00
|
|
|
|
|
|
|
HTTPConnection *connection = new HTTPConnection(args.This(), HTTP_REQUEST);
|
|
|
|
ObjectWrap::InformV8ofAllocation(connection);
|
|
|
|
|
2009-05-03 14:09:16 +02:00
|
|
|
return args.This();
|
2009-02-23 13:48:34 +01:00
|
|
|
}
|
|
|
|
|
2009-03-03 01:56:15 +01:00
|
|
|
void
|
2009-05-03 21:06:20 +02:00
|
|
|
HTTPConnection::OnReceive (const void *buf, size_t len)
|
|
|
|
{
|
|
|
|
http_parser_execute(&parser_, static_cast<const char*>(buf), len);
|
|
|
|
|
2009-05-06 14:54:28 +02:00
|
|
|
if (http_parser_has_error(&parser_))
|
|
|
|
ForceClose();
|
2009-05-03 21:06:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
HTTPConnection::on_message_begin (http_parser *parser)
|
|
|
|
{
|
|
|
|
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
|
|
|
|
HandleScope scope;
|
|
|
|
|
2009-05-14 23:47:21 +02:00
|
|
|
Local<Value> on_message_v = connection->handle_->Get(ON_MESSAGE_SYMBOL);
|
2009-05-03 21:06:20 +02:00
|
|
|
if (!on_message_v->IsFunction()) return -1;
|
|
|
|
Handle<Function> on_message = Handle<Function>::Cast(on_message_v);
|
2009-05-06 14:54:28 +02:00
|
|
|
|
|
|
|
TryCatch try_catch;
|
2009-05-03 21:06:20 +02:00
|
|
|
Local<Object> message_handler = on_message->NewInstance();
|
2009-05-06 14:54:28 +02:00
|
|
|
if (try_catch.HasCaught()) {
|
|
|
|
fatal_exception(try_catch);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-05-03 21:06:20 +02:00
|
|
|
connection->handle_->SetHiddenValue(MESSAGE_HANDLER_SYMBOL, message_handler);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-06 14:54:28 +02:00
|
|
|
#define DEFINE_PARSER_CALLBACK(name, symbol) \
|
|
|
|
int \
|
|
|
|
HTTPConnection::name (http_parser *parser, const char *buf, size_t len) \
|
|
|
|
{ \
|
|
|
|
HandleScope scope; \
|
|
|
|
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data); \
|
|
|
|
Local<Value> message_handler_v = \
|
|
|
|
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL); \
|
|
|
|
if (message_handler_v->IsObject() == false) \
|
|
|
|
return -1; \
|
|
|
|
Local<Object> message_handler = message_handler_v->ToObject(); \
|
|
|
|
Local<Value> callback_v = message_handler->Get(symbol); \
|
|
|
|
if (callback_v->IsFunction() == false) \
|
|
|
|
return 0; \
|
|
|
|
Local<Function> callback = Local<Function>::Cast(callback_v); \
|
|
|
|
TryCatch try_catch; \
|
|
|
|
Local<Value> argv[1] = { String::New(buf, len) }; \
|
|
|
|
Local<Value> ret = callback->Call(message_handler, 1, argv); \
|
|
|
|
if (ret.IsEmpty()) { \
|
|
|
|
fatal_exception(try_catch); \
|
|
|
|
return -2; \
|
|
|
|
} \
|
|
|
|
if (ret->IsFalse()) return -3; \
|
|
|
|
return 0; \
|
2009-05-03 21:06:20 +02:00
|
|
|
}
|
|
|
|
|
2009-05-06 14:54:28 +02:00
|
|
|
DEFINE_PARSER_CALLBACK(on_uri, ON_URI_SYMBOL)
|
|
|
|
DEFINE_PARSER_CALLBACK(on_header_field, ON_HEADER_FIELD_SYMBOL)
|
|
|
|
DEFINE_PARSER_CALLBACK(on_header_value, ON_HEADER_VALUE_SYMBOL)
|
2009-05-03 21:06:20 +02:00
|
|
|
|
|
|
|
int
|
|
|
|
HTTPConnection::on_headers_complete (http_parser *parser)
|
2009-03-03 01:56:15 +01:00
|
|
|
{
|
2009-05-03 21:06:20 +02:00
|
|
|
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
|
2009-05-03 21:37:10 +02:00
|
|
|
HandleScope scope;
|
2009-05-03 21:06:20 +02:00
|
|
|
|
|
|
|
Local<Value> message_handler_v =
|
|
|
|
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
|
|
|
|
Local<Object> message_handler = message_handler_v->ToObject();
|
|
|
|
|
|
|
|
// STATUS
|
|
|
|
message_handler->Set(STATUS_CODE_SYMBOL,
|
|
|
|
Integer::New(connection->parser_.status_code));
|
|
|
|
|
|
|
|
// VERSION
|
|
|
|
char version[10];
|
2009-05-04 12:08:13 +02:00
|
|
|
snprintf( version
|
|
|
|
, 10
|
|
|
|
, "%d.%d"
|
|
|
|
, connection->parser_.version_major
|
|
|
|
, connection->parser_.version_minor
|
|
|
|
);
|
2009-05-03 21:06:20 +02:00
|
|
|
message_handler->Set(HTTP_VERSION_SYMBOL, String::New(version));
|
|
|
|
|
2009-05-11 23:38:41 +02:00
|
|
|
// SHOULD KEEP ALIVE
|
|
|
|
message_handler->Set( SHOULD_KEEP_ALIVE_SYMBOL
|
|
|
|
, http_parser_should_keep_alive(&connection->parser_) ? True() : False()
|
|
|
|
);
|
|
|
|
|
2009-05-03 21:06:20 +02:00
|
|
|
|
|
|
|
Local<Value> on_headers_complete_v = message_handler->Get(ON_HEADERS_COMPLETE_SYMBOL);
|
|
|
|
if (on_headers_complete_v->IsFunction() == false) return 0;
|
|
|
|
|
|
|
|
Handle<Function> on_headers_complete = Handle<Function>::Cast(on_headers_complete_v);
|
|
|
|
|
2009-05-06 14:54:28 +02:00
|
|
|
TryCatch try_catch;
|
|
|
|
Local<Value> ret = on_headers_complete->Call(message_handler, 0, NULL);
|
|
|
|
if (ret.IsEmpty()) {
|
|
|
|
fatal_exception(try_catch);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
if (ret->IsFalse()) return -3;
|
2009-05-03 21:06:20 +02:00
|
|
|
|
|
|
|
return 0;
|
2009-03-03 01:56:15 +01:00
|
|
|
}
|
2009-02-16 01:34:45 +01:00
|
|
|
|
2009-05-03 21:37:10 +02:00
|
|
|
int
|
|
|
|
HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len)
|
|
|
|
{
|
2009-05-07 12:15:01 +02:00
|
|
|
assert(len != 0);
|
2009-05-03 21:37:10 +02:00
|
|
|
|
|
|
|
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
|
|
|
|
HandleScope scope;
|
|
|
|
|
|
|
|
Local<Value> message_handler_v =
|
|
|
|
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
|
|
|
|
Local<Object> message_handler = message_handler_v->ToObject();
|
|
|
|
|
|
|
|
Local<Value> on_body_v = message_handler->Get(ON_BODY_SYMBOL);
|
|
|
|
if (on_body_v->IsFunction() == false) return 0;
|
|
|
|
Handle<Function> on_body = Handle<Function>::Cast(on_body_v);
|
|
|
|
|
2009-05-07 12:15:01 +02:00
|
|
|
/* Look at the value of message_handler.encoding to decide how to
|
|
|
|
* send the body chunk. This is rather sloppy and unnecesary. FIXME
|
|
|
|
*/
|
|
|
|
enum encoding encoding = RAW;
|
|
|
|
Local<Value> encoding_v = message_handler->Get(ENCODING_SYMBOL);
|
|
|
|
if (encoding_v->IsString()) {
|
|
|
|
Local<String> encoding_string = encoding_v->ToString();
|
|
|
|
char buf[5]; // need enough room for "utf8" or "raw"
|
|
|
|
encoding_string->WriteAscii(buf, 0, 4);
|
|
|
|
buf[4] = '\0';
|
|
|
|
if(strcasecmp(buf, "utf8") == 0)
|
|
|
|
encoding = UTF8;
|
|
|
|
}
|
2009-05-03 21:37:10 +02:00
|
|
|
|
2009-05-07 12:15:01 +02:00
|
|
|
Handle<Value> argv[1];
|
2009-05-06 14:54:28 +02:00
|
|
|
// TODO each message should have their encoding.
|
|
|
|
// don't look at the conneciton for encoding
|
2009-05-07 12:15:01 +02:00
|
|
|
if(encoding == UTF8) {
|
2009-05-03 21:37:10 +02:00
|
|
|
// utf8 encoding
|
|
|
|
Handle<String> chunk = String::New((const char*)buf, len);
|
|
|
|
argv[0] = chunk;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// raw encoding
|
|
|
|
Local<Array> array = Array::New(len);
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
char val = static_cast<const char*>(buf)[i];
|
|
|
|
array->Set(Integer::New(i), Integer::New(val));
|
|
|
|
}
|
|
|
|
argv[0] = array;
|
|
|
|
}
|
2009-05-06 14:54:28 +02:00
|
|
|
|
|
|
|
TryCatch try_catch;
|
2009-05-15 01:12:46 +02:00
|
|
|
Local<Value> ret = on_body->Call(message_handler, 1, argv);
|
2009-05-06 14:54:28 +02:00
|
|
|
if (ret.IsEmpty()) {
|
|
|
|
fatal_exception(try_catch);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
if (ret->IsFalse()) return -3;
|
|
|
|
|
2009-05-03 21:37:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
HTTPConnection::on_message_complete (http_parser *parser)
|
|
|
|
{
|
|
|
|
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
|
|
|
|
HandleScope scope;
|
|
|
|
|
|
|
|
Local<Value> message_handler_v =
|
|
|
|
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
|
|
|
|
Local<Object> message_handler = message_handler_v->ToObject();
|
2009-05-06 14:54:28 +02:00
|
|
|
connection->handle_->DeleteHiddenValue(MESSAGE_HANDLER_SYMBOL);
|
2009-05-03 21:37:10 +02:00
|
|
|
|
|
|
|
Local<Value> on_msg_complete_v = message_handler->Get(ON_MESSAGE_COMPLETE_SYMBOL);
|
2009-05-06 14:54:28 +02:00
|
|
|
if (on_msg_complete_v->IsFunction() == false)
|
|
|
|
return 0;
|
|
|
|
Handle<Function> on_msg_complete = Handle<Function>::Cast(on_msg_complete_v);
|
|
|
|
|
|
|
|
TryCatch try_catch;
|
|
|
|
Local<Value> ret = on_msg_complete->Call(message_handler, 0, NULL);
|
|
|
|
if (ret.IsEmpty()) {
|
|
|
|
fatal_exception(try_catch);
|
|
|
|
return -2;
|
2009-05-03 21:37:10 +02:00
|
|
|
}
|
2009-05-06 14:54:28 +02:00
|
|
|
if (ret->IsFalse()) return -3;
|
|
|
|
|
2009-05-03 21:37:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-14 23:47:21 +02:00
|
|
|
HTTPConnection::HTTPConnection (Handle<Object> handle, enum http_parser_type type)
|
|
|
|
: Connection(handle)
|
2009-03-03 01:56:15 +01:00
|
|
|
{
|
2009-05-03 21:06:20 +02:00
|
|
|
http_parser_init (&parser_, type);
|
|
|
|
parser_.on_message_begin = on_message_begin;
|
2009-05-04 12:08:13 +02:00
|
|
|
parser_.on_uri = on_uri;
|
2009-05-03 21:06:20 +02:00
|
|
|
parser_.on_header_field = on_header_field;
|
|
|
|
parser_.on_header_value = on_header_value;
|
|
|
|
parser_.on_headers_complete = on_headers_complete;
|
2009-05-03 21:37:10 +02:00
|
|
|
parser_.on_body = on_body;
|
|
|
|
parser_.on_message_complete = on_message_complete;
|
2009-05-03 21:06:20 +02:00
|
|
|
parser_.data = this;
|
|
|
|
}
|
|
|
|
|
2009-05-15 16:28:10 +02:00
|
|
|
|
|
|
|
HTTPConnection::~HTTPConnection ( )
|
|
|
|
{
|
|
|
|
V8::AdjustAmountOfExternalAllocatedMemory(-sizeof(HTTPConnection));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-04 17:19:04 +02:00
|
|
|
Persistent<FunctionTemplate> HTTPServer::constructor_template;
|
|
|
|
|
|
|
|
void
|
|
|
|
HTTPServer::Initialize (Handle<Object> target)
|
2009-05-04 15:39:36 +02:00
|
|
|
{
|
2009-05-04 17:19:04 +02:00
|
|
|
HandleScope scope;
|
|
|
|
|
2009-05-04 17:38:17 +02:00
|
|
|
Local<FunctionTemplate> t = FunctionTemplate::New(v8New);
|
2009-05-04 17:19:04 +02:00
|
|
|
constructor_template = Persistent<FunctionTemplate>::New(t);
|
|
|
|
constructor_template->Inherit(Acceptor::constructor_template);
|
|
|
|
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
2009-05-06 14:54:28 +02:00
|
|
|
target->Set(String::NewSymbol("LowLevelServer"), constructor_template->GetFunction());
|
2009-05-04 15:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Handle<Value>
|
|
|
|
HTTPServer::v8New (const Arguments& args)
|
|
|
|
{
|
2009-05-04 17:19:04 +02:00
|
|
|
HandleScope scope;
|
|
|
|
|
|
|
|
if (args.Length() < 1 || args[0]->IsFunction() == false)
|
|
|
|
return ThrowException(String::New("Must at give connection handler as the first argument"));
|
|
|
|
|
|
|
|
Local<Function> protocol_class = Local<Function>::Cast(args[0]);
|
|
|
|
Local<Object> options;
|
|
|
|
|
|
|
|
if (args.Length() > 1 && args[1]->IsObject()) {
|
|
|
|
options = args[1]->ToObject();
|
|
|
|
} else {
|
|
|
|
options = Object::New();
|
|
|
|
}
|
|
|
|
|
2009-05-15 16:28:10 +02:00
|
|
|
HTTPServer *s = new HTTPServer(args.This(), protocol_class, options);
|
|
|
|
ObjectWrap::InformV8ofAllocation(s);
|
2009-05-04 17:19:04 +02:00
|
|
|
|
|
|
|
return args.This();
|
2009-05-04 15:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Connection*
|
|
|
|
HTTPServer::OnConnection (struct sockaddr *addr, socklen_t len)
|
|
|
|
{
|
2009-05-04 17:19:04 +02:00
|
|
|
HandleScope scope;
|
|
|
|
|
2009-05-14 23:47:21 +02:00
|
|
|
Local<Function> connection_handler = GetConnectionHandler ();
|
|
|
|
if (connection_handler.IsEmpty()) {
|
2009-05-04 17:19:04 +02:00
|
|
|
Close();
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-05-04 15:39:36 +02:00
|
|
|
|
2009-05-15 01:36:51 +02:00
|
|
|
TryCatch try_catch;
|
|
|
|
|
2009-05-04 17:19:04 +02:00
|
|
|
Local<Object> connection_handle =
|
2009-05-14 23:47:21 +02:00
|
|
|
HTTPConnection::server_constructor_template->GetFunction()->NewInstance(0, NULL);
|
2009-05-04 17:19:04 +02:00
|
|
|
|
2009-05-15 01:36:51 +02:00
|
|
|
if (connection_handle.IsEmpty()) {
|
|
|
|
fatal_exception(try_catch);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-04 17:19:04 +02:00
|
|
|
HTTPConnection *connection = NODE_UNWRAP(HTTPConnection, connection_handle);
|
2009-05-15 01:12:46 +02:00
|
|
|
if (!connection) return NULL;
|
|
|
|
|
2009-05-04 17:19:04 +02:00
|
|
|
connection->SetAcceptor(handle_);
|
|
|
|
|
2009-05-15 01:47:17 +02:00
|
|
|
Handle<Value> argv[1] = { connection_handle };
|
|
|
|
|
|
|
|
Local<Value> ret = connection_handler->Call(handle_, 1, argv);
|
|
|
|
|
|
|
|
if (ret.IsEmpty())
|
|
|
|
fatal_exception(try_catch);
|
|
|
|
|
2009-05-04 17:19:04 +02:00
|
|
|
return connection;
|
|
|
|
}
|
2009-05-04 15:39:36 +02:00
|
|
|
|