diff --git a/buildconf/jwsgi.ini b/buildconf/jwsgi.ini new file mode 100644 index 00000000..c6b4c848 --- /dev/null +++ b/buildconf/jwsgi.ini @@ -0,0 +1,3 @@ +[uwsgi] +main_plugin = jvm,jwsgi +inherit = base diff --git a/plugins/jvm/jvm.h b/plugins/jvm/jvm.h index cfbde598..6f44409b 100644 --- a/plugins/jvm/jvm.h +++ b/plugins/jvm/jvm.h @@ -17,6 +17,7 @@ struct uwsgi_jvm { jclass request_body_class; jclass str_class; + jclass str_array_class; jclass long_class; jclass int_class; jclass byte_class; @@ -96,3 +97,9 @@ jobject uwsgi_jvm_num(long); jobject uwsgi_jvm_request_body_input_stream(void); size_t uwsgi_jvm_array_len(jobject); +jobject uwsgi_jvm_array_get(jobject, long); + +int uwsgi_jvm_iterator_to_response_headers(struct wsgi_request *, jobject); +jobject uwsgi_jvm_entryset(jobject); + +int uwsgi_jvm_object_to_response_body(struct wsgi_request *, jobject); diff --git a/plugins/jvm/jvm_plugin.c b/plugins/jvm/jvm_plugin.c index 3fd4fbe2..a120d57c 100644 --- a/plugins/jvm/jvm_plugin.c +++ b/plugins/jvm/jvm_plugin.c @@ -105,6 +105,189 @@ static struct uwsgi_option uwsgi_jvm_options[] = { {0, 0, 0, 0}, }; +jobject uwsgi_jvm_entryset(jobject o) { + jclass c = uwsgi_jvm_class_from_object(o); + if (!c) return NULL; + jmethodID mid = uwsgi_jvm_get_method_id(c, "entrySet", "()Ljava/util/Set;"); + uwsgi_jvm_local_unref(c); + if (!mid) return NULL; + return uwsgi_jvm_call_object(o, mid); +} + +int uwsgi_jvm_object_to_response_body(struct wsgi_request *wsgi_req, jobject body) { + + // check for string + if (uwsgi_jvm_object_is_instance(body, ujvm.str_class)) { + char *c_body = uwsgi_jvm_str2c(body); + size_t c_body_len = uwsgi_jvm_strlen(body); + uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len); + uwsgi_jvm_release_chars(body, c_body); + return 0; + } + + // check for string array + if (uwsgi_jvm_object_is_instance(body, ujvm.str_array_class)) { + size_t items = uwsgi_jvm_array_len(body); + size_t i; + for(i=0;iExceptionCheck(ujvm_env)) { @@ -213,6 +396,14 @@ size_t uwsgi_jvm_array_len(jobject o) { return len; } +jobject uwsgi_jvm_array_get(jobject o, long index) { + jobject ret = (*ujvm_env)->GetObjectArrayElement(ujvm_env, o, index); + if (uwsgi_jvm_exception()) { + return NULL; + } + return ret; +} + int uwsgi_jvm_consume_input_stream(struct wsgi_request *wsgi_req, size_t chunk, jobject o) { int ret = 0; jclass c = uwsgi_jvm_class_from_object(o); @@ -614,6 +805,9 @@ static void uwsgi_jvm_create(void) { ujvm.str_class = uwsgi_jvm_class("java/lang/String"); if (!ujvm.str_class) exit(1); + ujvm.str_array_class = uwsgi_jvm_class("[Ljava/lang/String;"); + if (!ujvm.str_array_class) exit(1); + ujvm.int_class = uwsgi_jvm_class("java/lang/Integer"); if (!ujvm.int_class) exit(1); diff --git a/plugins/jwsgi/jwsgi_plugin.c b/plugins/jwsgi/jwsgi_plugin.c index ab530659..9a6baa33 100644 --- a/plugins/jwsgi/jwsgi_plugin.c +++ b/plugins/jwsgi/jwsgi_plugin.c @@ -1,158 +1,177 @@ -#include "../jvm/jvm.h" +#include extern struct uwsgi_server uwsgi; extern struct uwsgi_jvm ujvm; -static int MAX_LREFS = 16; +#define UWSGI_JVM_REQUEST_HANDLER_JWSGI 0 -void uwsgi_jwsgi_init(void) { +struct uwsgi_jwsgi { + char *app; + jmethodID app_mid; + jclass app_class; +} ujwsgi; +static struct uwsgi_option uwsgi_jwsgi_options[] = { + {"jwsgi", required_argument, 0, "load the specified JWSGI application (syntax class:method)", uwsgi_opt_set_str, &ujwsgi.app, 0}, + {0, 0, 0, 0}, +}; +static int uwsgi_jwsgi_add_request_item(jobject hm, char *key, uint16_t key_len, char *value, uint16_t value_len) { + jobject j_key = uwsgi_jvm_str(key, key_len); + if (!j_key) return -1; + + jobject j_value = uwsgi_jvm_str(value, value_len); + if (!j_value) { + uwsgi_jvm_local_unref(j_value); + return -1; + } + + int ret = uwsgi_jvm_hashmap_put(hm, j_key, j_value); + uwsgi_jvm_local_unref(j_key); + uwsgi_jvm_local_unref(j_value); + return ret; } -int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) { +static int uwsgi_jwsgi_add_request_input(jobject hm, char *key, uint16_t key_len) { + jobject j_key = uwsgi_jvm_str(key, key_len); + if (!j_key) return -1; - jmethodID jmid; - int i; - jobject env; - jobject hkey, hval; - jobject response; - - jobject status; - jobject headers, header; - jobject body; - - const char* body_str; - const char* status_str; - const char* hkey_str; - const char* hval_str; - - jclass hc; - - jmethodID hh_size, hh_get; - int hlen; - - if (!wsgi_req->uh.pktsize) { - uwsgi_log("Invalid JWSGI request. skip.\n"); - return -1; - } - - if (uwsgi_parse_vars(wsgi_req)) { - uwsgi_log("Invalid JWSGI request. skip.\n"); - return -1; - } - - if ((*ujvm.env)->PushLocalFrame(ujvm.env, MAX_LREFS) < 0) { - uwsgi_log("jwsgi can not allocate frame!"); - return -1; - } - - jmid = uwsgi_jvm_get_static_method_id(ujvm.main_class, "jwsgi", "(Ljava/util/Hashtable;)[Ljava/lang/Object;"); - - uwsgi_log("jwsgi method id = %d\n", jmid); - - env = uwsgi_jvm_ht_new(); - uwsgi_jvm_exception(); - - int cnt = wsgi_req->var_cnt; - for(i=0;iPushLocalFrame(ujvm.env, MAX_LREFS) < 0) { - uwsgi_log("jwsgi can not allocate frame!"); - return -1; + jobject j_value = uwsgi_jvm_request_body_input_stream(); + if (!j_value) { + uwsgi_jvm_local_unref(j_value); + return -1; } - hkey = uwsgi_jvm_str_new(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len); - hval = uwsgi_jvm_str_new(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len); - uwsgi_jvm_ht_put(env, hkey, hval); - uwsgi_jvm_exception(); + int ret = uwsgi_jvm_hashmap_put(hm, j_key, j_value); + uwsgi_jvm_local_unref(j_key); + uwsgi_jvm_local_unref(j_value); + return ret; +} - (*ujvm.env)->PopLocalFrame(ujvm.env, NULL); +static int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) { + char status_str[11]; + jobject hm = NULL; + jobject response = NULL; + jobject r_status = NULL; + jobject r_headers = NULL; + jobject r_headers_entries = NULL; + jobject r_body = NULL; - i++; - } + hm = uwsgi_jvm_hashmap(); + if (!hm) return -1; - uwsgi_log("env created\n"); + int i; + for(i=0;ivar_cnt;i++) { + char *hk = wsgi_req->hvec[i].iov_base; + uint16_t hk_l = wsgi_req->hvec[i].iov_len; + char *hv = wsgi_req->hvec[i+1].iov_base; + uint16_t hv_l = wsgi_req->hvec[i+1].iov_len; + if (uwsgi_jwsgi_add_request_item(hm, hk, hk_l, hv, hv_l)) goto end; + i++; + } - uwsgi_jvm_ht_put(env, uwsgi_jvm_str("jwsgi.input"), uwsgi_jvm_fd(wsgi_req->poll.fd)); + if (uwsgi_jwsgi_add_request_input(hm, "jwsgi.input", 11)) goto end; - uwsgi_log("jwsgi.input created\n"); + response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm); + if (!response) goto end; - response = (*ujvm.env)->CallObjectMethod(ujvm.env, ujvm.main_class, jmid, env); - uwsgi_jvm_exception(); + if (uwsgi_jvm_array_len(response) != 3) { + uwsgi_log("invalid JWSGI response object\n"); + goto end; + } - uwsgi_log("RESPONSE SIZE %d\n", (*ujvm.env)->GetArrayLength(ujvm.env, response)); + r_status = uwsgi_jvm_array_get(response, 0); + if (!r_status) goto end; + long n_status = uwsgi_jvm_number2c(r_status); + if (n_status == -1) goto end; - if ((*ujvm.env)->PushLocalFrame(ujvm.env, MAX_LREFS) < 0) { - uwsgi_log("jwsgi can not allocate frame!"); - return -1; - } - - status = uwsgi_jvm_array_get(response, 0); - uwsgi_jvm_exception(); - - status_str = uwsgi_jvm_str2c(status); - wsgi_req->headers_size += write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len); - wsgi_req->headers_size += write(wsgi_req->poll.fd, " ", 1); - wsgi_req->headers_size += write(wsgi_req->poll.fd, status_str, uwsgi_jvm_strlen2c(status)); - wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2); - (*ujvm.env)->ReleaseStringUTFChars(ujvm.env, status, status_str); - - headers = uwsgi_jvm_array_get(response, 1); - - hc = uwsgi_jvm_get_object_class(headers); - hh_size = uwsgi_jvm_get_method_id(hc, "size","()I"); - hh_get = uwsgi_jvm_get_method_id(hc, "get","(I)Ljava/lang/Object;"); - - hlen = (*ujvm.env)->CallIntMethod(ujvm.env, headers, hh_size); - - for(i=0;iPushLocalFrame(ujvm.env, MAX_LREFS) < 0) { - uwsgi_log("jwsgi can not allocate frame!"); - return -1; + if (uwsgi_num2str2(n_status, status_str) != 3) { + goto end; } - header = (*ujvm.env)->CallObjectMethod(ujvm.env, headers, hh_get, i); - hkey = uwsgi_jvm_array_get(header, 0); - hval = uwsgi_jvm_array_get(header, 1); - hkey_str = uwsgi_jvm_str2c(hkey); - hval_str = uwsgi_jvm_str2c(hval); + if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end; - wsgi_req->headers_size += write(wsgi_req->poll.fd, hkey_str, uwsgi_jvm_strlen2c(hkey)); - wsgi_req->headers_size += write(wsgi_req->poll.fd, ": ", 2); - wsgi_req->headers_size += write(wsgi_req->poll.fd, hval_str, uwsgi_jvm_strlen2c(hval)); - wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2); + r_headers = uwsgi_jvm_array_get(response, 1); + if (!r_headers) goto end; - (*ujvm.env)->ReleaseStringUTFChars(ujvm.env, hkey, hkey_str); - (*ujvm.env)->ReleaseStringUTFChars(ujvm.env, hval, hval_str); + // get entrySet + r_headers_entries = uwsgi_jvm_entryset(r_headers); + if (!r_headers_entries) goto end; - (*ujvm.env)->PopLocalFrame(ujvm.env, NULL); - } + // get iterator + jobject values = uwsgi_jvm_auto_iterator(r_headers_entries); + if (values) { + int ret = uwsgi_jvm_iterator_to_response_headers(wsgi_req, values); + uwsgi_jvm_local_unref(values); + if (ret) goto end; + } + else { + uwsgi_log("unsupported response headers type !!! (must be java/util/HashMap)\n"); + goto end; + } - wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2); + r_body = uwsgi_jvm_array_get(response, 2); + if (!r_body) goto end; - body = uwsgi_jvm_array_get(response, 2); - body_str = (*ujvm.env)->GetStringUTFChars(ujvm.env, body, NULL); - wsgi_req->response_size = write(wsgi_req->poll.fd, body_str, (*ujvm.env)->GetStringUTFLength(ujvm.env, body)); - (*ujvm.env)->ReleaseStringUTFChars(ujvm.env, body, status_str); + if (uwsgi_jvm_object_to_response_body(wsgi_req, r_body)) { + uwsgi_log("unsupported JWSGI response body type\n"); + } - (*ujvm.env)->PopLocalFrame(ujvm.env, NULL); +end: + if (r_status) uwsgi_jvm_local_unref(r_status); + if (r_headers_entries) uwsgi_jvm_local_unref(r_headers_entries); + if (r_headers) uwsgi_jvm_local_unref(r_headers); + if (r_body) uwsgi_jvm_local_unref(r_body); - (*ujvm.env)->PopLocalFrame(ujvm.env, NULL); - - return 1; + if (response) { + uwsgi_jvm_local_unref(response); + } + uwsgi_jvm_local_unref(hm); + return UWSGI_OK; } -void uwsgi_jwsgi_after_request(struct wsgi_request *wsgi_req) { - log_request(wsgi_req); +static int uwsgi_jwsgi_setup() { + + char *app = uwsgi_str(ujwsgi.app); + + char *colon = strchr(app, ':'); + + if (!colon) { + uwsgi_log("invalid JWSGI app definition, must be class:method\n"); + exit(1); + } + + *colon = 0; + + ujwsgi.app_class = uwsgi_jvm_class(app); + if (!ujwsgi.app_class) { + exit(1); + } + + ujwsgi.app_mid = uwsgi_jvm_get_static_method_id(ujwsgi.app_class, colon+1, "(Ljava/util/HashMap;)[Ljava/lang/Object;"); + if (!ujwsgi.app_mid) { + exit(1); + } + + uwsgi_log("JWSGI app \"%s\" loaded\n", ujwsgi.app); + return 0; } +static int uwsgi_jwsgi_init() { + + if (!ujwsgi.app) return 0; + + if (uwsgi_jvm_register_request_handler(UWSGI_JVM_REQUEST_HANDLER_JWSGI, uwsgi_jwsgi_setup, uwsgi_jwsgi_request)) { + exit(1); + } + + return 0; +} + + struct uwsgi_plugin jwsgi_plugin = { - - .name = "jwsgi", - .modifier1 = 8, - .request = uwsgi_jwsgi_request, - .after_request = uwsgi_jwsgi_after_request, + .name = "jwsgi", + .options = uwsgi_jwsgi_options, + .init = uwsgi_jwsgi_init, }; diff --git a/plugins/jwsgi/uwsgiplugin.py b/plugins/jwsgi/uwsgiplugin.py index 0ca9b080..62d333e7 100644 --- a/plugins/jwsgi/uwsgiplugin.py +++ b/plugins/jwsgi/uwsgiplugin.py @@ -1,22 +1,16 @@ -import os,sys +jvm_path = 'plugins/jvm' -NAME='jwsgi' +up = {} +try: + execfile('%s/uwsgiplugin.py' % jvm_path, up) +except: + f = open('%s/uwsgiplugin.py' % jvm_path) + exec(f.read(), up) + f.close() -# Snow Leopard -#JVM_INCPATH = "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Headers/" -#JVM_LIBPATH = "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Libraries/ -framework JavaVM" - -# Ubuntu -JVM_INCPATH = "/usr/lib/jvm/java-6-sun-1.6.0.15/include/ -I/usr/lib/jvm/java-6-sun-1.6.0.15/include/linux" -JVM_LIBPATH = "/usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/i386/server/" - - -CFLAGS = ['-I' + JVM_INCPATH] -LDFLAGS = ['-L' + JVM_LIBPATH] -LIBS = ['-ljvm'] +NAME='ring' +CFLAGS = up['CFLAGS'] +CFLAGS.append('-I%s' % jvm_path) +LDFLAGS = [] +LIBS = [] GCC_LIST = ['jwsgi_plugin'] - -if os.environ.has_key('LD_RUN_PATH'): - os.environ['LD_RUN_PATH'] += ':' + JVM_LIBPATH -else: - os.environ['LD_RUN_PATH'] = JVM_LIBPATH diff --git a/plugins/ring/ring_plugin.c b/plugins/ring/ring_plugin.c index c4d85304..1197886f 100644 --- a/plugins/ring/ring_plugin.c +++ b/plugins/ring/ring_plugin.c @@ -224,7 +224,7 @@ static jobject uwsgi_ring_response_get(jobject r, char *name, size_t len) { // the request handler static int uwsgi_ring_request(struct wsgi_request *wsgi_req) { - char status_str[1]; + char status_str[11]; jobject request = NULL; jobject response = NULL; jobject entries = NULL; @@ -362,127 +362,16 @@ hend: entries = uwsgi_ring_Associative_iterator(r_headers); if (!entries) goto end; - int error = 0; - while(uwsgi_jvm_iterator_hasNext(entries)) { - jobject hh = NULL, h_key = NULL, h_value = NULL; - - hh = uwsgi_jvm_iterator_next(entries); - if (!hh) { error = 1 ; goto clear;} - h_key = uwsgi_jvm_getKey(hh); - if (!h_key) { error = 1 ; goto clear;} - h_value = uwsgi_jvm_getValue(hh); - if (!h_value) { error = 1 ; goto clear;} - - if (!uwsgi_jvm_object_is_instance(h_key, ujvm.str_class)) { - uwsgi_log("headers key must be java/lang/String !!!\n"); - error = 1 ; goto clear; - } - - // check for string - if (uwsgi_jvm_object_is_instance(h_value, ujvm.str_class)) { - char *c_h_key = uwsgi_jvm_str2c(h_key); - uint16_t c_h_keylen = uwsgi_jvm_strlen(h_key); - char *c_h_value = uwsgi_jvm_str2c(h_value); - uint16_t c_h_vallen = uwsgi_jvm_strlen(h_value); - int ret = uwsgi_response_add_header(wsgi_req, c_h_key, c_h_keylen, c_h_value, c_h_vallen); - uwsgi_jvm_release_chars(h_key, c_h_key); - uwsgi_jvm_release_chars(h_value, c_h_value); - if (ret) error = 1; - goto clear; - } - - // check for collection - jobject values = uwsgi_jvm_auto_iterator(h_value); - if (values) { - while(uwsgi_jvm_iterator_hasNext(values)) { - jobject hh_value = uwsgi_jvm_iterator_next(values); - if (!uwsgi_jvm_object_is_instance(hh_value, ujvm.str_class)) { - uwsgi_log("headers value must be java/lang/String !!!\n"); - uwsgi_jvm_local_unref(hh_value); - uwsgi_jvm_local_unref(values); - error = 1 ; goto clear; - } - char *c_h_key = uwsgi_jvm_str2c(h_key); - uint16_t c_h_keylen = uwsgi_jvm_strlen(h_key); - char *c_h_value = uwsgi_jvm_str2c(hh_value); - uint16_t c_h_vallen = uwsgi_jvm_strlen(hh_value); - int ret = uwsgi_response_add_header(wsgi_req, c_h_key, c_h_keylen, c_h_value, c_h_vallen); - uwsgi_jvm_release_chars(h_key, c_h_key); - uwsgi_jvm_release_chars(hh_value, c_h_value); - uwsgi_jvm_local_unref(hh_value); - if (ret) { uwsgi_jvm_local_unref(values); error = 1 ; goto clear;} - } - uwsgi_jvm_local_unref(values); - goto clear; - } - uwsgi_log("unsupported header value !!! (must be java/lang/String or collection/seq)\n"); - error = 1; -clear: - if (h_value) - uwsgi_jvm_local_unref(h_value); - if (h_key) - uwsgi_jvm_local_unref(h_key); - if (hh) - uwsgi_jvm_local_unref(hh); - if (error) goto end; + if (uwsgi_jvm_iterator_to_response_headers(wsgi_req, entries)) { + goto end; } r_body = uwsgi_ring_response_get(response, "body", 4); if (!r_body) goto end; - - if (uwsgi_jvm_object_is_instance(r_body, ujvm.str_class)) { - char *c_body = uwsgi_jvm_str2c(r_body); - size_t c_body_len = uwsgi_jvm_strlen(r_body); - uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len); - uwsgi_jvm_release_chars(r_body, c_body); - goto end; - } - - jobject chunks = uwsgi_jvm_auto_iterator(r_body); - if (chunks) { - while(uwsgi_jvm_iterator_hasNext(chunks)) { - jobject chunk = uwsgi_jvm_iterator_next(chunks); - if (!chunk) goto done; - if (!uwsgi_jvm_object_is_instance(chunk, ujvm.str_class)) { - uwsgi_log("body iSeq item must be java/lang/String !!!\n"); - uwsgi_jvm_local_unref(chunk); - goto done; - } - char *c_body = uwsgi_jvm_str2c(chunk); - size_t c_body_len = uwsgi_jvm_strlen(chunk); - int ret = uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len); - uwsgi_jvm_release_chars(chunk, c_body); - uwsgi_jvm_local_unref(chunk); - if (ret) goto done; - } -done: - uwsgi_jvm_local_unref(chunks); - goto end; + if (uwsgi_jvm_object_to_response_body(wsgi_req, r_body)) { + uwsgi_log("unsupported clojure/ring body type\n"); } - - if (uwsgi_jvm_object_is_instance(r_body, ujvm.file_class)) { - jobject j_filename = uwsgi_jvm_filename(r_body); - if (!j_filename) goto end; - char *c_filename = uwsgi_jvm_str2c(j_filename); - int fd = open(c_filename, O_RDONLY); - if (fd < 0) { - uwsgi_error("clojure/ring->open()"); - goto done2; - } - uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0); -done2: - uwsgi_jvm_release_chars(j_filename, c_filename); - uwsgi_jvm_local_unref(j_filename); - goto end; - } - - if (uwsgi_jvm_object_is_instance(r_body, ujvm.input_stream_class)) { - uwsgi_jvm_consume_input_stream(wsgi_req, 8192, r_body); - goto end; - } - - uwsgi_log("unsupported clojure/ring body type\n"); end: // destroy the request map and the response uwsgi_jvm_local_unref(hm);