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
nxt_java_initInputStream(JNIEnv * env,jobject cl)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
nxt_java_InputStream_readLine(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray out,jint off,jint len)90 nxt_java_InputStream_readLine(JNIEnv *env, jclass cls,
91 jlong req_info_ptr, jarray out, jint off, jint len)
92 {
93 uint8_t *data;
94 ssize_t res;
95 nxt_unit_request_info_t *req;
96
97 req = nxt_jlong2ptr(req_info_ptr);
98
99 data = (*env)->GetPrimitiveArrayCritical(env, out, NULL);
100
101 res = nxt_unit_request_readline_size(req, len);
102
103 if (res > 0) {
104 res = nxt_unit_request_read(req, data + off, res);
105 }
106
107 nxt_unit_req_debug(req, "readLine '%.*s'", (int) res, (char *) data + off);
108
109 (*env)->ReleasePrimitiveArrayCritical(env, out, data, 0);
110
111 return res > 0 ? res : -1;
112 }
113
114
115 static jboolean JNICALL
nxt_java_InputStream_isFinished(JNIEnv * env,jclass cls,jlong req_info_ptr)116 nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls, jlong req_info_ptr)
117 {
118 nxt_unit_request_info_t *req;
119
120 req = nxt_jlong2ptr(req_info_ptr);
121
122 return req->content_length == 0;
123 }
124
125
126 static jint JNICALL
nxt_java_InputStream_readByte(JNIEnv * env,jclass cls,jlong req_info_ptr)127 nxt_java_InputStream_readByte(JNIEnv *env, jclass cls, jlong req_info_ptr)
128 {
129 uint8_t b;
130 ssize_t size;
131 nxt_unit_request_info_t *req;
132
133 req = nxt_jlong2ptr(req_info_ptr);
134
135 size = nxt_unit_request_read(req, &b, 1);
136
137 return size == 1 ? b : -1;
138 }
139
140
141 static jint JNICALL
nxt_java_InputStream_read(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray b,jint off,jint len)142 nxt_java_InputStream_read(JNIEnv *env, jclass cls, jlong req_info_ptr,
143 jarray b, jint off, jint len)
144 {
145 uint8_t *data;
146 ssize_t res;
147 nxt_unit_request_info_t *req;
148
149 req = nxt_jlong2ptr(req_info_ptr);
150
151 data = (*env)->GetPrimitiveArrayCritical(env, b, NULL);
152
153 res = nxt_unit_request_read(req, data + off, len);
154
155 nxt_unit_req_debug(req, "read '%.*s'", (int) res, (char *) data + off);
156
157 (*env)->ReleasePrimitiveArrayCritical(env, b, data, 0);
158
159 return res > 0 ? res : -1;
160 }
161
162
163 static jlong JNICALL
nxt_java_InputStream_skip(JNIEnv * env,jclass cls,jlong req_info_ptr,jlong n)164 nxt_java_InputStream_skip(JNIEnv *env, jclass cls, jlong req_info_ptr, jlong n)
165 {
166 size_t rest, b_size;
167 nxt_unit_buf_t *buf;
168 nxt_unit_request_info_t *req;
169
170 req = nxt_jlong2ptr(req_info_ptr);
171
172 rest = n;
173
174 buf = req->content_buf;
175
176 while (buf != NULL) {
177 b_size = buf->end - buf->free;
178 b_size = rest < b_size ? rest : b_size;
179
180 buf->free += b_size;
181 rest -= b_size;
182
183 if (rest == 0) {
184 if (buf->end == buf->free) {
185 buf = nxt_unit_buf_next(buf);
186 }
187
188 break;
189 }
190
191 buf = nxt_unit_buf_next(buf);
192 }
193
194 n = n < (jlong) req->content_length ? n : (jlong) req->content_length;
195
196 req->content_length -= n;
197
198 return n;
199 }
200
201
202 static jint JNICALL
nxt_java_InputStream_available(JNIEnv * env,jclass cls,jlong req_info_ptr)203 nxt_java_InputStream_available(JNIEnv *env, jclass cls, jlong req_info_ptr)
204 {
205 nxt_unit_request_info_t *req;
206
207 req = nxt_jlong2ptr(req_info_ptr);
208
209 return req->content_length;
210 }
211