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