Browse Source

extract headers, status_code, path, http version from http messages.

still a work in progress.
v0.7.4-release
Ryan 16 years ago
parent
commit
be6b3acf0e
  1. 174
      src/http.cc
  2. 15
      src/http.h
  3. 25
      src/http.js
  4. 1
      src/main.js
  5. 8
      src/node.cc
  6. 2
      wscript

174
src/http.cc

@ -5,16 +5,73 @@
#include <assert.h>
#include <stdio.h>
#define ON_MESSAGE_SYMBOL String::NewSymbol("onMessage")
#define MESSAGE_HANDLER_SYMBOL String::NewSymbol("messageHandler")
#define ON_HEADERS_COMPLETE_SYMBOL String::NewSymbol("onHeadersComplete")
#define PATH_SYMBOL String::NewSymbol("path")
#define STATUS_CODE_SYMBOL String::NewSymbol("status_code")
#define HTTP_VERSION_SYMBOL String::NewSymbol("http_version")
using namespace v8;
using namespace node;
using namespace std;
// Helper Functions
static Persistent<Function> _fill_field;
static Persistent<Function> _append_header_field;
static Persistent<Function> _append_header_value;
#define CATCH_NATIVE_HTTP_FUNCTION(variable, jsname) \
do { \
if (variable.IsEmpty()) { \
Local<Object> __g = Context::GetCurrent()->Global(); \
Local<Value> __node_v = __g->Get(String::NewSymbol("node")); \
Local<Object> __node = __node_v->ToObject(); \
Local<Value> __http_v = __node->Get(String::NewSymbol("http")); \
Local<Object> __http = __http_v->ToObject(); \
Local<Value> __value = __http->Get(String::NewSymbol(jsname)); \
Handle<Function> __function_handle = Handle<Function>::Cast(__value); \
variable = Persistent<Function>::New(__function_handle); \
} \
} while(0)
void
fillField (Handle<Value> message, Handle<Value> field, Handle<Value> value)
{
HandleScope scope;
CATCH_NATIVE_HTTP_FUNCTION(_fill_field, "fillField");
Handle<Value> argv[] = { message, field, value };
_fill_field->Call(message->ToObject(), 3, argv);
}
void
appendHeaderField (Handle<Value> message, Handle<Value> d)
{
HandleScope scope;
CATCH_NATIVE_HTTP_FUNCTION(_append_header_field, "appendHeaderField");
Handle<Value> argv[] = { message, d };
_append_header_field->Call(message->ToObject(), 2, argv);
}
void
appendHeaderValue (Handle<Value> message, Handle<Value> d)
{
HandleScope scope;
CATCH_NATIVE_HTTP_FUNCTION(_append_header_value, "appendHeaderValue");
Handle<Value> argv[] = { message, d };
_append_header_value->Call(message->ToObject(), 2, argv);
}
void
HTTPClient::Initialize (Handle<Object> target)
HTTPConnection::Initialize (Handle<Object> target)
{
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(HTTPClient::v8New);
Local<FunctionTemplate> t = FunctionTemplate::New(HTTPConnection::v8New);
t->InstanceTemplate()->SetInternalFieldCount(1);
target->Set(String::NewSymbol("HTTPClient"), t->GetFunction());
@ -25,7 +82,7 @@ HTTPClient::Initialize (Handle<Object> target)
}
Handle<Value>
HTTPClient::v8New (const Arguments& args)
HTTPConnection::v8New (const Arguments& args)
{
HandleScope scope;
@ -44,18 +101,121 @@ HTTPClient::v8New (const Arguments& args)
Local<Object> protocol_instance = protocol->NewInstance(argc, argv);
new HTTPClient(args.This(), protocol_instance);
// changeme the type should come from javascript
new HTTPConnection(args.This(), protocol_instance, HTTP_RESPONSE);
return args.This();
}
void
HTTPClient::OnReceive (const void *buf, size_t len)
HTTPConnection::OnReceive (const void *buf, size_t len)
{
printf("http client got data!\n");
http_parser_execute(&parser_, static_cast<const char*>(buf), len);
if (http_parser_has_error(&parser_)) {
// do something.
Close();
return;
}
}
HTTPClient::HTTPClient (Handle<Object> handle, Handle<Object> protocol)
int
HTTPConnection::on_message_begin (http_parser *parser)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
HandleScope scope;
Local<Object> protocol = connection->GetProtocol();
Local<Value> on_message_v = protocol->Get(ON_MESSAGE_SYMBOL);
if (!on_message_v->IsFunction()) return -1;
Handle<Function> on_message = Handle<Function>::Cast(on_message_v);
Local<Object> message_handler = on_message->NewInstance();
connection->handle_->SetHiddenValue(MESSAGE_HANDLER_SYMBOL, message_handler);
return 0;
}
int
HTTPConnection::on_path (http_parser *parser, const char *buf, size_t len)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
HandleScope scope;
Local<Value> message_handler_v =
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
fillField(message_handler_v, PATH_SYMBOL, String::New(buf, len));
return 0;
}
int
HTTPConnection::on_header_field (http_parser *parser, const char *buf, size_t len)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
HandleScope scope;
Local<Value> message_handler_v =
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
appendHeaderField(message_handler_v, String::New(buf, len));
return 0;
}
int
HTTPConnection::on_header_value (http_parser *parser, const char *buf, size_t len)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
HandleScope scope;
Local<Value> message_handler_v =
connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
appendHeaderValue(message_handler_v, String::New(buf, len));
return 0;
}
int
HTTPConnection::on_headers_complete (http_parser *parser)
{
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
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];
snprintf(version, 10, "%d.%d", connection->parser_.version_major, connection->parser_.version_minor);
message_handler->Set(HTTP_VERSION_SYMBOL, String::New(version));
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);
on_headers_complete->Call(message_handler, 0, NULL);
return 0;
}
HTTPConnection::HTTPConnection (Handle<Object> handle, Handle<Object> protocol, enum http_parser_type type)
: Connection(handle, protocol)
{
http_parser_init (&parser_, type);
parser_.on_message_begin = on_message_begin;
parser_.on_path = on_path;
parser_.on_query_string = NULL;
parser_.on_uri = NULL;
parser_.on_fragment = NULL;
parser_.on_header_field = on_header_field;
parser_.on_header_value = on_header_value;
parser_.on_headers_complete = on_headers_complete;
parser_.on_body = NULL;
parser_.on_message_complete = NULL;
parser_.data = this;
}

15
src/http.h

@ -3,19 +3,30 @@
#include <v8.h>
#include "net.h"
#include <http_parser.h>
namespace node {
class HTTPClient : public node::Connection {
class HTTPConnection : public Connection {
public:
static void Initialize (v8::Handle<v8::Object> target);
HTTPClient (v8::Handle<v8::Object> handle, v8::Handle<v8::Object> protocol);
HTTPConnection (v8::Handle<v8::Object> handle,
v8::Handle<v8::Object> protocol,
enum http_parser_type type);
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
protected:
void OnReceive (const void *buf, size_t len);
static int on_message_begin (http_parser *parser);
static int on_path (http_parser *parser, const char *at, size_t length);
static int on_header_field (http_parser *parser, const char *buf, size_t len);
static int on_header_value (http_parser *parser, const char *buf, size_t len);
static int on_headers_complete (http_parser *parser);
http_parser parser_;
};
} // namespace node

25
src/http.js

@ -0,0 +1,25 @@
node.http = {
fillField : function (msg, field, data) {
msg[field] = (msg[field] || "") + data;
},
appendHeaderField : function (msg, data) {
if (msg.hasOwnProperty("headers")) {
var last_pair = msg.headers[msg.headers.length-1];
if (last_pair.length == 1)
last_pair[0] += data;
else
msg.headers.push([data]);
} else {
msg.headers = [[data]];
}
},
appendHeaderValue : function (msg, data) {
var last_pair = msg.headers[msg.headers.length-1];
if (last_pair.length == 1)
last_pair[1] = data;
else
last_pair[1] += data;
}
};

1
src/main.js

@ -178,4 +178,3 @@ clearInterval = clearTimeout;
loadScript(ARGV[1], this);
})();

8
src/node.cc

@ -56,9 +56,6 @@ ObjectWrap::MakeWeak (Persistent<Value> _, void *data)
delete w;
}
// Extracts a C string from a V8 Utf8Value.
const char*
ToCString(const v8::String::Utf8Value& value)
@ -252,11 +249,14 @@ main (int argc, char *argv[])
Connection::Initialize(g);
node::Init_timer(g);
node::Init_file(g);
HTTPClient::Initialize(g);
HTTPConnection::Initialize(g);
// NATIVE JAVASCRIPT MODULES
TryCatch try_catch;
ExecuteString(String::New(native_http), String::New("http.js"));
if (try_catch.HasCaught()) goto native_js_error;
ExecuteString(String::New(native_file), String::New("file.js"));
if (try_catch.HasCaught()) goto native_js_error;

2
wscript

@ -137,7 +137,7 @@ def build(bld):
js2c.JS2C(source, targets)
native_cc = bld.new_task_gen(
source="src/file.js src/main.js",
source="src/http.js src/file.js src/main.js",
target="src/natives.h",
rule=javascript_in_c,
before="cxx"

Loading…
Cancel
Save