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