From af3860dbd7d4feed03ac0d223bb3b5cd9e67f8a3 Mon Sep 17 00:00:00 2001 From: Unbit Date: Mon, 4 Mar 2013 15:43:52 +0100 Subject: [PATCH] completed status and headers management for the ring plugin --- plugins/jvm/jvm.h | 12 ++++++ plugins/jvm/jvm_plugin.c | 69 +++++++++++++++++++++++++++++++ plugins/ring/ring_plugin.c | 84 +++++++++++++++++++++++++++++++++++--- 3 files changed, 159 insertions(+), 6 deletions(-) diff --git a/plugins/jvm/jvm.h b/plugins/jvm/jvm.h index 076ffa49..e1f50dfe 100644 --- a/plugins/jvm/jvm.h +++ b/plugins/jvm/jvm.h @@ -14,6 +14,8 @@ struct uwsgi_jvm { struct uwsgi_string_list *main_classes; jclass str_class; + jclass long_class; + jclass int_class; jclass hashmap_class; jclass set_class; jclass iterator_class; @@ -62,3 +64,13 @@ int uwsgi_jvm_iterator_hasNext(jobject); jobject uwsgi_jvm_iterator_next(jobject); jobject uwsgi_jvm_iterator(jobject); +jobject uwsgi_jvm_auto_iterator(jobject); + +jobject uwsgi_jvm_getKey(jobject); +jobject uwsgi_jvm_getValue(jobject); + +size_t uwsgi_jvm_strlen(jobject); +long uwsgi_jvm_number2c(jobject); + +long uwsgi_jvm_int2c(jobject); +long uwsgi_jvm_long2c(jobject); diff --git a/plugins/jvm/jvm_plugin.c b/plugins/jvm/jvm_plugin.c index bc632d78..7fb774ac 100644 --- a/plugins/jvm/jvm_plugin.c +++ b/plugins/jvm/jvm_plugin.c @@ -117,6 +117,45 @@ jobject uwsgi_jvm_object_class_name(jobject o) { return uwsgi_jvm_call_object(oc, mid); } +long uwsgi_jvm_int2c(jobject o) { + static jmethodID mid = 0; + if (!mid) { + mid = uwsgi_jvm_get_method_id(ujvm.int_class, "intValue", "()I"); + if (!mid) return -1 ; + } + long value = (*ujvm_env)->CallIntMethod(ujvm_env, o, mid); + if (uwsgi_jvm_exception()) { + return -1; + } + return value; +} + +long uwsgi_jvm_long2c(jobject o) { + static jmethodID mid = 0; + if (!mid) { + mid = uwsgi_jvm_get_method_id(ujvm.long_class, "longValue", "()J"); + if (!mid) return -1; + } + long value = (*ujvm_env)->CallLongMethod(ujvm_env, o, mid); + if (uwsgi_jvm_exception()) { + return -1; + } + return value; +} + + +long uwsgi_jvm_number2c(jobject o) { + if (uwsgi_jvm_object_is_instance(o, ujvm.int_class)) { + return uwsgi_jvm_int2c(o); + } + + if (uwsgi_jvm_object_is_instance(o, ujvm.long_class)) { + return uwsgi_jvm_long2c(o); + } + + return -1; +} + // returns the method id, given the method name and its signature jmethodID uwsgi_jvm_get_method_id(jclass cls, char *name, char *signature) { jmethodID mid = (*ujvm_env)->GetMethodID(ujvm_env, cls, name, signature); @@ -193,6 +232,30 @@ jobject uwsgi_jvm_iterator(jobject set) { return uwsgi_jvm_call_object(set, mid); } +jobject uwsgi_jvm_auto_iterator(jobject o) { + jclass c = uwsgi_jvm_class_from_object(o); + if (!c) return NULL; + jmethodID mid = uwsgi_jvm_get_method_id(c, "iterator", "()Ljava/util/Iterator;"); + if (!mid) return NULL; + return uwsgi_jvm_call_object(o, mid); +} + +jobject uwsgi_jvm_getKey(jobject item) { + jclass c = uwsgi_jvm_class_from_object(item); + if (!c) return NULL; + jmethodID mid = uwsgi_jvm_get_method_id(c, "getKey", "()Ljava/lang/Object;"); + if (!mid) return NULL; + return uwsgi_jvm_call_object(item, mid); +} + +jobject uwsgi_jvm_getValue(jobject item) { + jclass c = uwsgi_jvm_class_from_object(item); + if (!c) return NULL; + jmethodID mid = uwsgi_jvm_get_method_id(c, "getValue", "()Ljava/lang/Object;"); + if (!mid) return NULL; + return uwsgi_jvm_call_object(item, mid); +} + int uwsgi_jvm_iterator_hasNext(jobject iterator) { // optimization static jmethodID mid = 0; @@ -350,6 +413,12 @@ static void uwsgi_jvm_create(void) { ujvm.str_class = uwsgi_jvm_class("java/lang/String"); if (!ujvm.str_class) exit(1); + ujvm.int_class = uwsgi_jvm_class("java/lang/Integer"); + if (!ujvm.int_class) exit(1); + + ujvm.long_class = uwsgi_jvm_class("java/lang/Long"); + if (!ujvm.long_class) exit(1); + ujvm.hashmap_class = uwsgi_jvm_class("java/util/HashMap"); if (!ujvm.hashmap_class) exit(1); diff --git a/plugins/ring/ring_plugin.c b/plugins/ring/ring_plugin.c index 986584ea..a176df54 100644 --- a/plugins/ring/ring_plugin.c +++ b/plugins/ring/ring_plugin.c @@ -2,6 +2,8 @@ #define UWSGI_JVM_REQUEST_HANDLER_RING 1 +extern struct uwsgi_jvm ujvm; + struct uwsgi_ring { char *app; jobject handler; @@ -14,6 +16,9 @@ struct uwsgi_ring { jclass PersistentArrayMap; jmethodID PersistentArrayMap_get; jmethodID PersistentArrayMap_entrySet; + + jclass PersistentVector; + jclass PersistentList; } uring; static struct uwsgi_option uwsgi_ring_options[] = { @@ -65,6 +70,7 @@ static jobject uwsgi_ring_header_get(jobject headers, jobject key) { } static int uwsgi_ring_request(struct wsgi_request *wsgi_req) { + char status_str[1]; uwsgi_log("managing ring request\n"); jobject hm = uwsgi_jvm_hashmap(); if (!hm) return -1; @@ -83,21 +89,77 @@ static int uwsgi_ring_request(struct wsgi_request *wsgi_req) { jobject r_status = uwsgi_ring_response_get(response, "status", 6); if (!r_status) goto error; + if (!uwsgi_jvm_object_is_instance(r_status, ujvm.long_class) && !uwsgi_jvm_object_is_instance(r_status, ujvm.int_class)) { + uwsgi_log("invalid ring response status type, must be: java.lang.Long\n"); + goto error; + } + + long n_status = uwsgi_jvm_number2c(r_status); + if (n_status == -1) goto error; + + if (uwsgi_num2str2(n_status, status_str) != 3) { + goto error; + } + + if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto error; + jobject r_headers = uwsgi_ring_response_get(response, "headers", 7); if (!r_headers) goto error; - char *cn = uwsgi_jvm_str2c( uwsgi_jvm_object_class_name(r_headers) ); - uwsgi_log("headers type = %s\n", cn); - - cn = uwsgi_jvm_str2c( uwsgi_jvm_object_class_name(r_status) ); - uwsgi_log("status type = %s\n", cn); + if (!uwsgi_jvm_object_is_instance(r_headers, uring.PersistentArrayMap)) { + uwsgi_log("invalid ring response headers type, must be: clojure.lang.PersistentArrayMap\n"); + goto error; + } jobject entries = uwsgi_ring_PersistentArrayMap_iterator(r_headers); if (!entries) goto error; while(uwsgi_jvm_iterator_hasNext(entries)) { jobject hh = uwsgi_jvm_iterator_next(entries); - uwsgi_log("hh = %p\n", hh); + if (!hh) goto error; + jobject h_key = uwsgi_jvm_getKey(hh); + if (!h_key) goto error; + jobject h_value = uwsgi_jvm_getValue(hh); + if (!h_value) goto error; + + if (!uwsgi_jvm_object_is_instance(h_key, ujvm.str_class)) { + uwsgi_log("headers key must be java/lang/String !!!\n"); + goto error; + } + + 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) goto error; + } + else if (uwsgi_jvm_object_is_instance(h_value, uring.PersistentVector) || uwsgi_jvm_object_is_instance(h_value, uring.PersistentList)) { + jobject values = uwsgi_jvm_auto_iterator(h_value); + if (!values) goto error; + 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"); + goto error; + } + 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); + if (ret) goto error; + } + } + else { + uwsgi_log("unsupported header value !!! (must be java/lang/String, clojure/lang/PersistentVector or clojure/lang/PersistentList)\n"); + goto error; + } } jobject ct = uwsgi_ring_header_get(r_headers, uwsgi_jvm_str("Content-Type", 0)); if (!ct) { @@ -132,6 +194,16 @@ static int uwsgi_ring_setup() { exit(1); } + uring.PersistentVector = uwsgi_jvm_class("clojure/lang/PersistentVector"); + if (!uring.PersistentVector) { + exit(1); + } + + uring.PersistentList = uwsgi_jvm_class("clojure/lang/PersistentList"); + if (!uring.PersistentList) { + exit(1); + } + jmethodID clojure_loadresourcescript = uwsgi_jvm_get_static_method_id(clojure, "loadResourceScript", "(Ljava/lang/String;)V"); if (!clojure_loadresourcescript) { exit(1);