1*977Smax.romanov@gmail.com 2*977Smax.romanov@gmail.com /* 3*977Smax.romanov@gmail.com * Copyright (C) NGINX, Inc. 4*977Smax.romanov@gmail.com */ 5*977Smax.romanov@gmail.com 6*977Smax.romanov@gmail.com #include <nxt_auto_config.h> 7*977Smax.romanov@gmail.com 8*977Smax.romanov@gmail.com #include <jni.h> 9*977Smax.romanov@gmail.com #include <nxt_unit.h> 10*977Smax.romanov@gmail.com 11*977Smax.romanov@gmail.com #include "nxt_jni.h" 12*977Smax.romanov@gmail.com #include "nxt_jni_OutputStream.h" 13*977Smax.romanov@gmail.com #include "nxt_jni_URLClassLoader.h" 14*977Smax.romanov@gmail.com 15*977Smax.romanov@gmail.com 16*977Smax.romanov@gmail.com static void JNICALL nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, 17*977Smax.romanov@gmail.com jlong req_info_ptr, jint b); 18*977Smax.romanov@gmail.com static nxt_unit_buf_t *nxt_java_OutputStream_req_buf(JNIEnv *env, 19*977Smax.romanov@gmail.com nxt_unit_request_info_t *req); 20*977Smax.romanov@gmail.com static void JNICALL nxt_java_OutputStream_write(JNIEnv *env, jclass cls, 21*977Smax.romanov@gmail.com jlong req_info_ptr, jarray b, jint off, jint len); 22*977Smax.romanov@gmail.com static void JNICALL nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, 23*977Smax.romanov@gmail.com jlong req_info_ptr); 24*977Smax.romanov@gmail.com static void JNICALL nxt_java_OutputStream_close(JNIEnv *env, jclass cls, 25*977Smax.romanov@gmail.com jlong req_info_ptr); 26*977Smax.romanov@gmail.com 27*977Smax.romanov@gmail.com 28*977Smax.romanov@gmail.com static jclass nxt_java_OutputStream_class; 29*977Smax.romanov@gmail.com 30*977Smax.romanov@gmail.com 31*977Smax.romanov@gmail.com int 32*977Smax.romanov@gmail.com nxt_java_initOutputStream(JNIEnv *env, jobject cl) 33*977Smax.romanov@gmail.com { 34*977Smax.romanov@gmail.com int res; 35*977Smax.romanov@gmail.com jclass cls; 36*977Smax.romanov@gmail.com 37*977Smax.romanov@gmail.com cls = nxt_java_loadClass(env, cl, "nginx.unit.OutputStream"); 38*977Smax.romanov@gmail.com if (cls == NULL) { 39*977Smax.romanov@gmail.com return NXT_UNIT_ERROR; 40*977Smax.romanov@gmail.com } 41*977Smax.romanov@gmail.com 42*977Smax.romanov@gmail.com nxt_java_OutputStream_class = (*env)->NewGlobalRef(env, cls); 43*977Smax.romanov@gmail.com (*env)->DeleteLocalRef(env, cls); 44*977Smax.romanov@gmail.com 45*977Smax.romanov@gmail.com cls = nxt_java_OutputStream_class; 46*977Smax.romanov@gmail.com 47*977Smax.romanov@gmail.com JNINativeMethod os_methods[] = { 48*977Smax.romanov@gmail.com { (char *) "write", 49*977Smax.romanov@gmail.com (char *) "(JI)V", 50*977Smax.romanov@gmail.com nxt_java_OutputStream_writeByte }, 51*977Smax.romanov@gmail.com 52*977Smax.romanov@gmail.com { (char *) "write", 53*977Smax.romanov@gmail.com (char *) "(J[BII)V", 54*977Smax.romanov@gmail.com nxt_java_OutputStream_write }, 55*977Smax.romanov@gmail.com 56*977Smax.romanov@gmail.com { (char *) "flush", 57*977Smax.romanov@gmail.com (char *) "(J)V", 58*977Smax.romanov@gmail.com nxt_java_OutputStream_flush }, 59*977Smax.romanov@gmail.com 60*977Smax.romanov@gmail.com { (char *) "close", 61*977Smax.romanov@gmail.com (char *) "(J)V", 62*977Smax.romanov@gmail.com nxt_java_OutputStream_close }, 63*977Smax.romanov@gmail.com }; 64*977Smax.romanov@gmail.com 65*977Smax.romanov@gmail.com res = (*env)->RegisterNatives(env, nxt_java_OutputStream_class, 66*977Smax.romanov@gmail.com os_methods, 67*977Smax.romanov@gmail.com sizeof(os_methods) / sizeof(os_methods[0])); 68*977Smax.romanov@gmail.com 69*977Smax.romanov@gmail.com nxt_unit_debug(NULL, "registered OutputStream methods: %d", res); 70*977Smax.romanov@gmail.com 71*977Smax.romanov@gmail.com if (res != 0) { 72*977Smax.romanov@gmail.com (*env)->DeleteGlobalRef(env, cls); 73*977Smax.romanov@gmail.com return NXT_UNIT_ERROR; 74*977Smax.romanov@gmail.com } 75*977Smax.romanov@gmail.com 76*977Smax.romanov@gmail.com return NXT_UNIT_OK; 77*977Smax.romanov@gmail.com } 78*977Smax.romanov@gmail.com 79*977Smax.romanov@gmail.com 80*977Smax.romanov@gmail.com static void JNICALL 81*977Smax.romanov@gmail.com nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, jlong req_info_ptr, 82*977Smax.romanov@gmail.com jint b) 83*977Smax.romanov@gmail.com { 84*977Smax.romanov@gmail.com nxt_unit_buf_t *buf; 85*977Smax.romanov@gmail.com nxt_unit_request_info_t *req; 86*977Smax.romanov@gmail.com nxt_java_request_data_t *data; 87*977Smax.romanov@gmail.com 88*977Smax.romanov@gmail.com req = nxt_jlong2ptr(req_info_ptr); 89*977Smax.romanov@gmail.com data = req->data; 90*977Smax.romanov@gmail.com 91*977Smax.romanov@gmail.com buf = nxt_java_OutputStream_req_buf(env, req); 92*977Smax.romanov@gmail.com if (buf == NULL) { 93*977Smax.romanov@gmail.com return; 94*977Smax.romanov@gmail.com } 95*977Smax.romanov@gmail.com 96*977Smax.romanov@gmail.com *buf->free++ = b; 97*977Smax.romanov@gmail.com 98*977Smax.romanov@gmail.com if ((uint32_t) (buf->free - buf->start) >= data->buf_size) { 99*977Smax.romanov@gmail.com nxt_java_OutputStream_flush_buf(env, req); 100*977Smax.romanov@gmail.com } 101*977Smax.romanov@gmail.com } 102*977Smax.romanov@gmail.com 103*977Smax.romanov@gmail.com 104*977Smax.romanov@gmail.com int 105*977Smax.romanov@gmail.com nxt_java_OutputStream_flush_buf(JNIEnv *env, nxt_unit_request_info_t *req) 106*977Smax.romanov@gmail.com { 107*977Smax.romanov@gmail.com int rc; 108*977Smax.romanov@gmail.com nxt_java_request_data_t *data; 109*977Smax.romanov@gmail.com 110*977Smax.romanov@gmail.com data = req->data; 111*977Smax.romanov@gmail.com 112*977Smax.romanov@gmail.com if (!nxt_unit_response_is_init(req)) { 113*977Smax.romanov@gmail.com rc = nxt_unit_response_init(req, 200, 0, 0); 114*977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 115*977Smax.romanov@gmail.com nxt_java_throw_IOException(env, "Failed to allocate response"); 116*977Smax.romanov@gmail.com 117*977Smax.romanov@gmail.com return rc; 118*977Smax.romanov@gmail.com } 119*977Smax.romanov@gmail.com } 120*977Smax.romanov@gmail.com 121*977Smax.romanov@gmail.com if (!nxt_unit_response_is_sent(req)) { 122*977Smax.romanov@gmail.com rc = nxt_unit_response_send(req); 123*977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 124*977Smax.romanov@gmail.com nxt_java_throw_IOException(env, "Failed to send response headers"); 125*977Smax.romanov@gmail.com 126*977Smax.romanov@gmail.com return rc; 127*977Smax.romanov@gmail.com } 128*977Smax.romanov@gmail.com } 129*977Smax.romanov@gmail.com 130*977Smax.romanov@gmail.com if (data->buf != NULL) { 131*977Smax.romanov@gmail.com rc = nxt_unit_buf_send(data->buf); 132*977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 133*977Smax.romanov@gmail.com nxt_java_throw_IOException(env, "Failed to send buffer"); 134*977Smax.romanov@gmail.com 135*977Smax.romanov@gmail.com } else { 136*977Smax.romanov@gmail.com data->buf = NULL; 137*977Smax.romanov@gmail.com } 138*977Smax.romanov@gmail.com 139*977Smax.romanov@gmail.com } else { 140*977Smax.romanov@gmail.com rc = NXT_UNIT_OK; 141*977Smax.romanov@gmail.com } 142*977Smax.romanov@gmail.com 143*977Smax.romanov@gmail.com return rc; 144*977Smax.romanov@gmail.com } 145*977Smax.romanov@gmail.com 146*977Smax.romanov@gmail.com 147*977Smax.romanov@gmail.com static nxt_unit_buf_t * 148*977Smax.romanov@gmail.com nxt_java_OutputStream_req_buf(JNIEnv *env, nxt_unit_request_info_t *req) 149*977Smax.romanov@gmail.com { 150*977Smax.romanov@gmail.com uint32_t size; 151*977Smax.romanov@gmail.com nxt_unit_buf_t *buf; 152*977Smax.romanov@gmail.com nxt_java_request_data_t *data; 153*977Smax.romanov@gmail.com 154*977Smax.romanov@gmail.com data = req->data; 155*977Smax.romanov@gmail.com buf = data->buf; 156*977Smax.romanov@gmail.com 157*977Smax.romanov@gmail.com if (buf == NULL || buf->free >= buf->end) { 158*977Smax.romanov@gmail.com size = data->buf_size == 0 ? nxt_unit_buf_min() : data->buf_size; 159*977Smax.romanov@gmail.com 160*977Smax.romanov@gmail.com buf = nxt_unit_response_buf_alloc(req, size); 161*977Smax.romanov@gmail.com if (buf == NULL) { 162*977Smax.romanov@gmail.com nxt_java_throw_IOException(env, "Failed to allocate buffer"); 163*977Smax.romanov@gmail.com 164*977Smax.romanov@gmail.com return NULL; 165*977Smax.romanov@gmail.com } 166*977Smax.romanov@gmail.com 167*977Smax.romanov@gmail.com data->buf = buf; 168*977Smax.romanov@gmail.com } 169*977Smax.romanov@gmail.com 170*977Smax.romanov@gmail.com return buf; 171*977Smax.romanov@gmail.com } 172*977Smax.romanov@gmail.com 173*977Smax.romanov@gmail.com 174*977Smax.romanov@gmail.com static void JNICALL 175*977Smax.romanov@gmail.com nxt_java_OutputStream_write(JNIEnv *env, jclass cls, jlong req_info_ptr, 176*977Smax.romanov@gmail.com jarray b, jint off, jint len) 177*977Smax.romanov@gmail.com { 178*977Smax.romanov@gmail.com int rc; 179*977Smax.romanov@gmail.com jint copy; 180*977Smax.romanov@gmail.com uint8_t *ptr; 181*977Smax.romanov@gmail.com nxt_unit_buf_t *buf; 182*977Smax.romanov@gmail.com nxt_unit_request_info_t *req; 183*977Smax.romanov@gmail.com nxt_java_request_data_t *data; 184*977Smax.romanov@gmail.com 185*977Smax.romanov@gmail.com req = nxt_jlong2ptr(req_info_ptr); 186*977Smax.romanov@gmail.com data = req->data; 187*977Smax.romanov@gmail.com 188*977Smax.romanov@gmail.com ptr = (*env)->GetPrimitiveArrayCritical(env, b, NULL); 189*977Smax.romanov@gmail.com 190*977Smax.romanov@gmail.com while (len > 0) { 191*977Smax.romanov@gmail.com buf = nxt_java_OutputStream_req_buf(env, req); 192*977Smax.romanov@gmail.com if (buf == NULL) { 193*977Smax.romanov@gmail.com return; 194*977Smax.romanov@gmail.com } 195*977Smax.romanov@gmail.com 196*977Smax.romanov@gmail.com copy = buf->end - buf->free; 197*977Smax.romanov@gmail.com copy = copy < len ? copy : len; 198*977Smax.romanov@gmail.com 199*977Smax.romanov@gmail.com memcpy(buf->free, ptr + off, copy); 200*977Smax.romanov@gmail.com buf->free += copy; 201*977Smax.romanov@gmail.com 202*977Smax.romanov@gmail.com len -= copy; 203*977Smax.romanov@gmail.com off += copy; 204*977Smax.romanov@gmail.com 205*977Smax.romanov@gmail.com if ((uint32_t) (buf->free - buf->start) >= data->buf_size) { 206*977Smax.romanov@gmail.com rc = nxt_java_OutputStream_flush_buf(env, req); 207*977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 208*977Smax.romanov@gmail.com break; 209*977Smax.romanov@gmail.com } 210*977Smax.romanov@gmail.com } 211*977Smax.romanov@gmail.com } 212*977Smax.romanov@gmail.com 213*977Smax.romanov@gmail.com (*env)->ReleasePrimitiveArrayCritical(env, b, ptr, 0); 214*977Smax.romanov@gmail.com } 215*977Smax.romanov@gmail.com 216*977Smax.romanov@gmail.com 217*977Smax.romanov@gmail.com static void JNICALL 218*977Smax.romanov@gmail.com nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, jlong req_info_ptr) 219*977Smax.romanov@gmail.com { 220*977Smax.romanov@gmail.com nxt_unit_request_info_t *req; 221*977Smax.romanov@gmail.com nxt_java_request_data_t *data; 222*977Smax.romanov@gmail.com 223*977Smax.romanov@gmail.com req = nxt_jlong2ptr(req_info_ptr); 224*977Smax.romanov@gmail.com data = req->data; 225*977Smax.romanov@gmail.com 226*977Smax.romanov@gmail.com if (data->buf != NULL && data->buf->free > data->buf->start) { 227*977Smax.romanov@gmail.com nxt_java_OutputStream_flush_buf(env, req); 228*977Smax.romanov@gmail.com } 229*977Smax.romanov@gmail.com } 230*977Smax.romanov@gmail.com 231*977Smax.romanov@gmail.com 232*977Smax.romanov@gmail.com static void JNICALL 233*977Smax.romanov@gmail.com nxt_java_OutputStream_close(JNIEnv *env, jclass cls, jlong req_info_ptr) 234*977Smax.romanov@gmail.com { 235*977Smax.romanov@gmail.com nxt_java_OutputStream_flush_buf(env, nxt_jlong2ptr(req_info_ptr)); 236*977Smax.romanov@gmail.com } 237