extract headers, status_code, path, http version from http messages.
still a work in progress.
This commit is contained in:
parent
5a071ad72f
commit
be6b3acf0e
174
src/http.cc
174
src/http.cc
@ -5,16 +5,73 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.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 v8;
|
||||||
using namespace node;
|
using namespace node;
|
||||||
using namespace std;
|
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
|
void
|
||||||
HTTPClient::Initialize (Handle<Object> target)
|
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
|
||||||
|
HTTPConnection::Initialize (Handle<Object> target)
|
||||||
{
|
{
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(HTTPClient::v8New);
|
Local<FunctionTemplate> t = FunctionTemplate::New(HTTPConnection::v8New);
|
||||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
target->Set(String::NewSymbol("HTTPClient"), t->GetFunction());
|
target->Set(String::NewSymbol("HTTPClient"), t->GetFunction());
|
||||||
|
|
||||||
@ -25,7 +82,7 @@ HTTPClient::Initialize (Handle<Object> target)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<Value>
|
Handle<Value>
|
||||||
HTTPClient::v8New (const Arguments& args)
|
HTTPConnection::v8New (const Arguments& args)
|
||||||
{
|
{
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
@ -44,18 +101,121 @@ HTTPClient::v8New (const Arguments& args)
|
|||||||
|
|
||||||
Local<Object> protocol_instance = protocol->NewInstance(argc, argv);
|
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();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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)
|
: 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
15
src/http.h
@ -3,19 +3,30 @@
|
|||||||
|
|
||||||
#include <v8.h>
|
#include <v8.h>
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include <http_parser.h>
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
class HTTPClient : public node::Connection {
|
class HTTPConnection : public Connection {
|
||||||
public:
|
public:
|
||||||
static void Initialize (v8::Handle<v8::Object> target);
|
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);
|
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
||||||
protected:
|
protected:
|
||||||
void OnReceive (const void *buf, size_t len);
|
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
|
} // namespace node
|
||||||
|
25
src/http.js
Normal file
25
src/http.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
};
|
@ -178,4 +178,3 @@ clearInterval = clearTimeout;
|
|||||||
|
|
||||||
loadScript(ARGV[1], this);
|
loadScript(ARGV[1], this);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -56,9 +56,6 @@ ObjectWrap::MakeWeak (Persistent<Value> _, void *data)
|
|||||||
delete w;
|
delete w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Extracts a C string from a V8 Utf8Value.
|
// Extracts a C string from a V8 Utf8Value.
|
||||||
const char*
|
const char*
|
||||||
ToCString(const v8::String::Utf8Value& value)
|
ToCString(const v8::String::Utf8Value& value)
|
||||||
@ -252,11 +249,14 @@ main (int argc, char *argv[])
|
|||||||
Connection::Initialize(g);
|
Connection::Initialize(g);
|
||||||
node::Init_timer(g);
|
node::Init_timer(g);
|
||||||
node::Init_file(g);
|
node::Init_file(g);
|
||||||
HTTPClient::Initialize(g);
|
HTTPConnection::Initialize(g);
|
||||||
|
|
||||||
// NATIVE JAVASCRIPT MODULES
|
// NATIVE JAVASCRIPT MODULES
|
||||||
TryCatch try_catch;
|
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"));
|
ExecuteString(String::New(native_file), String::New("file.js"));
|
||||||
if (try_catch.HasCaught()) goto native_js_error;
|
if (try_catch.HasCaught()) goto native_js_error;
|
||||||
|
|
||||||
|
2
wscript
2
wscript
@ -137,7 +137,7 @@ def build(bld):
|
|||||||
js2c.JS2C(source, targets)
|
js2c.JS2C(source, targets)
|
||||||
|
|
||||||
native_cc = bld.new_task_gen(
|
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",
|
target="src/natives.h",
|
||||||
rule=javascript_in_c,
|
rule=javascript_in_c,
|
||||||
before="cxx"
|
before="cxx"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user