diff options
Diffstat (limited to 'src/java/nxt_jni_OutputStream.c')
-rw-r--r-- | src/java/nxt_jni_OutputStream.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/java/nxt_jni_OutputStream.c b/src/java/nxt_jni_OutputStream.c new file mode 100644 index 00000000..170b33ba --- /dev/null +++ b/src/java/nxt_jni_OutputStream.c @@ -0,0 +1,236 @@ + +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_auto_config.h> + +#include <jni.h> +#include <nxt_unit.h> + +#include "nxt_jni.h" +#include "nxt_jni_OutputStream.h" +#include "nxt_jni_URLClassLoader.h" + + +static void JNICALL nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, + jlong req_info_ptr, jint b); +static nxt_unit_buf_t *nxt_java_OutputStream_req_buf(JNIEnv *env, + nxt_unit_request_info_t *req); +static void JNICALL nxt_java_OutputStream_write(JNIEnv *env, jclass cls, + jlong req_info_ptr, jarray b, jint off, jint len); +static void JNICALL nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, + jlong req_info_ptr); +static void JNICALL nxt_java_OutputStream_close(JNIEnv *env, jclass cls, + jlong req_info_ptr); + + +static jclass nxt_java_OutputStream_class; + + +int +nxt_java_initOutputStream(JNIEnv *env, jobject cl) +{ + int res; + jclass cls; + + cls = nxt_java_loadClass(env, cl, "nginx.unit.OutputStream"); + if (cls == NULL) { + return NXT_UNIT_ERROR; + } + + nxt_java_OutputStream_class = (*env)->NewGlobalRef(env, cls); + (*env)->DeleteLocalRef(env, cls); + + cls = nxt_java_OutputStream_class; + + JNINativeMethod os_methods[] = { + { (char *) "write", + (char *) "(JI)V", + nxt_java_OutputStream_writeByte }, + + { (char *) "write", + (char *) "(J[BII)V", + nxt_java_OutputStream_write }, + + { (char *) "flush", + (char *) "(J)V", + nxt_java_OutputStream_flush }, + + { (char *) "close", + (char *) "(J)V", + nxt_java_OutputStream_close }, + }; + + res = (*env)->RegisterNatives(env, nxt_java_OutputStream_class, + os_methods, + sizeof(os_methods) / sizeof(os_methods[0])); + + nxt_unit_debug(NULL, "registered OutputStream methods: %d", res); + + if (res != 0) { + (*env)->DeleteGlobalRef(env, cls); + return NXT_UNIT_ERROR; + } + + return NXT_UNIT_OK; +} + + +static void JNICALL +nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, jlong req_info_ptr, + jint b) +{ + nxt_unit_buf_t *buf; + nxt_unit_request_info_t *req; + nxt_java_request_data_t *data; + + req = nxt_jlong2ptr(req_info_ptr); + data = req->data; + + buf = nxt_java_OutputStream_req_buf(env, req); + if (buf == NULL) { + return; + } + + *buf->free++ = b; + + if ((uint32_t) (buf->free - buf->start) >= data->buf_size) { + nxt_java_OutputStream_flush_buf(env, req); + } +} + + +int +nxt_java_OutputStream_flush_buf(JNIEnv *env, nxt_unit_request_info_t *req) +{ + int rc; + nxt_java_request_data_t *data; + + data = req->data; + + if (!nxt_unit_response_is_init(req)) { + rc = nxt_unit_response_init(req, 200, 0, 0); + if (rc != NXT_UNIT_OK) { + nxt_java_throw_IOException(env, "Failed to allocate response"); + + return rc; + } + } + + if (!nxt_unit_response_is_sent(req)) { + rc = nxt_unit_response_send(req); + if (rc != NXT_UNIT_OK) { + nxt_java_throw_IOException(env, "Failed to send response headers"); + + return rc; + } + } + + if (data->buf != NULL) { + rc = nxt_unit_buf_send(data->buf); + if (rc != NXT_UNIT_OK) { + nxt_java_throw_IOException(env, "Failed to send buffer"); + + } else { + data->buf = NULL; + } + + } else { + rc = NXT_UNIT_OK; + } + + return rc; +} + + +static nxt_unit_buf_t * +nxt_java_OutputStream_req_buf(JNIEnv *env, nxt_unit_request_info_t *req) +{ + uint32_t size; + nxt_unit_buf_t *buf; + nxt_java_request_data_t *data; + + data = req->data; + buf = data->buf; + + if (buf == NULL || buf->free >= buf->end) { + size = data->buf_size == 0 ? nxt_unit_buf_min() : data->buf_size; + + buf = nxt_unit_response_buf_alloc(req, size); + if (buf == NULL) { + nxt_java_throw_IOException(env, "Failed to allocate buffer"); + + return NULL; + } + + data->buf = buf; + } + + return buf; +} + + +static void JNICALL +nxt_java_OutputStream_write(JNIEnv *env, jclass cls, jlong req_info_ptr, + jarray b, jint off, jint len) +{ + int rc; + jint copy; + uint8_t *ptr; + nxt_unit_buf_t *buf; + nxt_unit_request_info_t *req; + nxt_java_request_data_t *data; + + req = nxt_jlong2ptr(req_info_ptr); + data = req->data; + + ptr = (*env)->GetPrimitiveArrayCritical(env, b, NULL); + + while (len > 0) { + buf = nxt_java_OutputStream_req_buf(env, req); + if (buf == NULL) { + return; + } + + copy = buf->end - buf->free; + copy = copy < len ? copy : len; + + memcpy(buf->free, ptr + off, copy); + buf->free += copy; + + len -= copy; + off += copy; + + if ((uint32_t) (buf->free - buf->start) >= data->buf_size) { + rc = nxt_java_OutputStream_flush_buf(env, req); + if (rc != NXT_UNIT_OK) { + break; + } + } + } + + (*env)->ReleasePrimitiveArrayCritical(env, b, ptr, 0); +} + + +static void JNICALL +nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, jlong req_info_ptr) +{ + nxt_unit_request_info_t *req; + nxt_java_request_data_t *data; + + req = nxt_jlong2ptr(req_info_ptr); + data = req->data; + + if (data->buf != NULL && data->buf->free > data->buf->start) { + nxt_java_OutputStream_flush_buf(env, req); + } +} + + +static void JNICALL +nxt_java_OutputStream_close(JNIEnv *env, jclass cls, jlong req_info_ptr) +{ + nxt_java_OutputStream_flush_buf(env, nxt_jlong2ptr(req_info_ptr)); +} |