diff --git a/plugins/v8/plugin.c b/plugins/v8/plugin.c index 35e4d69127..d629011ca2 100644 --- a/plugins/v8/plugin.c +++ b/plugins/v8/plugin.c @@ -15,9 +15,7 @@ static void uwsgi_v8_register(void) { extern struct uwsgi_option uwsgi_v8_options[]; -static int uwsgi_v8_request(struct wsgi_request *wsgi_req) { - return UWSGI_OK; -} +int uwsgi_v8_request(struct wsgi_request *); struct uwsgi_plugin v8_plugin = { .name = "v8", diff --git a/plugins/v8/uwsgiplugin.py b/plugins/v8/uwsgiplugin.py index 40534eecfa..e49fc83cd8 100644 --- a/plugins/v8/uwsgiplugin.py +++ b/plugins/v8/uwsgiplugin.py @@ -3,4 +3,4 @@ CFLAGS = ['-Wno-deprecated-declarations'] LDFLAGS = [] LIBS = ['-lv8'] -GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc'] +GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc', 'v8_jsgi.cc'] diff --git a/plugins/v8/v8_jsgi.cc b/plugins/v8/v8_jsgi.cc new file mode 100644 index 0000000000..4b15e36a5d --- /dev/null +++ b/plugins/v8/v8_jsgi.cc @@ -0,0 +1,126 @@ +#include "v8_uwsgi.h" + +extern struct uwsgi_v8 uv8; + +extern "C" int uwsgi_v8_request(struct wsgi_request *wsgi_req) { + char status_str[11]; + uint32_t i,l; + v8::Handle status, headers, body; + v8::Local props; + v8::Local key, value; + + /* Standard JSGI 3.0 request */ + if (!wsgi_req->uh->pktsize) { + uwsgi_log( "Empty JSGI request. skip.\n"); + return -1; + } + + if (uwsgi_parse_vars(wsgi_req)) { + return -1; + } + + int core_id = wsgi_req->async_id; + + uv8.isolates[core_id]->Enter(); + uv8.contexts[core_id]->Enter(); + v8::HandleScope handle_scope; + v8::Handle argj[1]; + argj[0] = v8::Object::New(); + v8::Handle result = uv8.jsgi_func[core_id]->Call(uv8.contexts[core_id]->Global(), 1, argj); + if (result.IsEmpty()) goto end; + if (!result->IsObject()) goto end; + + status = result->ToObject()->Get(v8::String::New("status")); + if (status.IsEmpty() || !status->IsNumber()) { + uwsgi_log("invalid JSGI response status\n"); + exit(1); + } + headers = result->ToObject()->Get(v8::String::New("headers")); + if (headers.IsEmpty() || !headers->IsObject()) { + uwsgi_log("invalid JSGI response headers\n"); + exit(1); + } + body = result->ToObject()->Get(v8::String::New("body")); + if (body.IsEmpty() || !body->IsObject()) { + uwsgi_log("invalid JSGI response body\n"); + exit(1); + } + + if (uwsgi_num2str2(status->Uint32Value(), status_str) != 3) { + goto end; + } + + if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end; + + props = headers->ToObject()->GetPropertyNames(); + l = props->Length(); + + for(i=0;iGet(i); + value = headers->ToObject()->Get(key); + v8::String::Utf8Value c_key(key->ToString()); + if (value->IsArray()) { + uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value(); + uint32_t j; + for(j=0;jToObject()->Get(j)->ToString()); + if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end; + } + } + else { + v8::String::Utf8Value c_value(value->ToString()); + if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end; + } + } + +end: + while(!v8::V8::IdleNotification()) {}; + return UWSGI_OK; +} + +v8::Persistent uwsgi_v8_load_jsgi(int core_id, char *filename) { + + uv8.isolates[core_id]->Enter(); + uv8.contexts[core_id]->Enter(); + v8::HandleScope handle_scope; + + size_t len = 0; + char *code = uwsgi_open_and_read(filename, &len, 1, NULL); + // we re-create every time an "exports" object to emulate a local object + v8::Local exports = v8::Object::New(); + v8::Context::GetCurrent()->Global()->Set(v8::String::New("exports"), exports); + + // we do not use TryCatch as we directly use stderr and simply exit with error code 1 + v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); + free(code); + if (script.IsEmpty()) { + exit(1); + } + + v8::Handle result = script->Run(); + if (result.IsEmpty()) { + exit(1); + } + + v8::Handle app = exports->Get(v8::String::New("app")); + if (!app.IsEmpty() && !app->IsNull() && !app->IsUndefined()) { + if (app->ToObject()->IsFunction()) { + if (!uv8.jsgi_announced) { + uwsgi_log("JSGI 3.0 application loaded from \"exports.app\" in %s\n", filename); + uv8.jsgi_announced = -1; + } + return v8::Persistent::New(v8::Handle::Cast(app)); + } + } + + if (!result->IsNull() && !result->IsUndefined() && result->ToObject()->IsFunction()) { + if (!uv8.jsgi_announced) { + uwsgi_log("JSGI 3.0 application loaded from return value of %s\n", filename); + uv8.jsgi_announced = -1; + } + return v8::Persistent::New(v8::Handle::Cast(result)); + } + + uwsgi_log("unable to find JSGI 3.0 entry point function\n"); + exit(1); +} diff --git a/plugins/v8/v8_uwsgi.cc b/plugins/v8/v8_uwsgi.cc index e59263ca98..2845fa9329 100644 --- a/plugins/v8/v8_uwsgi.cc +++ b/plugins/v8/v8_uwsgi.cc @@ -10,6 +10,7 @@ struct uwsgi_option uwsgi_v8_options[] = { {(char *)"v8-preemptive", required_argument, 0, (char *)"put v8 in preemptive move (single isolate) with the specified frequency", uwsgi_opt_set_int, &uv8.preemptive, 0}, {(char *)"v8-gc-freq", required_argument, 0, (char *)"set the v8 garbage collection frequency", uwsgi_opt_set_64bit, &uv8.gc_freq, 0}, {(char *)"v8-module-path", required_argument, 0, (char *)"set the v8 modules search path", uwsgi_opt_add_string_list, &uv8.module_paths, 0}, + {(char *)"v8-jsgi", required_argument, 0, (char *)"load the specified JSGI 3.0 application", uwsgi_opt_set_str, &uv8.jsgi, 0}, {0, 0, 0, 0}, }; @@ -175,6 +176,7 @@ extern "C" int uwsgi_v8_init(){ for(i=0;i<256;i++) { uv8.sigtable[i].func = (v8::Persistent*) uwsgi_calloc(sizeof(v8::Persistent) * uwsgi.cores); } + uv8.jsgi_func = (v8::Persistent *) uwsgi_calloc( sizeof(v8::Persistent) * uwsgi.cores ); pthread_key_create(&uv8.current_core, NULL); pthread_setspecific(uv8.current_core, (void *) 0); @@ -184,12 +186,15 @@ extern "C" int uwsgi_v8_init(){ } static void uwsgi_v8_apps_do(int core_id) { - if (!uv8.load) return; struct uwsgi_string_list *usl = uv8.load; while(usl) { uwsgi_v8_load_file(core_id, usl->value); usl = usl->next; } + + if (uv8.jsgi) { + uv8.jsgi_func[core_id] = uwsgi_v8_load_jsgi(core_id, uv8.jsgi); + } } extern "C" void uwsgi_v8_apps() { diff --git a/plugins/v8/v8_uwsgi.h b/plugins/v8/v8_uwsgi.h index 12ac26a273..df85c9a6a9 100644 --- a/plugins/v8/v8_uwsgi.h +++ b/plugins/v8/v8_uwsgi.h @@ -16,6 +16,9 @@ struct uwsgi_v8_rpc_table { struct uwsgi_v8 { v8::Persistent *contexts; v8::Isolate **isolates; + char *jsgi; + v8::Persistent *jsgi_func; + int jsgi_announced; struct uwsgi_string_list *load; struct uwsgi_v8_signal_table *sigtable; struct uwsgi_v8_rpc_table *rpctable; @@ -24,3 +27,5 @@ struct uwsgi_v8 { uint64_t gc_freq; struct uwsgi_string_list *module_paths; }; + +v8::Persistent uwsgi_v8_load_jsgi(int, char *);