xref: /unit/src/java/nxt_jni_InputStream.c (revision 977:4f9268f27b57)
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