1
2 /*
3 * Copyright (C) NGINX, Inc.
4 */
5
6 #include <nxt_auto_config.h>
7
8 #include <nxt_unit.h>
9 #include <nxt_unit_response.h>
10 #include <jni.h>
11 #include <stdio.h>
12
13 #include "nxt_jni.h"
14 #include "nxt_jni_Response.h"
15 #include "nxt_jni_HeadersEnumeration.h"
16 #include "nxt_jni_HeaderNamesEnumeration.h"
17 #include "nxt_jni_OutputStream.h"
18 #include "nxt_jni_URLClassLoader.h"
19
20
21 static jclass nxt_java_Response_class;
22 static jmethodID nxt_java_Response_ctor;
23
24
25 static void JNICALL nxt_java_Response_addHeader(JNIEnv *env, jclass cls,
26 jlong req_info_ptr, jarray name, jarray value);
27
28 static nxt_unit_request_info_t *nxt_java_get_response_info(
29 jlong req_info_ptr, uint32_t extra_fields, uint32_t extra_data);
30
31 static void JNICALL nxt_java_Response_addIntHeader(JNIEnv *env, jclass cls,
32 jlong req_info_ptr, jarray name, jint value);
33
34 static void nxt_java_add_int_header(nxt_unit_request_info_t *req,
35 const char *name, uint8_t name_len, int value);
36
37 static jboolean JNICALL nxt_java_Response_containsHeader(JNIEnv *env,
38 jclass cls, jlong req_info_ptr, jarray name);
39
40 static jstring JNICALL nxt_java_Response_getHeader(JNIEnv *env, jclass cls,
41 jlong req_info_ptr, jarray name);
42
43 static jobject JNICALL nxt_java_Response_getHeaderNames(JNIEnv *env,
44 jclass cls, jlong req_info_ptr);
45
46 static jobject JNICALL nxt_java_Response_getHeaders(JNIEnv *env, jclass cls,
47 jlong req_info_ptr, jarray name);
48
49 static jint JNICALL nxt_java_Response_getStatus(JNIEnv *env, jclass cls,
50 jlong req_info_ptr);
51
52 static jobject JNICALL nxt_java_Response_getRequest(JNIEnv *env, jclass cls,
53 jlong req_info_ptr);
54
55 static void JNICALL nxt_java_Response_commit(JNIEnv *env, jclass cls,
56 jlong req_info_ptr);
57
58 static void JNICALL nxt_java_Response_sendRedirect(JNIEnv *env, jclass cls,
59 jlong req_info_ptr, jarray loc);
60
61 static int nxt_java_response_set_header(jlong req_info_ptr,
62 const char *name, jint name_len, const char *value, jint value_len);
63
64 static void JNICALL nxt_java_Response_setHeader(JNIEnv *env, jclass cls,
65 jlong req_info_ptr, jarray name, jarray value);
66
67 static void JNICALL nxt_java_Response_removeHeader(JNIEnv *env, jclass cls,
68 jlong req_info_ptr, jarray name);
69
70 static int nxt_java_response_remove_header(jlong req_info_ptr,
71 const char *name, jint name_len);
72
73 static void JNICALL nxt_java_Response_setIntHeader(JNIEnv *env, jclass cls,
74 jlong req_info_ptr, jarray name, jint value);
75
76 static void JNICALL nxt_java_Response_setStatus(JNIEnv *env, jclass cls,
77 jlong req_info_ptr, jint sc);
78
79 static jstring JNICALL nxt_java_Response_getContentType(JNIEnv *env,
80 jclass cls, jlong req_info_ptr);
81
82 static jboolean JNICALL nxt_java_Response_isCommitted(JNIEnv *env, jclass cls,
83 jlong req_info_ptr);
84
85 static void JNICALL nxt_java_Response_reset(JNIEnv *env, jclass cls,
86 jlong req_info_ptr);
87
88 static void JNICALL nxt_java_Response_resetBuffer(JNIEnv *env, jclass cls,
89 jlong req_info_ptr);
90
91 static void JNICALL nxt_java_Response_setBufferSize(JNIEnv *env, jclass cls,
92 jlong req_info_ptr, jint size);
93
94 static jint JNICALL nxt_java_Response_getBufferSize(JNIEnv *env, jclass cls,
95 jlong req_info_ptr);
96
97 static void JNICALL nxt_java_Response_setContentLength(JNIEnv *env, jclass cls,
98 jlong req_info_ptr, jlong len);
99
100 static void JNICALL nxt_java_Response_setContentType(JNIEnv *env, jclass cls,
101 jlong req_info_ptr, jarray type);
102
103 static void JNICALL nxt_java_Response_removeContentType(JNIEnv *env, jclass cls,
104 jlong req_info_ptr);
105
106 static void JNICALL nxt_java_Response_log(JNIEnv *env, jclass cls,
107 jlong req_info_ptr, jarray msg);
108
109 static void JNICALL nxt_java_Response_trace(JNIEnv *env, jclass cls,
110 jlong req_info_ptr, jarray msg);
111
112 int
nxt_java_initResponse(JNIEnv * env,jobject cl)113 nxt_java_initResponse(JNIEnv *env, jobject cl)
114 {
115 int res;
116 jclass cls;
117
118 cls = nxt_java_loadClass(env, cl, "nginx.unit.Response");
119 if (cls == NULL) {
120 return NXT_UNIT_ERROR;
121 }
122
123 nxt_java_Response_class = (*env)->NewGlobalRef(env, cls);
124 (*env)->DeleteLocalRef(env, cls);
125 cls = nxt_java_Response_class;
126
127 nxt_java_Response_ctor = (*env)->GetMethodID(env, cls, "<init>", "(J)V");
128 if (nxt_java_Response_ctor == NULL) {
129 (*env)->DeleteGlobalRef(env, cls);
130 return NXT_UNIT_ERROR;
131 }
132
133 JNINativeMethod resp_methods[] = {
134 { (char *) "addHeader",
135 (char *) "(J[B[B)V",
136 nxt_java_Response_addHeader },
137
138 { (char *) "addIntHeader",
139 (char *) "(J[BI)V",
140 nxt_java_Response_addIntHeader },
141
142 { (char *) "containsHeader",
143 (char *) "(J[B)Z",
144 nxt_java_Response_containsHeader },
145
146 { (char *) "getHeader",
147 (char *) "(J[B)Ljava/lang/String;",
148 nxt_java_Response_getHeader },
149
150 { (char *) "getHeaderNames",
151 (char *) "(J)Ljava/util/Enumeration;",
152 nxt_java_Response_getHeaderNames },
153
154 { (char *) "getHeaders",
155 (char *) "(J[B)Ljava/util/Enumeration;",
156 nxt_java_Response_getHeaders },
157
158 { (char *) "getStatus",
159 (char *) "(J)I",
160 nxt_java_Response_getStatus },
161
162 { (char *) "getRequest",
163 (char *) "(J)Lnginx/unit/Request;",
164 nxt_java_Response_getRequest },
165
166 { (char *) "commit",
167 (char *) "(J)V",
168 nxt_java_Response_commit },
169
170 { (char *) "sendRedirect",
171 (char *) "(J[B)V",
172 nxt_java_Response_sendRedirect },
173
174 { (char *) "setHeader",
175 (char *) "(J[B[B)V",
176 nxt_java_Response_setHeader },
177
178 { (char *) "removeHeader",
179 (char *) "(J[B)V",
180 nxt_java_Response_removeHeader },
181
182 { (char *) "setIntHeader",
183 (char *) "(J[BI)V",
184 nxt_java_Response_setIntHeader },
185
186 { (char *) "setStatus",
187 (char *) "(JI)V",
188 nxt_java_Response_setStatus },
189
190 { (char *) "getContentType",
191 (char *) "(J)Ljava/lang/String;",
192 nxt_java_Response_getContentType },
193
194 { (char *) "isCommitted",
195 (char *) "(J)Z",
196 nxt_java_Response_isCommitted },
197
198 { (char *) "reset",
199 (char *) "(J)V",
200 nxt_java_Response_reset },
201
202 { (char *) "resetBuffer",
203 (char *) "(J)V",
204 nxt_java_Response_resetBuffer },
205
206 { (char *) "setBufferSize",
207 (char *) "(JI)V",
208 nxt_java_Response_setBufferSize },
209
210 { (char *) "getBufferSize",
211 (char *) "(J)I",
212 nxt_java_Response_getBufferSize },
213
214 { (char *) "setContentLength",
215 (char *) "(JJ)V",
216 nxt_java_Response_setContentLength },
217
218 { (char *) "setContentType",
219 (char *) "(J[B)V",
220 nxt_java_Response_setContentType },
221
222 { (char *) "removeContentType",
223 (char *) "(J)V",
224 nxt_java_Response_removeContentType },
225
226 { (char *) "log",
227 (char *) "(J[B)V",
228 nxt_java_Response_log },
229
230 { (char *) "trace",
231 (char *) "(J[B)V",
232 nxt_java_Response_trace },
233
234 };
235
236 res = (*env)->RegisterNatives(env, nxt_java_Response_class,
237 resp_methods,
238 sizeof(resp_methods)
239 / sizeof(resp_methods[0]));
240
241 nxt_unit_debug(NULL, "registered Response methods: %d", res);
242
243 if (res != 0) {
244 (*env)->DeleteGlobalRef(env, cls);
245 return NXT_UNIT_ERROR;
246 }
247
248 return NXT_UNIT_OK;
249 }
250
251
252 jobject
nxt_java_newResponse(JNIEnv * env,nxt_unit_request_info_t * req)253 nxt_java_newResponse(JNIEnv *env, nxt_unit_request_info_t *req)
254 {
255 return (*env)->NewObject(env, nxt_java_Response_class,
256 nxt_java_Response_ctor, nxt_ptr2jlong(req));
257 }
258
259
260 static void JNICALL
nxt_java_Response_addHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jarray value)261 nxt_java_Response_addHeader(JNIEnv *env, jclass cls, jlong req_info_ptr,
262 jarray name, jarray value)
263 {
264 int rc;
265 char *name_str, *value_str;
266 jsize name_len, value_len;
267 nxt_unit_request_info_t *req;
268
269 name_len = (*env)->GetArrayLength(env, name);
270 value_len = (*env)->GetArrayLength(env, value);
271
272 req = nxt_java_get_response_info(req_info_ptr, 1, name_len + value_len + 2);
273 if (req == NULL) {
274 return;
275 }
276
277 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
278 if (name_str == NULL) {
279 nxt_unit_req_warn(req, "addHeader: failed to get name content");
280 return;
281 }
282
283 value_str = (*env)->GetPrimitiveArrayCritical(env, value, NULL);
284 if (value_str == NULL) {
285 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
286 nxt_unit_req_warn(req, "addHeader: failed to get value content");
287
288 return;
289 }
290
291 rc = nxt_unit_response_add_field(req, name_str, name_len,
292 value_str, value_len);
293 if (rc != NXT_UNIT_OK) {
294 // throw
295 }
296
297 (*env)->ReleasePrimitiveArrayCritical(env, value, value_str, 0);
298 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
299 }
300
301
302 static nxt_unit_request_info_t *
nxt_java_get_response_info(jlong req_info_ptr,uint32_t extra_fields,uint32_t extra_data)303 nxt_java_get_response_info(jlong req_info_ptr, uint32_t extra_fields,
304 uint32_t extra_data)
305 {
306 int rc;
307 char *p;
308 uint32_t max_size;
309 nxt_unit_buf_t *buf;
310 nxt_unit_request_info_t *req;
311 nxt_java_request_data_t *data;
312
313 req = nxt_jlong2ptr(req_info_ptr);
314
315 if (nxt_unit_response_is_sent(req)) {
316 return NULL;
317 }
318
319 data = req->data;
320
321 if (!nxt_unit_response_is_init(req)) {
322 max_size = nxt_unit_buf_max();
323 max_size = max_size < data->header_size ? max_size : data->header_size;
324
325 rc = nxt_unit_response_init(req, 200, 16, max_size);
326 if (rc != NXT_UNIT_OK) {
327 return NULL;
328 }
329 }
330
331 buf = req->response_buf;
332
333 if (extra_fields > req->response_max_fields
334 - req->response->fields_count
335 || extra_data > (uint32_t) (buf->end - buf->free))
336 {
337 p = buf->start + req->response_max_fields * sizeof(nxt_unit_field_t);
338
339 max_size = 2 * (buf->end - p);
340 if (max_size > nxt_unit_buf_max()) {
341 nxt_unit_req_warn(req, "required max_size is too big: %"PRIu32,
342 max_size);
343 return NULL;
344 }
345
346 rc = nxt_unit_response_realloc(req, 2 * req->response_max_fields,
347 max_size);
348 if (rc != NXT_UNIT_OK) {
349 nxt_unit_req_warn(req, "reallocation failed: %"PRIu32", %"PRIu32,
350 2 * req->response_max_fields, max_size);
351 return NULL;
352 }
353 }
354
355 return req;
356 }
357
358
359 static void JNICALL
nxt_java_Response_addIntHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jint value)360 nxt_java_Response_addIntHeader(JNIEnv *env, jclass cls, jlong req_info_ptr,
361 jarray name, jint value)
362 {
363 char *name_str;
364 jsize name_len;
365 nxt_unit_request_info_t *req;
366
367 name_len = (*env)->GetArrayLength(env, name);
368
369 req = nxt_java_get_response_info(req_info_ptr, 1, name_len + 40);
370 if (req == NULL) {
371 return;
372 }
373
374 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
375 if (name_str == NULL) {
376 nxt_unit_req_warn(req, "addIntHeader: failed to get name content");
377 return;
378 }
379
380 nxt_java_add_int_header(req, name_str, name_len, value);
381
382 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
383 }
384
385
386 static void
nxt_java_add_int_header(nxt_unit_request_info_t * req,const char * name,uint8_t name_len,int value)387 nxt_java_add_int_header(nxt_unit_request_info_t *req, const char *name,
388 uint8_t name_len, int value)
389 {
390 char *p;
391 nxt_unit_field_t *f;
392 nxt_unit_response_t *resp;
393
394 resp = req->response;
395
396 f = resp->fields + resp->fields_count;
397 p = req->response_buf->free;
398
399 f->hash = nxt_unit_field_hash(name, name_len);
400 f->skip = 0;
401 f->name_length = name_len;
402
403 nxt_unit_sptr_set(&f->name, p);
404 memcpy(p, name, name_len);
405 p += name_len;
406
407 nxt_unit_sptr_set(&f->value, p);
408 f->value_length = snprintf(p, 40, "%d", (int) value);
409 p += f->value_length + 1;
410
411 resp->fields_count++;
412 req->response_buf->free = p;
413
414 }
415
416
417 static jboolean JNICALL
nxt_java_Response_containsHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)418 nxt_java_Response_containsHeader(JNIEnv *env,
419 jclass cls, jlong req_info_ptr, jarray name)
420 {
421 jboolean res;
422 char *name_str;
423 jsize name_len;
424 nxt_unit_response_t *resp;
425 nxt_unit_request_info_t *req;
426
427 req = nxt_jlong2ptr(req_info_ptr);
428
429 if (!nxt_unit_response_is_init(req)) {
430 nxt_unit_req_debug(req, "containsHeader: response is not initialized");
431 return 0;
432 }
433
434 if (nxt_unit_response_is_sent(req)) {
435 nxt_unit_req_debug(req, "containsHeader: response already sent");
436 return 0;
437 }
438
439 name_len = (*env)->GetArrayLength(env, name);
440
441 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
442 if (name_str == NULL) {
443 nxt_unit_req_warn(req, "containsHeader: failed to get name content");
444 return 0;
445 }
446
447 resp = req->response;
448
449 res = nxt_java_findHeader(resp->fields,
450 resp->fields + resp->fields_count,
451 name_str, name_len) != NULL;
452
453 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
454
455 return res;
456 }
457
458
459 static jstring JNICALL
nxt_java_Response_getHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)460 nxt_java_Response_getHeader(JNIEnv *env, jclass cls, jlong req_info_ptr,
461 jarray name)
462 {
463 char *name_str;
464 jsize name_len;
465 nxt_unit_field_t *f;
466 nxt_unit_request_info_t *req;
467
468 req = nxt_jlong2ptr(req_info_ptr);
469
470 if (!nxt_unit_response_is_init(req)) {
471 nxt_unit_req_debug(req, "getHeader: response is not initialized");
472 return NULL;
473 }
474
475 if (nxt_unit_response_is_sent(req)) {
476 nxt_unit_req_debug(req, "getHeader: response already sent");
477 return NULL;
478 }
479
480 name_len = (*env)->GetArrayLength(env, name);
481
482 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
483 if (name_str == NULL) {
484 nxt_unit_req_warn(req, "getHeader: failed to get name content");
485 return NULL;
486 }
487
488 f = nxt_java_findHeader(req->response->fields,
489 req->response->fields + req->response->fields_count,
490 name_str, name_len);
491
492 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
493
494 if (f == NULL) {
495 return NULL;
496 }
497
498 return nxt_java_newString(env, nxt_unit_sptr_get(&f->value),
499 f->value_length);
500 }
501
502
503 static jobject JNICALL
nxt_java_Response_getHeaderNames(JNIEnv * env,jclass cls,jlong req_info_ptr)504 nxt_java_Response_getHeaderNames(JNIEnv *env, jclass cls, jlong req_info_ptr)
505 {
506 nxt_unit_request_info_t *req;
507
508 req = nxt_jlong2ptr(req_info_ptr);
509
510 if (!nxt_unit_response_is_init(req)) {
511 nxt_unit_req_debug(req, "getHeaderNames: response is not initialized");
512 return NULL;
513 }
514
515 if (nxt_unit_response_is_sent(req)) {
516 nxt_unit_req_debug(req, "getHeaderNames: response already sent");
517 return NULL;
518 }
519
520 return nxt_java_newHeaderNamesEnumeration(env, req->response->fields,
521 req->response->fields_count);
522 }
523
524
525 static jobject JNICALL
nxt_java_Response_getHeaders(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)526 nxt_java_Response_getHeaders(JNIEnv *env, jclass cls,
527 jlong req_info_ptr, jarray name)
528 {
529 char *name_str;
530 jsize name_len;
531 nxt_unit_field_t *f;
532 nxt_unit_response_t *resp;
533 nxt_unit_request_info_t *req;
534
535 req = nxt_jlong2ptr(req_info_ptr);
536
537 if (!nxt_unit_response_is_init(req)) {
538 nxt_unit_req_debug(req, "getHeaders: response is not initialized");
539 return NULL;
540 }
541
542 if (nxt_unit_response_is_sent(req)) {
543 nxt_unit_req_debug(req, "getHeaders: response already sent");
544 return NULL;
545 }
546
547 resp = req->response;
548
549 name_len = (*env)->GetArrayLength(env, name);
550
551 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
552 if (name_str == NULL) {
553 nxt_unit_req_warn(req, "getHeaders: failed to get name content");
554 return NULL;
555 }
556
557 f = nxt_java_findHeader(resp->fields, resp->fields + resp->fields_count,
558 name_str, name_len);
559
560 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
561
562 if (f == NULL) {
563 f = resp->fields + resp->fields_count;
564 }
565
566 return nxt_java_newHeadersEnumeration(env, resp->fields, resp->fields_count,
567 f - resp->fields);
568 }
569
570
571 static jint JNICALL
nxt_java_Response_getStatus(JNIEnv * env,jclass cls,jlong req_info_ptr)572 nxt_java_Response_getStatus(JNIEnv *env, jclass cls, jlong req_info_ptr)
573 {
574 nxt_unit_request_info_t *req;
575
576 req = nxt_jlong2ptr(req_info_ptr);
577
578 if (!nxt_unit_response_is_init(req)) {
579 nxt_unit_req_debug(req, "getStatus: response is not initialized");
580 return 200;
581 }
582
583 if (nxt_unit_response_is_sent(req)) {
584 nxt_unit_req_debug(req, "getStatus: response already sent");
585 return 200;
586 }
587
588 return req->response->status;
589 }
590
591
592 static jobject JNICALL
nxt_java_Response_getRequest(JNIEnv * env,jclass cls,jlong req_info_ptr)593 nxt_java_Response_getRequest(JNIEnv *env, jclass cls, jlong req_info_ptr)
594 {
595 nxt_unit_request_info_t *req;
596 nxt_java_request_data_t *data;
597
598 req = nxt_jlong2ptr(req_info_ptr);
599 data = req->data;
600
601 return data->jreq;
602 }
603
604
605 static void JNICALL
nxt_java_Response_commit(JNIEnv * env,jclass cls,jlong req_info_ptr)606 nxt_java_Response_commit(JNIEnv *env, jclass cls, jlong req_info_ptr)
607 {
608 nxt_unit_request_info_t *req;
609
610 req = nxt_jlong2ptr(req_info_ptr);
611
612 nxt_java_OutputStream_flush_buf(env, req);
613 }
614
615
616 static void JNICALL
nxt_java_Response_sendRedirect(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray loc)617 nxt_java_Response_sendRedirect(JNIEnv *env, jclass cls,
618 jlong req_info_ptr, jarray loc)
619 {
620 int rc;
621 char *loc_str;
622 jsize loc_len;
623 nxt_unit_request_info_t *req;
624
625 static const char location[] = "Location";
626 static const uint32_t location_len = sizeof(location) - 1;
627
628 req = nxt_jlong2ptr(req_info_ptr);
629
630 if (nxt_unit_response_is_sent(req)) {
631 nxt_java_throw_IllegalStateException(env, "Response already sent");
632
633 return;
634 }
635
636 loc_len = (*env)->GetArrayLength(env, loc);
637
638 req = nxt_java_get_response_info(req_info_ptr, 1,
639 location_len + loc_len + 2);
640 if (req == NULL) {
641 return;
642 }
643
644 loc_str = (*env)->GetPrimitiveArrayCritical(env, loc, NULL);
645 if (loc_str == NULL) {
646 nxt_unit_req_warn(req, "sendRedirect: failed to get loc content");
647 return;
648 }
649
650 req->response->status = 302;
651
652 rc = nxt_java_response_set_header(req_info_ptr, location, location_len,
653 loc_str, loc_len);
654 if (rc != NXT_UNIT_OK) {
655 // throw
656 }
657
658 (*env)->ReleasePrimitiveArrayCritical(env, loc, loc_str, 0);
659
660 nxt_unit_response_send(req);
661 }
662
663
664 static int
nxt_java_response_set_header(jlong req_info_ptr,const char * name,jint name_len,const char * value,jint value_len)665 nxt_java_response_set_header(jlong req_info_ptr,
666 const char *name, jint name_len, const char *value, jint value_len)
667 {
668 int add_field;
669 char *dst;
670 nxt_unit_field_t *f, *e;
671 nxt_unit_response_t *resp;
672 nxt_unit_request_info_t *req;
673
674 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
675 if (req == NULL) {
676 return NXT_UNIT_ERROR;
677 }
678
679 resp = req->response;
680
681 f = resp->fields;
682 e = f + resp->fields_count;
683
684 add_field = 1;
685
686 for ( ;; ) {
687 f = nxt_java_findHeader(f, e, name, name_len);
688 if (f == NULL) {
689 break;
690 }
691
692 if (add_field && f->value_length >= (uint32_t) value_len) {
693 dst = nxt_unit_sptr_get(&f->value);
694 memcpy(dst, value, value_len);
695 dst[value_len] = '\0';
696 f->value_length = value_len;
697
698 add_field = 0;
699 f->skip = 0;
700
701 } else {
702 f->skip = 1;
703 }
704
705 ++f;
706 }
707
708 if (!add_field) {
709 return NXT_UNIT_OK;
710 }
711
712 req = nxt_java_get_response_info(req_info_ptr, 1, name_len + value_len + 2);
713 if (req == NULL) {
714 return NXT_UNIT_ERROR;
715 }
716
717 return nxt_unit_response_add_field(req, name, name_len, value, value_len);
718 }
719
720
721 static void JNICALL
nxt_java_Response_setHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jarray value)722 nxt_java_Response_setHeader(JNIEnv *env, jclass cls,
723 jlong req_info_ptr, jarray name, jarray value)
724 {
725 int rc;
726 char *name_str, *value_str;
727 jsize name_len, value_len;
728 nxt_unit_request_info_t *req;
729
730 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
731 if (name_str == NULL) {
732 req = nxt_jlong2ptr(req_info_ptr);
733 nxt_unit_req_warn(req, "setHeader: failed to get name content");
734 return;
735 }
736
737 value_str = (*env)->GetPrimitiveArrayCritical(env, value, NULL);
738 if (value_str == NULL) {
739 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
740
741 req = nxt_jlong2ptr(req_info_ptr);
742 nxt_unit_req_warn(req, "setHeader: failed to get value content");
743
744 return;
745 }
746
747 name_len = (*env)->GetArrayLength(env, name);
748 value_len = (*env)->GetArrayLength(env, value);
749
750 rc = nxt_java_response_set_header(req_info_ptr, name_str, name_len,
751 value_str, value_len);
752 if (rc != NXT_UNIT_OK) {
753 // throw
754 }
755
756 (*env)->ReleasePrimitiveArrayCritical(env, value, value_str, 0);
757 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
758 }
759
760
761 static void JNICALL
nxt_java_Response_removeHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)762 nxt_java_Response_removeHeader(JNIEnv *env, jclass cls,
763 jlong req_info_ptr, jarray name)
764 {
765 int rc;
766 char *name_str;
767 jsize name_len;
768 nxt_unit_request_info_t *req;
769
770 name_len = (*env)->GetArrayLength(env, name);
771
772 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
773 if (name_str == NULL) {
774 req = nxt_jlong2ptr(req_info_ptr);
775 nxt_unit_req_warn(req, "setHeader: failed to get name content");
776 return;
777 }
778
779 rc = nxt_java_response_remove_header(req_info_ptr, name_str, name_len);
780 if (rc != NXT_UNIT_OK) {
781 // throw
782 }
783
784 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
785 }
786
787
788 static int
nxt_java_response_remove_header(jlong req_info_ptr,const char * name,jint name_len)789 nxt_java_response_remove_header(jlong req_info_ptr,
790 const char *name, jint name_len)
791 {
792 nxt_unit_field_t *f, *e;
793 nxt_unit_response_t *resp;
794 nxt_unit_request_info_t *req;
795
796 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
797 if (req == NULL) {
798 return NXT_UNIT_ERROR;
799 }
800
801 resp = req->response;
802
803 f = resp->fields;
804 e = f + resp->fields_count;
805
806 for ( ;; ) {
807 f = nxt_java_findHeader(f, e, name, name_len);
808 if (f == NULL) {
809 break;
810 }
811
812 f->skip = 1;
813
814 ++f;
815 }
816
817 return NXT_UNIT_OK;
818 }
819
820
821 static void JNICALL
nxt_java_Response_setIntHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jint value)822 nxt_java_Response_setIntHeader(JNIEnv *env, jclass cls,
823 jlong req_info_ptr, jarray name, jint value)
824 {
825 int value_len, rc;
826 char value_str[40];
827 char *name_str;
828 jsize name_len;
829
830 value_len = snprintf(value_str, sizeof(value_str), "%d", (int) value);
831
832 name_len = (*env)->GetArrayLength(env, name);
833
834 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
835 if (name_str == NULL) {
836 nxt_unit_req_warn(nxt_jlong2ptr(req_info_ptr),
837 "setIntHeader: failed to get name content");
838 return;
839 }
840
841 rc = nxt_java_response_set_header(req_info_ptr, name_str, name_len,
842 value_str, value_len);
843 if (rc != NXT_UNIT_OK) {
844 // throw
845 }
846
847 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
848 }
849
850
851 static void JNICALL
nxt_java_Response_setStatus(JNIEnv * env,jclass cls,jlong req_info_ptr,jint sc)852 nxt_java_Response_setStatus(JNIEnv *env, jclass cls, jlong req_info_ptr,
853 jint sc)
854 {
855 nxt_unit_request_info_t *req;
856
857 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
858 if (req == NULL) {
859 return;
860 }
861
862 req->response->status = sc;
863 }
864
865
866 static jstring JNICALL
nxt_java_Response_getContentType(JNIEnv * env,jclass cls,jlong req_info_ptr)867 nxt_java_Response_getContentType(JNIEnv *env, jclass cls, jlong req_info_ptr)
868 {
869 nxt_unit_field_t *f;
870 nxt_unit_request_info_t *req;
871
872 req = nxt_jlong2ptr(req_info_ptr);
873
874 if (!nxt_unit_response_is_init(req)) {
875 nxt_unit_req_debug(req, "getContentType: response is not initialized");
876 return NULL;
877 }
878
879 if (nxt_unit_response_is_sent(req)) {
880 nxt_unit_req_debug(req, "getContentType: response already sent");
881 return NULL;
882 }
883
884 f = nxt_java_findHeader(req->response->fields,
885 req->response->fields + req->response->fields_count,
886 "Content-Type", sizeof("Content-Type") - 1);
887
888 if (f == NULL) {
889 return NULL;
890 }
891
892 return nxt_java_newString(env, nxt_unit_sptr_get(&f->value),
893 f->value_length);
894 }
895
896
897 static jboolean JNICALL
nxt_java_Response_isCommitted(JNIEnv * env,jclass cls,jlong req_info_ptr)898 nxt_java_Response_isCommitted(JNIEnv *env, jclass cls, jlong req_info_ptr)
899 {
900 nxt_unit_request_info_t *req;
901
902 req = nxt_jlong2ptr(req_info_ptr);
903
904 if (nxt_unit_response_is_sent(req)) {
905 return 1;
906 }
907
908 return 0;
909 }
910
911
912 static void JNICALL
nxt_java_Response_reset(JNIEnv * env,jclass cls,jlong req_info_ptr)913 nxt_java_Response_reset(JNIEnv *env, jclass cls, jlong req_info_ptr)
914 {
915 nxt_unit_buf_t *buf;
916 nxt_unit_request_info_t *req;
917 nxt_java_request_data_t *data;
918
919 req = nxt_jlong2ptr(req_info_ptr);
920
921 if (nxt_unit_response_is_sent(req)) {
922 nxt_java_throw_IllegalStateException(env, "Response already sent");
923
924 return;
925 }
926
927 data = req->data;
928
929 if (data->buf != NULL && data->buf->free > data->buf->start) {
930 data->buf->free = data->buf->start;
931 }
932
933 if (nxt_unit_response_is_init(req)) {
934 req->response->status = 200;
935 req->response->fields_count = 0;
936
937 buf = req->response_buf;
938
939 buf->free = buf->start + req->response_max_fields
940 * sizeof(nxt_unit_field_t);
941 }
942 }
943
944
945 static void JNICALL
nxt_java_Response_resetBuffer(JNIEnv * env,jclass cls,jlong req_info_ptr)946 nxt_java_Response_resetBuffer(JNIEnv *env, jclass cls, jlong req_info_ptr)
947 {
948 nxt_unit_request_info_t *req;
949 nxt_java_request_data_t *data;
950
951 req = nxt_jlong2ptr(req_info_ptr);
952 data = req->data;
953
954 if (data->buf != NULL && data->buf->free > data->buf->start) {
955 data->buf->free = data->buf->start;
956 }
957 }
958
959
960 static void JNICALL
nxt_java_Response_setBufferSize(JNIEnv * env,jclass cls,jlong req_info_ptr,jint size)961 nxt_java_Response_setBufferSize(JNIEnv *env, jclass cls, jlong req_info_ptr,
962 jint size)
963 {
964 nxt_unit_request_info_t *req;
965 nxt_java_request_data_t *data;
966
967 req = nxt_jlong2ptr(req_info_ptr);
968 data = req->data;
969
970 if (data->buf_size == (uint32_t) size) {
971 return;
972 }
973
974 if (data->buf != NULL && data->buf->free > data->buf->start) {
975 nxt_java_throw_IllegalStateException(env, "Buffer is not empty");
976
977 return;
978 }
979
980 data->buf_size = size;
981
982 if (data->buf_size > nxt_unit_buf_max()) {
983 data->buf_size = nxt_unit_buf_max();
984 }
985
986 if (data->buf != NULL
987 && (uint32_t) (data->buf->end - data->buf->start) < data->buf_size)
988 {
989 nxt_unit_buf_free(data->buf);
990
991 data->buf = NULL;
992 }
993 }
994
995
996 static jint JNICALL
nxt_java_Response_getBufferSize(JNIEnv * env,jclass cls,jlong req_info_ptr)997 nxt_java_Response_getBufferSize(JNIEnv *env, jclass cls, jlong req_info_ptr)
998 {
999 nxt_unit_request_info_t *req;
1000 nxt_java_request_data_t *data;
1001
1002 req = nxt_jlong2ptr(req_info_ptr);
1003 data = req->data;
1004
1005 return data->buf_size;
1006 }
1007
1008
1009 static void JNICALL
nxt_java_Response_setContentLength(JNIEnv * env,jclass cls,jlong req_info_ptr,jlong len)1010 nxt_java_Response_setContentLength(JNIEnv *env, jclass cls, jlong req_info_ptr,
1011 jlong len)
1012 {
1013 nxt_unit_request_info_t *req;
1014
1015 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
1016 if (req == NULL) {
1017 return;
1018 }
1019
1020 req->response->content_length = len;
1021 }
1022
1023
1024 static void JNICALL
nxt_java_Response_setContentType(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray type)1025 nxt_java_Response_setContentType(JNIEnv *env, jclass cls, jlong req_info_ptr,
1026 jarray type)
1027 {
1028 int rc;
1029 char *type_str;
1030 jsize type_len;
1031
1032 static const char content_type[] = "Content-Type";
1033 static const uint32_t content_type_len = sizeof(content_type) - 1;
1034
1035 type_len = (*env)->GetArrayLength(env, type);
1036
1037 type_str = (*env)->GetPrimitiveArrayCritical(env, type, NULL);
1038 if (type_str == NULL) {
1039 return;
1040 }
1041
1042 rc = nxt_java_response_set_header(req_info_ptr,
1043 content_type, content_type_len,
1044 type_str, type_len);
1045 if (rc != NXT_UNIT_OK) {
1046 // throw
1047 }
1048
1049 (*env)->ReleasePrimitiveArrayCritical(env, type, type_str, 0);
1050 }
1051
1052
1053 static void JNICALL
nxt_java_Response_removeContentType(JNIEnv * env,jclass cls,jlong req_info_ptr)1054 nxt_java_Response_removeContentType(JNIEnv *env, jclass cls, jlong req_info_ptr)
1055 {
1056 nxt_java_response_remove_header(req_info_ptr, "Content-Type",
1057 sizeof("Content-Type") - 1);
1058 }
1059
1060
1061 static void JNICALL
nxt_java_Response_log(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray msg)1062 nxt_java_Response_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jarray msg)
1063 {
1064 char *msg_str;
1065 jsize msg_len;
1066 nxt_unit_request_info_t *req;
1067
1068 req = nxt_jlong2ptr(req_info_ptr);
1069 msg_len = (*env)->GetArrayLength(env, msg);
1070
1071 msg_str = (*env)->GetPrimitiveArrayCritical(env, msg, NULL);
1072 if (msg_str == NULL) {
1073 nxt_unit_req_warn(req, "log: failed to get msg content");
1074 return;
1075 }
1076
1077 nxt_unit_req_log(req, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str);
1078
1079 (*env)->ReleasePrimitiveArrayCritical(env, msg, msg_str, 0);
1080 }
1081
1082
1083 static void JNICALL
nxt_java_Response_trace(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray msg)1084 nxt_java_Response_trace(JNIEnv *env, jclass cls, jlong req_info_ptr, jarray msg)
1085 {
1086 #if (NXT_DEBUG)
1087 char *msg_str;
1088 jsize msg_len;
1089 nxt_unit_request_info_t *req;
1090
1091 req = nxt_jlong2ptr(req_info_ptr);
1092 msg_len = (*env)->GetArrayLength(env, msg);
1093
1094 msg_str = (*env)->GetPrimitiveArrayCritical(env, msg, NULL);
1095 if (msg_str == NULL) {
1096 nxt_unit_req_warn(req, "trace: failed to get msg content");
1097 return;
1098 }
1099
1100 nxt_unit_req_debug(req, "%.*s", msg_len, msg_str);
1101
1102 (*env)->ReleasePrimitiveArrayCritical(env, msg, msg_str, 0);
1103 #endif
1104 }
1105
1106