1 2 /* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6 #include <nxt_auto_config.h> 7 8 #include <jni.h> 9 #include <nxt_unit.h> 10 #include <string.h> 11 12 #include "nxt_jni.h" 13 #include "nxt_jni_InputStream.h" 14 #include "nxt_jni_URLClassLoader.h" 15 16 17 static jint JNICALL nxt_java_InputStream_readLine(JNIEnv *env, jclass cls, 18 jlong req_info_ptr, jarray b, jint off, jint len); 19 static jboolean JNICALL nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls, 20 jlong req_info_ptr); 21 static jint JNICALL nxt_java_InputStream_readByte(JNIEnv *env, jclass cls, 22 jlong req_info_ptr); 23 static jint JNICALL nxt_java_InputStream_read(JNIEnv *env, jclass cls, 24 jlong req_info_ptr, jarray b, jint off, jint len); 25 static jlong JNICALL nxt_java_InputStream_skip(JNIEnv *env, jclass cls, 26 jlong req_info_ptr, jlong n); 27 static jint JNICALL nxt_java_InputStream_available(JNIEnv *env, jclass cls, 28 jlong req_info_ptr); 29 30 31 static jclass nxt_java_InputStream_class; 32 33 34 int 35 nxt_java_initInputStream(JNIEnv *env, jobject cl) 36 { 37 int res; 38 jclass cls; 39 40 cls = nxt_java_loadClass(env, cl, "nginx.unit.InputStream"); 41 if (cls == NULL) { 42 return NXT_UNIT_ERROR; 43 } 44 45 nxt_java_InputStream_class = (*env)->NewGlobalRef(env, cls); 46 (*env)->DeleteLocalRef(env, cls); 47 48 JNINativeMethod is_methods[] = { 49 { (char *) "readLine", 50 (char *) "(J[BII)I", 51 nxt_java_InputStream_readLine }, 52 53 { (char *) "isFinished", 54 (char *) "(J)Z", 55 nxt_java_InputStream_isFinished }, 56 57 { (char *) "read", 58 (char *) "(J)I", 59 nxt_java_InputStream_readByte }, 60 61 { (char *) "read", 62 (char *) "(J[BII)I", 63 nxt_java_InputStream_read }, 64 65 { (char *) "skip", 66 (char *) "(JJ)J", 67 nxt_java_InputStream_skip }, 68 69 { (char *) "available", 70 (char *) "(J)I", 71 nxt_java_InputStream_available }, 72 }; 73 74 res = (*env)->RegisterNatives(env, nxt_java_InputStream_class, 75 is_methods, 76 sizeof(is_methods) / sizeof(is_methods[0])); 77 78 nxt_unit_debug(NULL, "registered InputStream methods: %d", res); 79 80 if (res != 0) { 81 (*env)->DeleteGlobalRef(env, cls); 82 return NXT_UNIT_ERROR; 83 } 84 85 return NXT_UNIT_OK; 86 } 87 88 89 static jint JNICALL 90 nxt_java_InputStream_readLine(JNIEnv *env, jclass cls, 91 jlong req_info_ptr, jarray out, jint off, jint len) 92 { 93 char *p; 94 jint size, b_size; 95 uint8_t *data; 96 ssize_t res; 97 nxt_unit_buf_t *b; 98 nxt_unit_request_info_t *req; 99 100 req = nxt_jlong2ptr(req_info_ptr); 101 102 size = 0; 103 104 for (b = req->content_buf; b; b = nxt_unit_buf_next(b)) { 105 b_size = b->end - b->free; 106 p = memchr(b->free, '\n', b_size); 107 108 if (p != NULL) { 109 p++; 110 size += p - b->free; 111 break; 112 } 113 114 size += b_size; 115 116 if (size >= len) { 117 break; 118 } 119 } 120 121 len = len < size ? len : size; 122 123 data = (*env)->GetPrimitiveArrayCritical(env, out, NULL); 124 125 res = nxt_unit_request_read(req, data + off, len); 126 127 nxt_unit_req_debug(req, "readLine '%.*s'", res, (char *) data + off); 128 129 (*env)->ReleasePrimitiveArrayCritical(env, out, data, 0); 130 131 return res > 0 ? res : -1; 132 } 133 134 135 static jboolean JNICALL 136 nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls, jlong req_info_ptr) 137 { 138 nxt_unit_request_info_t *req; 139 140 req = nxt_jlong2ptr(req_info_ptr); 141 142 return req->content_length == 0; 143 } 144 145 146 static jint JNICALL 147 nxt_java_InputStream_readByte(JNIEnv *env, jclass cls, jlong req_info_ptr) 148 { 149 uint8_t b; 150 ssize_t size; 151 nxt_unit_request_info_t *req; 152 153 req = nxt_jlong2ptr(req_info_ptr); 154 155 size = nxt_unit_request_read(req, &b, 1); 156 157 return size == 1 ? b : -1; 158 } 159 160 161 static jint JNICALL 162 nxt_java_InputStream_read(JNIEnv *env, jclass cls, jlong req_info_ptr, 163 jarray b, jint off, jint len) 164 { 165 uint8_t *data; 166 ssize_t res; 167 nxt_unit_request_info_t *req; 168 169 req = nxt_jlong2ptr(req_info_ptr); 170 171 data = (*env)->GetPrimitiveArrayCritical(env, b, NULL); 172 173 res = nxt_unit_request_read(req, data + off, len); 174 175 nxt_unit_req_debug(req, "read '%.*s'", res, (char *) data + off); 176 177 (*env)->ReleasePrimitiveArrayCritical(env, b, data, 0); 178 179 return res > 0 ? res : -1; 180 } 181 182 183 static jlong JNICALL 184 nxt_java_InputStream_skip(JNIEnv *env, jclass cls, jlong req_info_ptr, jlong n) 185 { 186 size_t rest, b_size; 187 nxt_unit_buf_t *buf; 188 nxt_unit_request_info_t *req; 189 190 req = nxt_jlong2ptr(req_info_ptr); 191 192 rest = n; 193 194 buf = req->content_buf; 195 196 while (buf != NULL) { 197 b_size = buf->end - buf->free; 198 b_size = rest < b_size ? rest : b_size; 199 200 buf->free += b_size; 201 rest -= b_size; 202 203 if (rest == 0) { 204 if (buf->end == buf->free) { 205 buf = nxt_unit_buf_next(buf); 206 } 207 208 break; 209 } 210 211 buf = nxt_unit_buf_next(buf); 212 } 213 214 n = n < (jlong) req->content_length ? n : (jlong) req->content_length; 215 216 req->content_length -= n; 217 218 return n; 219 } 220 221 222 static jint JNICALL 223 nxt_java_InputStream_available(JNIEnv *env, jclass cls, jlong req_info_ptr) 224 { 225 nxt_unit_request_info_t *req; 226 227 req = nxt_jlong2ptr(req_info_ptr); 228 229 return req->content_length; 230 } 231