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 + sizeof(nxt_unit_response_t)
338 + req->response_max_fields * sizeof(nxt_unit_field_t);
339
340 max_size = 2 * (buf->end - p);
341 if (max_size > nxt_unit_buf_max()) {
342 nxt_unit_req_warn(req, "required max_size is too big: %"PRIu32,
343 max_size);
344 return NULL;
345 }
346
347 rc = nxt_unit_response_realloc(req, 2 * req->response_max_fields,
348 max_size);
349 if (rc != NXT_UNIT_OK) {
350 nxt_unit_req_warn(req, "reallocation failed: %"PRIu32", %"PRIu32,
351 2 * req->response_max_fields, max_size);
352 return NULL;
353 }
354 }
355
356 return req;
357 }
358
359
360 static void JNICALL
nxt_java_Response_addIntHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jint value)361 nxt_java_Response_addIntHeader(JNIEnv *env, jclass cls, jlong req_info_ptr,
362 jarray name, jint value)
363 {
364 char *name_str;
365 jsize name_len;
366 nxt_unit_request_info_t *req;
367
368 name_len = (*env)->GetArrayLength(env, name);
369
370 req = nxt_java_get_response_info(req_info_ptr, 1, name_len + 40);
371 if (req == NULL) {
372 return;
373 }
374
375 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
376 if (name_str == NULL) {
377 nxt_unit_req_warn(req, "addIntHeader: failed to get name content");
378 return;
379 }
380
381 nxt_java_add_int_header(req, name_str, name_len, value);
382
383 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
384 }
385
386
387 static void
nxt_java_add_int_header(nxt_unit_request_info_t * req,const char * name,uint8_t name_len,int value)388 nxt_java_add_int_header(nxt_unit_request_info_t *req, const char *name,
389 uint8_t name_len, int value)
390 {
391 char *p;
392 nxt_unit_field_t *f;
393 nxt_unit_response_t *resp;
394
395 resp = req->response;
396
397 f = resp->fields + resp->fields_count;
398 p = req->response_buf->free;
399
400 f->hash = nxt_unit_field_hash(name, name_len);
401 f->skip = 0;
402 f->name_length = name_len;
403
404 nxt_unit_sptr_set(&f->name, p);
405 memcpy(p, name, name_len);
406 p += name_len;
407
408 nxt_unit_sptr_set(&f->value, p);
409 f->value_length = snprintf(p, 40, "%d", (int) value);
410 p += f->value_length + 1;
411
412 resp->fields_count++;
413 req->response_buf->free = p;
414
415 }
416
417
418 static jboolean JNICALL
nxt_java_Response_containsHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)419 nxt_java_Response_containsHeader(JNIEnv *env,
420 jclass cls, jlong req_info_ptr, jarray name)
421 {
422 jboolean res;
423 char *name_str;
424 jsize name_len;
425 nxt_unit_response_t *resp;
426 nxt_unit_request_info_t *req;
427
428 req = nxt_jlong2ptr(req_info_ptr);
429
430 if (!nxt_unit_response_is_init(req)) {
431 nxt_unit_req_debug(req, "containsHeader: response is not initialized");
432 return 0;
433 }
434
435 if (nxt_unit_response_is_sent(req)) {
436 nxt_unit_req_debug(req, "containsHeader: response already sent");
437 return 0;
438 }
439
440 name_len = (*env)->GetArrayLength(env, name);
441
442 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
443 if (name_str == NULL) {
444 nxt_unit_req_warn(req, "containsHeader: failed to get name content");
445 return 0;
446 }
447
448 resp = req->response;
449
450 res = nxt_java_findHeader(resp->fields,
451 resp->fields + resp->fields_count,
452 name_str, name_len) != NULL;
453
454 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
455
456 return res;
457 }
458
459
460 static jstring JNICALL
nxt_java_Response_getHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)461 nxt_java_Response_getHeader(JNIEnv *env, jclass cls, jlong req_info_ptr,
462 jarray name)
463 {
464 char *name_str;
465 jsize name_len;
466 nxt_unit_field_t *f;
467 nxt_unit_request_info_t *req;
468
469 req = nxt_jlong2ptr(req_info_ptr);
470
471 if (!nxt_unit_response_is_init(req)) {
472 nxt_unit_req_debug(req, "getHeader: response is not initialized");
473 return NULL;
474 }
475
476 if (nxt_unit_response_is_sent(req)) {
477 nxt_unit_req_debug(req, "getHeader: response already sent");
478 return NULL;
479 }
480
481 name_len = (*env)->GetArrayLength(env, name);
482
483 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
484 if (name_str == NULL) {
485 nxt_unit_req_warn(req, "getHeader: failed to get name content");
486 return NULL;
487 }
488
489 f = nxt_java_findHeader(req->response->fields,
490 req->response->fields + req->response->fields_count,
491 name_str, name_len);
492
493 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
494
495 if (f == NULL) {
496 return NULL;
497 }
498
499 return nxt_java_newString(env, nxt_unit_sptr_get(&f->value),
500 f->value_length);
501 }
502
503
504 static jobject JNICALL
nxt_java_Response_getHeaderNames(JNIEnv * env,jclass cls,jlong req_info_ptr)505 nxt_java_Response_getHeaderNames(JNIEnv *env, jclass cls, jlong req_info_ptr)
506 {
507 nxt_unit_request_info_t *req;
508
509 req = nxt_jlong2ptr(req_info_ptr);
510
511 if (!nxt_unit_response_is_init(req)) {
512 nxt_unit_req_debug(req, "getHeaderNames: response is not initialized");
513 return NULL;
514 }
515
516 if (nxt_unit_response_is_sent(req)) {
517 nxt_unit_req_debug(req, "getHeaderNames: response already sent");
518 return NULL;
519 }
520
521 return nxt_java_newHeaderNamesEnumeration(env, req->response->fields,
522 req->response->fields_count);
523 }
524
525
526 static jobject JNICALL
nxt_java_Response_getHeaders(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)527 nxt_java_Response_getHeaders(JNIEnv *env, jclass cls,
528 jlong req_info_ptr, jarray name)
529 {
530 char *name_str;
531 jsize name_len;
532 nxt_unit_field_t *f;
533 nxt_unit_response_t *resp;
534 nxt_unit_request_info_t *req;
535
536 req = nxt_jlong2ptr(req_info_ptr);
537
538 if (!nxt_unit_response_is_init(req)) {
539 nxt_unit_req_debug(req, "getHeaders: response is not initialized");
540 return NULL;
541 }
542
543 if (nxt_unit_response_is_sent(req)) {
544 nxt_unit_req_debug(req, "getHeaders: response already sent");
545 return NULL;
546 }
547
548 resp = req->response;
549
550 name_len = (*env)->GetArrayLength(env, name);
551
552 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
553 if (name_str == NULL) {
554 nxt_unit_req_warn(req, "getHeaders: failed to get name content");
555 return NULL;
556 }
557
558 f = nxt_java_findHeader(resp->fields, resp->fields + resp->fields_count,
559 name_str, name_len);
560
561 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
562
563 if (f == NULL) {
564 f = resp->fields + resp->fields_count;
565 }
566
567 return nxt_java_newHeadersEnumeration(env, resp->fields, resp->fields_count,
568 f - resp->fields);
569 }
570
571
572 static jint JNICALL
nxt_java_Response_getStatus(JNIEnv * env,jclass cls,jlong req_info_ptr)573 nxt_java_Response_getStatus(JNIEnv *env, jclass cls, jlong req_info_ptr)
574 {
575 nxt_unit_request_info_t *req;
576
577 req = nxt_jlong2ptr(req_info_ptr);
578
579 if (!nxt_unit_response_is_init(req)) {
580 nxt_unit_req_debug(req, "getStatus: response is not initialized");
581 return 200;
582 }
583
584 if (nxt_unit_response_is_sent(req)) {
585 nxt_unit_req_debug(req, "getStatus: response already sent");
586 return 200;
587 }
588
589 return req->response->status;
590 }
591
592
593 static jobject JNICALL
nxt_java_Response_getRequest(JNIEnv * env,jclass cls,jlong req_info_ptr)594 nxt_java_Response_getRequest(JNIEnv *env, jclass cls, jlong req_info_ptr)
595 {
596 nxt_unit_request_info_t *req;
597 nxt_java_request_data_t *data;
598
599 req = nxt_jlong2ptr(req_info_ptr);
600 data = req->data;
601
602 return data->jreq;
603 }
604
605
606 static void JNICALL
nxt_java_Response_commit(JNIEnv * env,jclass cls,jlong req_info_ptr)607 nxt_java_Response_commit(JNIEnv *env, jclass cls, jlong req_info_ptr)
608 {
609 nxt_unit_request_info_t *req;
610
611 req = nxt_jlong2ptr(req_info_ptr);
612
613 nxt_java_OutputStream_flush_buf(env, req);
614 }
615
616
617 static void JNICALL
nxt_java_Response_sendRedirect(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray loc)618 nxt_java_Response_sendRedirect(JNIEnv *env, jclass cls,
619 jlong req_info_ptr, jarray loc)
620 {
621 int rc;
622 char *loc_str;
623 jsize loc_len;
624 nxt_unit_request_info_t *req;
625
626 static const char location[] = "Location";
627 static const uint32_t location_len = sizeof(location) - 1;
628
629 req = nxt_jlong2ptr(req_info_ptr);
630
631 if (nxt_unit_response_is_sent(req)) {
632 nxt_java_throw_IllegalStateException(env, "Response already sent");
633
634 return;
635 }
636
637 loc_len = (*env)->GetArrayLength(env, loc);
638
639 req = nxt_java_get_response_info(req_info_ptr, 1,
640 location_len + loc_len + 2);
641 if (req == NULL) {
642 return;
643 }
644
645 loc_str = (*env)->GetPrimitiveArrayCritical(env, loc, NULL);
646 if (loc_str == NULL) {
647 nxt_unit_req_warn(req, "sendRedirect: failed to get loc content");
648 return;
649 }
650
651 req->response->status = 302;
652
653 rc = nxt_java_response_set_header(req_info_ptr, location, location_len,
654 loc_str, loc_len);
655 if (rc != NXT_UNIT_OK) {
656 // throw
657 }
658
659 (*env)->ReleasePrimitiveArrayCritical(env, loc, loc_str, 0);
660
661 nxt_unit_response_send(req);
662 }
663
664
665 static int
nxt_java_response_set_header(jlong req_info_ptr,const char * name,jint name_len,const char * value,jint value_len)666 nxt_java_response_set_header(jlong req_info_ptr,
667 const char *name, jint name_len, const char *value, jint value_len)
668 {
669 int add_field;
670 char *dst;
671 nxt_unit_field_t *f, *e;
672 nxt_unit_response_t *resp;
673 nxt_unit_request_info_t *req;
674
675 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
676 if (req == NULL) {
677 return NXT_UNIT_ERROR;
678 }
679
680 resp = req->response;
681
682 f = resp->fields;
683 e = f + resp->fields_count;
684
685 add_field = 1;
686
687 for ( ;; ) {
688 f = nxt_java_findHeader(f, e, name, name_len);
689 if (f == NULL) {
690 break;
691 }
692
693 if (add_field && f->value_length >= (uint32_t) value_len) {
694 dst = nxt_unit_sptr_get(&f->value);
695 memcpy(dst, value, value_len);
696 dst[value_len] = '\0';
697 f->value_length = value_len;
698
699 add_field = 0;
700 f->skip = 0;
701
702 } else {
703 f->skip = 1;
704 }
705
706 ++f;
707 }
708
709 if (!add_field) {
710 return NXT_UNIT_OK;
711 }
712
713 req = nxt_java_get_response_info(req_info_ptr, 1, name_len + value_len + 2);
714 if (req == NULL) {
715 return NXT_UNIT_ERROR;
716 }
717
718 return nxt_unit_response_add_field(req, name, name_len, value, value_len);
719 }
720
721
722 static void JNICALL
nxt_java_Response_setHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jarray value)723 nxt_java_Response_setHeader(JNIEnv *env, jclass cls,
724 jlong req_info_ptr, jarray name, jarray value)
725 {
726 int rc;
727 char *name_str, *value_str;
728 jsize name_len, value_len;
729 nxt_unit_request_info_t *req;
730
731 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
732 if (name_str == NULL) {
733 req = nxt_jlong2ptr(req_info_ptr);
734 nxt_unit_req_warn(req, "setHeader: failed to get name content");
735 return;
736 }
737
738 value_str = (*env)->GetPrimitiveArrayCritical(env, value, NULL);
739 if (value_str == NULL) {
740 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
741
742 req = nxt_jlong2ptr(req_info_ptr);
743 nxt_unit_req_warn(req, "setHeader: failed to get value content");
744
745 return;
746 }
747
748 name_len = (*env)->GetArrayLength(env, name);
749 value_len = (*env)->GetArrayLength(env, value);
750
751 rc = nxt_java_response_set_header(req_info_ptr, name_str, name_len,
752 value_str, value_len);
753 if (rc != NXT_UNIT_OK) {
754 // throw
755 }
756
757 (*env)->ReleasePrimitiveArrayCritical(env, value, value_str, 0);
758 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
759 }
760
761
762 static void JNICALL
nxt_java_Response_removeHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name)763 nxt_java_Response_removeHeader(JNIEnv *env, jclass cls,
764 jlong req_info_ptr, jarray name)
765 {
766 int rc;
767 char *name_str;
768 jsize name_len;
769 nxt_unit_request_info_t *req;
770
771 name_len = (*env)->GetArrayLength(env, name);
772
773 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
774 if (name_str == NULL) {
775 req = nxt_jlong2ptr(req_info_ptr);
776 nxt_unit_req_warn(req, "setHeader: failed to get name content");
777 return;
778 }
779
780 rc = nxt_java_response_remove_header(req_info_ptr, name_str, name_len);
781 if (rc != NXT_UNIT_OK) {
782 // throw
783 }
784
785 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
786 }
787
788
789 static int
nxt_java_response_remove_header(jlong req_info_ptr,const char * name,jint name_len)790 nxt_java_response_remove_header(jlong req_info_ptr,
791 const char *name, jint name_len)
792 {
793 nxt_unit_field_t *f, *e;
794 nxt_unit_response_t *resp;
795 nxt_unit_request_info_t *req;
796
797 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
798 if (req == NULL) {
799 return NXT_UNIT_ERROR;
800 }
801
802 resp = req->response;
803
804 f = resp->fields;
805 e = f + resp->fields_count;
806
807 for ( ;; ) {
808 f = nxt_java_findHeader(f, e, name, name_len);
809 if (f == NULL) {
810 break;
811 }
812
813 f->skip = 1;
814
815 ++f;
816 }
817
818 return NXT_UNIT_OK;
819 }
820
821
822 static void JNICALL
nxt_java_Response_setIntHeader(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray name,jint value)823 nxt_java_Response_setIntHeader(JNIEnv *env, jclass cls,
824 jlong req_info_ptr, jarray name, jint value)
825 {
826 int value_len, rc;
827 char value_str[40];
828 char *name_str;
829 jsize name_len;
830
831 value_len = snprintf(value_str, sizeof(value_str), "%d", (int) value);
832
833 name_len = (*env)->GetArrayLength(env, name);
834
835 name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL);
836 if (name_str == NULL) {
837 nxt_unit_req_warn(nxt_jlong2ptr(req_info_ptr),
838 "setIntHeader: failed to get name content");
839 return;
840 }
841
842 rc = nxt_java_response_set_header(req_info_ptr, name_str, name_len,
843 value_str, value_len);
844 if (rc != NXT_UNIT_OK) {
845 // throw
846 }
847
848 (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0);
849 }
850
851
852 static void JNICALL
nxt_java_Response_setStatus(JNIEnv * env,jclass cls,jlong req_info_ptr,jint sc)853 nxt_java_Response_setStatus(JNIEnv *env, jclass cls, jlong req_info_ptr,
854 jint sc)
855 {
856 nxt_unit_request_info_t *req;
857
858 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
859 if (req == NULL) {
860 return;
861 }
862
863 req->response->status = sc;
864 }
865
866
867 static jstring JNICALL
nxt_java_Response_getContentType(JNIEnv * env,jclass cls,jlong req_info_ptr)868 nxt_java_Response_getContentType(JNIEnv *env, jclass cls, jlong req_info_ptr)
869 {
870 nxt_unit_field_t *f;
871 nxt_unit_request_info_t *req;
872
873 req = nxt_jlong2ptr(req_info_ptr);
874
875 if (!nxt_unit_response_is_init(req)) {
876 nxt_unit_req_debug(req, "getContentType: response is not initialized");
877 return NULL;
878 }
879
880 if (nxt_unit_response_is_sent(req)) {
881 nxt_unit_req_debug(req, "getContentType: response already sent");
882 return NULL;
883 }
884
885 f = nxt_java_findHeader(req->response->fields,
886 req->response->fields + req->response->fields_count,
887 "Content-Type", sizeof("Content-Type") - 1);
888
889 if (f == NULL) {
890 return NULL;
891 }
892
893 return nxt_java_newString(env, nxt_unit_sptr_get(&f->value),
894 f->value_length);
895 }
896
897
898 static jboolean JNICALL
nxt_java_Response_isCommitted(JNIEnv * env,jclass cls,jlong req_info_ptr)899 nxt_java_Response_isCommitted(JNIEnv *env, jclass cls, jlong req_info_ptr)
900 {
901 nxt_unit_request_info_t *req;
902
903 req = nxt_jlong2ptr(req_info_ptr);
904
905 if (nxt_unit_response_is_sent(req)) {
906 return 1;
907 }
908
909 return 0;
910 }
911
912
913 static void JNICALL
nxt_java_Response_reset(JNIEnv * env,jclass cls,jlong req_info_ptr)914 nxt_java_Response_reset(JNIEnv *env, jclass cls, jlong req_info_ptr)
915 {
916 nxt_unit_buf_t *buf;
917 nxt_unit_request_info_t *req;
918 nxt_java_request_data_t *data;
919
920 req = nxt_jlong2ptr(req_info_ptr);
921
922 if (nxt_unit_response_is_sent(req)) {
923 nxt_java_throw_IllegalStateException(env, "Response already sent");
924
925 return;
926 }
927
928 data = req->data;
929
930 if (data->buf != NULL && data->buf->free > data->buf->start) {
931 data->buf->free = data->buf->start;
932 }
933
934 if (nxt_unit_response_is_init(req)) {
935 req->response->status = 200;
936 req->response->fields_count = 0;
937
938 buf = req->response_buf;
939
940 buf->free = buf->start + sizeof(nxt_unit_response_t)
941 + req->response_max_fields * sizeof(nxt_unit_field_t);
942 }
943 }
944
945
946 static void JNICALL
nxt_java_Response_resetBuffer(JNIEnv * env,jclass cls,jlong req_info_ptr)947 nxt_java_Response_resetBuffer(JNIEnv *env, jclass cls, jlong req_info_ptr)
948 {
949 nxt_unit_request_info_t *req;
950 nxt_java_request_data_t *data;
951
952 req = nxt_jlong2ptr(req_info_ptr);
953 data = req->data;
954
955 if (data->buf != NULL && data->buf->free > data->buf->start) {
956 data->buf->free = data->buf->start;
957 }
958 }
959
960
961 static void JNICALL
nxt_java_Response_setBufferSize(JNIEnv * env,jclass cls,jlong req_info_ptr,jint size)962 nxt_java_Response_setBufferSize(JNIEnv *env, jclass cls, jlong req_info_ptr,
963 jint size)
964 {
965 nxt_unit_request_info_t *req;
966 nxt_java_request_data_t *data;
967
968 req = nxt_jlong2ptr(req_info_ptr);
969 data = req->data;
970
971 if (data->buf_size == (uint32_t) size) {
972 return;
973 }
974
975 if (data->buf != NULL && data->buf->free > data->buf->start) {
976 nxt_java_throw_IllegalStateException(env, "Buffer is not empty");
977
978 return;
979 }
980
981 data->buf_size = size;
982
983 if (data->buf_size > nxt_unit_buf_max()) {
984 data->buf_size = nxt_unit_buf_max();
985 }
986
987 if (data->buf != NULL
988 && (uint32_t) (data->buf->end - data->buf->start) < data->buf_size)
989 {
990 nxt_unit_buf_free(data->buf);
991
992 data->buf = NULL;
993 }
994 }
995
996
997 static jint JNICALL
nxt_java_Response_getBufferSize(JNIEnv * env,jclass cls,jlong req_info_ptr)998 nxt_java_Response_getBufferSize(JNIEnv *env, jclass cls, jlong req_info_ptr)
999 {
1000 nxt_unit_request_info_t *req;
1001 nxt_java_request_data_t *data;
1002
1003 req = nxt_jlong2ptr(req_info_ptr);
1004 data = req->data;
1005
1006 return data->buf_size;
1007 }
1008
1009
1010 static void JNICALL
nxt_java_Response_setContentLength(JNIEnv * env,jclass cls,jlong req_info_ptr,jlong len)1011 nxt_java_Response_setContentLength(JNIEnv *env, jclass cls, jlong req_info_ptr,
1012 jlong len)
1013 {
1014 nxt_unit_request_info_t *req;
1015
1016 req = nxt_java_get_response_info(req_info_ptr, 0, 0);
1017 if (req == NULL) {
1018 return;
1019 }
1020
1021 req->response->content_length = len;
1022 }
1023
1024
1025 static void JNICALL
nxt_java_Response_setContentType(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray type)1026 nxt_java_Response_setContentType(JNIEnv *env, jclass cls, jlong req_info_ptr,
1027 jarray type)
1028 {
1029 int rc;
1030 char *type_str;
1031 jsize type_len;
1032
1033 static const char content_type[] = "Content-Type";
1034 static const uint32_t content_type_len = sizeof(content_type) - 1;
1035
1036 type_len = (*env)->GetArrayLength(env, type);
1037
1038 type_str = (*env)->GetPrimitiveArrayCritical(env, type, NULL);
1039 if (type_str == NULL) {
1040 return;
1041 }
1042
1043 rc = nxt_java_response_set_header(req_info_ptr,
1044 content_type, content_type_len,
1045 type_str, type_len);
1046 if (rc != NXT_UNIT_OK) {
1047 // throw
1048 }
1049
1050 (*env)->ReleasePrimitiveArrayCritical(env, type, type_str, 0);
1051 }
1052
1053
1054 static void JNICALL
nxt_java_Response_removeContentType(JNIEnv * env,jclass cls,jlong req_info_ptr)1055 nxt_java_Response_removeContentType(JNIEnv *env, jclass cls, jlong req_info_ptr)
1056 {
1057 nxt_java_response_remove_header(req_info_ptr, "Content-Type",
1058 sizeof("Content-Type") - 1);
1059 }
1060
1061
1062 static void JNICALL
nxt_java_Response_log(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray msg)1063 nxt_java_Response_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jarray msg)
1064 {
1065 char *msg_str;
1066 jsize msg_len;
1067 nxt_unit_request_info_t *req;
1068
1069 req = nxt_jlong2ptr(req_info_ptr);
1070 msg_len = (*env)->GetArrayLength(env, msg);
1071
1072 msg_str = (*env)->GetPrimitiveArrayCritical(env, msg, NULL);
1073 if (msg_str == NULL) {
1074 nxt_unit_req_warn(req, "log: failed to get msg content");
1075 return;
1076 }
1077
1078 nxt_unit_req_log(req, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str);
1079
1080 (*env)->ReleasePrimitiveArrayCritical(env, msg, msg_str, 0);
1081 }
1082
1083
1084 static void JNICALL
nxt_java_Response_trace(JNIEnv * env,jclass cls,jlong req_info_ptr,jarray msg)1085 nxt_java_Response_trace(JNIEnv *env, jclass cls, jlong req_info_ptr, jarray msg)
1086 {
1087 #if (NXT_DEBUG)
1088 char *msg_str;
1089 jsize msg_len;
1090 nxt_unit_request_info_t *req;
1091
1092 req = nxt_jlong2ptr(req_info_ptr);
1093 msg_len = (*env)->GetArrayLength(env, msg);
1094
1095 msg_str = (*env)->GetPrimitiveArrayCritical(env, msg, NULL);
1096 if (msg_str == NULL) {
1097 nxt_unit_req_warn(req, "trace: failed to get msg content");
1098 return;
1099 }
1100
1101 nxt_unit_req_debug(req, "%.*s", msg_len, msg_str);
1102
1103 (*env)->ReleasePrimitiveArrayCritical(env, msg, msg_str, 0);
1104 #endif
1105 }
1106
1107