diff --git a/Makefile b/Makefile index fbf96ebfe6..82d1d344b6 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ V8INC = $(HOME)/src/v8/include V8LIB = $(HOME)/src/v8/libv8.a CFLAGS = -g -I$(V8INC) -Ideps/oi -DHAVE_GNUTLS=0 -Ideps/ebb -LDFLAGS = -lev -pthread #-lefence +LDFLAGS = -lev -pthread -lefence ifdef EVDIR CFLAGS += -I$(EVDIR)/include diff --git a/count-hosts.js b/count-hosts.js index c19bef015f..d341d6d1bc 100644 --- a/count-hosts.js +++ b/count-hosts.js @@ -1,13 +1,28 @@ + function Process(request) { + + // + // request.headers => { "Content-Length": "123" } + // request.http_version => "1.1" + // log("Processing " + request.path + ". method: " + request.method); // sends null on the last chunk. request.onBody = function (chunk) { - log("body chunk: '" + chunk + "'"); + log("got chunk length: " + chunk.length.toString(16) ); + if(chunk) { + this.respond(chunk.length.toString(16) + "\r\n" + chunk + "\r\n"); + } else { + this.respond("0\r\n\r\n"); + this.respond(null); + } } - request.respond("HTTP/1.0 200 OK\r\n") - request.respond("Content-Type: text-plain\r\n") - request.respond("Content-Length: 6\r\n\r\nhello\n"); - request.respond(null); // eof + request.respond("HTTP/1.0 200 OK\r\n"); + request.respond("Content-Type: text-plain\r\n"); + request.respond("Transfer-Encoding: chunked\r\n"); + request.respond("\r\n"); + //request.respond("Content-Length: 6\r\n\r\nhello\n"); + // } + diff --git a/server.cc b/server.cc index e0893152f5..5cc8256684 100644 --- a/server.cc +++ b/server.cc @@ -34,7 +34,7 @@ public: class HttpRequest { public: HttpRequest (Connection &c); - ~HttpRequest() { } + ~HttpRequest(); string path; @@ -44,7 +44,7 @@ class HttpRequest { Persistent js_object; }; -HttpRequest* UnwrapRequest +static HttpRequest* UnwrapRequest ( Handle obj ) { @@ -53,23 +53,44 @@ HttpRequest* UnwrapRequest return static_cast(ptr); } -Handle GetPath - ( Local name - , const AccessorInfo& info +static void make_onBody_callback + ( HttpRequest *request + , const char *base + , size_t length ) { - HttpRequest* request = UnwrapRequest(info.Holder()); - return String::New(request->path.c_str(), request->path.length()); + HandleScope handle_scope; + + Handle obj = request->js_object; + // XXX don't always allocate onBody strings + Handle onBody_val = obj->Get(String::New("onBody")); + if (!onBody_val->IsFunction()) return; + Handle onBody = Handle::Cast(onBody_val); + + TryCatch try_catch; + const int argc = 1; + Handle argv[argc]; + + if(length) { + Handle chunk = String::New(base, length); + argv[0] = chunk; + } else { + argv[0] = Null(); + } + + Handle result = onBody->Call(obj, argc, argv); + + if (result.IsEmpty()) { + String::Utf8Value error(try_catch.Exception()); + printf("error: %s\n", *error); + } } -Handle GetMethod - ( Local name - , const AccessorInfo& info +static Handle GetMethodString + ( int method ) { - HttpRequest* request = UnwrapRequest(info.Holder()); - // TODO allocate these strings only once. reference global - switch(request->parser_info.method) { + switch(method) { case EBB_COPY: return String::New("COPY"); case EBB_DELETE: return String::New("DELETE"); case EBB_GET: return String::New("GET"); @@ -84,12 +105,11 @@ Handle GetMethod case EBB_PUT: return String::New("PUT"); case EBB_TRACE: return String::New("TRACE"); case EBB_UNLOCK: return String::New("UNLOCK"); - default: - return Null(); } + return Null(); } -Handle RespondCallback +static Handle RespondCallback ( const Arguments& args ) { @@ -100,17 +120,22 @@ Handle RespondCallback // TODO Make sure that we write reponses in the correct order. With // keep-alive it's possible that one response can return before the last // one has been sent!!! + + printf("response called\n"); if(arg == Null()) { - request->connection.socket.on_drain = oi_socket_close; + printf("response got null\n"); + //delete request; } else { - Local s = arg->ToString(); + Handle s = arg->ToString(); + + printf("response called len %d\n", s->Length()); oi_buf *buf = oi_buf_new2(s->Length()); - s->WriteAscii(buf->base); + s->WriteAscii(buf->base, s->Length()); oi_socket_write(&request->connection.socket, buf); @@ -119,19 +144,46 @@ Handle RespondCallback return Undefined(); } +HttpRequest::~HttpRequest () +{ + //make_onBody_callback(this, NULL, 0); // EOF + + printf("request is being destructed\n"); + + connection.socket.on_drain = oi_socket_close; + + HandleScope scope; + // delete a reference to the respond method + //js_object->Delete(String::New("respond")); + js_object.Dispose(); +} + HttpRequest::HttpRequest (Connection &c) : connection(c) { ebb_request_init(&parser_info); +} + +static void on_path + ( ebb_request *req + , const char *buf + , size_t len + ) +{ + HttpRequest *request = static_cast (req->data); + request->path.append(buf, len); +} + +static void on_headers_complete + ( ebb_request *req + ) +{ + HttpRequest *request = static_cast (req->data); HandleScope handle_scope; if (request_template_.IsEmpty()) { Handle raw_template = ObjectTemplate::New(); raw_template->SetInternalFieldCount(1); - - // Add accessors for each of the fields of the request. - raw_template->SetAccessor(String::NewSymbol("path"), GetPath); - raw_template->SetAccessor(String::NewSymbol("method"), GetMethod); raw_template->Set(String::New("respond"), FunctionTemplate::New(RespondCallback)); request_template_ = Persistent::New(raw_template); @@ -143,32 +195,20 @@ HttpRequest::HttpRequest (Connection &c) : connection(c) // Wrap the raw C++ pointer in an External so it can be referenced // from within JavaScript. - Handle request_ptr = External::New(this); + Handle request_ptr = External::New(request); // Store the request pointer in the JavaScript wrapper. result->SetInternalField(0, request_ptr); - js_object = Persistent::New(result); -} - -static void on_path - ( ebb_request *req - , const char *buf - , size_t len - ) -{ - HttpRequest *request = static_cast (req->data); - request->path.append(buf, len); -} + result->Set ( String::NewSymbol("path") + , String::New(request->path.c_str(), request->path.length()) + ); -static void on_headers_complete - ( ebb_request *req - ) -{ - HttpRequest *request = static_cast (req->data); + result->Set ( String::NewSymbol("method") + , GetMethodString(request->parser_info.method) + ); - // Create a handle scope to keep the temporary object references. - HandleScope handle_scope; + Persistent js_object = Persistent::New(result); // Enter this processor's context so all the remaining operations // take place there @@ -180,9 +220,9 @@ static void on_headers_complete // Invoke the process function, giving the global object as 'this' // and one argument, the request. const int argc = 1; - Handle argv[argc] = { request->js_object }; - Handle result = process_->Call(context_->Global(), argc, argv); - if (result.IsEmpty()) { + Handle argv[argc] = { js_object }; + Handle r = process_->Call(context_->Global(), argc, argv); + if (r.IsEmpty()) { String::Utf8Value error(try_catch.Exception()); printf("error: %s\n", *error); } @@ -193,20 +233,26 @@ static void on_request_complete ) { HttpRequest *request = static_cast (req->data); + + //delete request; } + static void on_body ( ebb_request *req - , const char *chunk + , const char *base , size_t length ) { + printf("on body %d\n", length); + HttpRequest *request = static_cast (req->data); - + if(length) + make_onBody_callback(request, base, length); } -ebb_request * on_request +static ebb_request * on_request ( void *data ) { @@ -236,10 +282,14 @@ static void on_read { Connection *connection = static_cast (socket->data); ebb_request_parser_execute ( &connection->parser - , static_cast (buf) // FIXME change ebb to use void* + // FIXME change ebb to use void* + , static_cast (buf) , count ); - /* TODO check for errors */ + if(ebb_request_parser_has_error(&connection->parser)) { + fprintf(stderr, "parse error closing connection\n"); + oi_socket_close(&connection->socket); + } } static void on_close @@ -247,8 +297,8 @@ static void on_close ) { Connection *connection = static_cast (socket->data); - /* TODO free requests */ - free(connection); + // TODO free requests + delete connection; } static void on_drain @@ -282,7 +332,7 @@ static oi_socket* new_connection // Reads a file into a v8 string. -Handle ReadFile +static Handle ReadFile ( const string& name ) { @@ -305,7 +355,7 @@ Handle ReadFile return result; } -void ParseOptions +static void ParseOptions ( int argc , char* argv[] , map& options @@ -325,7 +375,7 @@ void ParseOptions } } -bool ExecuteScript +static bool compile ( Handle script ) { @@ -399,7 +449,7 @@ int main Context::Scope context_scope(context); // Compile and run the script - if (!ExecuteScript(source)) + if (!compile(source)) return false; // The script compiled and ran correctly. Now we fetch out the