xref: /unit/src/java/nxt_jni_Request.c (revision 977:4f9268f27b57)
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_request.h>
10 #include <jni.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 #include "nxt_jni.h"
15 #include "nxt_jni_Request.h"
16 #include "nxt_jni_URLClassLoader.h"
17 #include "nxt_jni_HeadersEnumeration.h"
18 #include "nxt_jni_HeaderNamesEnumeration.h"
19 
20 
21 static jstring JNICALL nxt_java_Request_getHeader(JNIEnv *env, jclass cls,
22     jlong req_ptr, jstring name, jint name_len);
23 static jobject JNICALL nxt_java_Request_getHeaderNames(JNIEnv *env, jclass cls,
24     jlong req_ptr);
25 static jobject JNICALL nxt_java_Request_getHeaders(JNIEnv *env, jclass cls,
26     jlong req_ptr, jstring name, jint name_len);
27 static jint JNICALL nxt_java_Request_getIntHeader(JNIEnv *env, jclass cls,
28     jlong req_ptr, jstring name, jint name_len);
29 static jstring JNICALL nxt_java_Request_getMethod(JNIEnv *env, jclass cls,
30     jlong req_ptr);
31 static jstring JNICALL nxt_java_Request_getQueryString(JNIEnv *env, jclass cls,
32     jlong req_ptr);
33 static jstring JNICALL nxt_java_Request_getRequestURI(JNIEnv *env, jclass cls,
34     jlong req_ptr);
35 static jlong JNICALL nxt_java_Request_getContentLength(JNIEnv *env, jclass cls,
36     jlong req_ptr);
37 static jstring JNICALL nxt_java_Request_getContentType(JNIEnv *env, jclass cls,
38     jlong req_ptr);
39 static jstring JNICALL nxt_java_Request_getLocalAddr(JNIEnv *env, jclass cls,
40     jlong req_ptr);
41 static jstring JNICALL nxt_java_Request_getLocalName(JNIEnv *env, jclass cls,
42     jlong req_ptr);
43 static jint JNICALL nxt_java_Request_getLocalPort(JNIEnv *env, jclass cls,
44     jlong req_ptr);
45 static jstring JNICALL nxt_java_Request_getProtocol(JNIEnv *env, jclass cls,
46     jlong req_ptr);
47 static jstring JNICALL nxt_java_Request_getRemoteAddr(JNIEnv *env, jclass cls,
48     jlong req_ptr);
49 static jstring JNICALL nxt_java_Request_getRemoteHost(JNIEnv *env, jclass cls,
50     jlong req_ptr);
51 static jint JNICALL nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls,
52     jlong req_ptr);
53 static jstring JNICALL nxt_java_Request_getScheme(JNIEnv *env, jclass cls,
54     jlong req_ptr);
55 static jstring JNICALL nxt_java_Request_getServerName(JNIEnv *env, jclass cls,
56     jlong req_ptr);
57 static jint JNICALL nxt_java_Request_getServerPort(JNIEnv *env, jclass cls,
58     jlong req_ptr);
59 static void JNICALL nxt_java_Request_log(JNIEnv *env, jclass cls,
60     jlong req_info_ptr, jstring msg, jint msg_len);
61 static void JNICALL nxt_java_Request_trace(JNIEnv *env, jclass cls,
62     jlong req_info_ptr, jstring msg, jint msg_len);
63 static jobject JNICALL nxt_java_Request_getResponse(JNIEnv *env, jclass cls,
64     jlong req_info_ptr);
65 
66 
67 static jclass     nxt_java_Request_class;
68 static jmethodID  nxt_java_Request_ctor;
69 
70 
71 int
72 nxt_java_initRequest(JNIEnv *env, jobject cl)
73 {
74     int     res;
75     jclass  cls;
76 
77     cls = nxt_java_loadClass(env, cl, "nginx.unit.Request");
78     if (cls == NULL) {
79         return NXT_UNIT_ERROR;
80     }
81 
82     nxt_java_Request_class = (*env)->NewGlobalRef(env, cls);
83     (*env)->DeleteLocalRef(env, cls);
84     cls = nxt_java_Request_class;
85 
86     nxt_java_Request_ctor = (*env)->GetMethodID(env, cls, "<init>", "(Lnginx/unit/Context;JJ)V");
87     if (nxt_java_Request_ctor == NULL) {
88         (*env)->DeleteGlobalRef(env, cls);
89         return NXT_UNIT_ERROR;
90     }
91 
92     JNINativeMethod request_methods[] = {
93         { (char *) "getHeader",
94           (char *) "(JLjava/lang/String;I)Ljava/lang/String;",
95           nxt_java_Request_getHeader },
96 
97         { (char *) "getHeaderNames",
98           (char *) "(J)Ljava/util/Enumeration;",
99           nxt_java_Request_getHeaderNames },
100 
101         { (char *) "getHeaders",
102           (char *) "(JLjava/lang/String;I)Ljava/util/Enumeration;",
103           nxt_java_Request_getHeaders },
104 
105         { (char *) "getIntHeader",
106           (char *) "(JLjava/lang/String;I)I",
107           nxt_java_Request_getIntHeader },
108 
109         { (char *) "getMethod",
110           (char *) "(J)Ljava/lang/String;",
111           nxt_java_Request_getMethod },
112 
113         { (char *) "getQueryString",
114           (char *) "(J)Ljava/lang/String;",
115           nxt_java_Request_getQueryString },
116 
117         { (char *) "getRequestURI",
118           (char *) "(J)Ljava/lang/String;",
119           nxt_java_Request_getRequestURI },
120 
121         { (char *) "getContentLength",
122           (char *) "(J)J",
123           nxt_java_Request_getContentLength },
124 
125         { (char *) "getContentType",
126           (char *) "(J)Ljava/lang/String;",
127           nxt_java_Request_getContentType },
128 
129         { (char *) "getLocalAddr",
130           (char *) "(J)Ljava/lang/String;",
131           nxt_java_Request_getLocalAddr },
132 
133         { (char *) "getLocalName",
134           (char *) "(J)Ljava/lang/String;",
135           nxt_java_Request_getLocalName },
136 
137         { (char *) "getLocalPort",
138           (char *) "(J)I",
139           nxt_java_Request_getLocalPort },
140 
141         { (char *) "getProtocol",
142           (char *) "(J)Ljava/lang/String;",
143           nxt_java_Request_getProtocol },
144 
145         { (char *) "getRemoteAddr",
146           (char *) "(J)Ljava/lang/String;",
147           nxt_java_Request_getRemoteAddr },
148 
149         { (char *) "getRemoteHost",
150           (char *) "(J)Ljava/lang/String;",
151           nxt_java_Request_getRemoteHost },
152 
153         { (char *) "getRemotePort",
154           (char *) "(J)I",
155           nxt_java_Request_getRemotePort },
156 
157         { (char *) "getScheme",
158           (char *) "(J)Ljava/lang/String;",
159           nxt_java_Request_getScheme },
160 
161         { (char *) "getServerName",
162           (char *) "(J)Ljava/lang/String;",
163           nxt_java_Request_getServerName },
164 
165         { (char *) "getServerPort",
166           (char *) "(J)I",
167           nxt_java_Request_getServerPort },
168 
169         { (char *) "log",
170           (char *) "(JLjava/lang/String;I)V",
171           nxt_java_Request_log },
172 
173         { (char *) "trace",
174           (char *) "(JLjava/lang/String;I)V",
175           nxt_java_Request_trace },
176 
177         { (char *) "getResponse",
178           (char *) "(J)Lnginx/unit/Response;",
179           nxt_java_Request_getResponse },
180 
181     };
182 
183     res = (*env)->RegisterNatives(env, nxt_java_Request_class,
184                                   request_methods,
185                                   sizeof(request_methods) / sizeof(request_methods[0]));
186 
187     nxt_unit_debug(NULL, "registered Request methods: %d", res);
188 
189     if (res != 0) {
190         nxt_unit_warn(NULL, "registering natives for Request failed");
191         goto failed;
192     }
193 
194     res = nxt_java_initHeadersEnumeration(env, cl);
195     if (res != NXT_UNIT_OK) {
196         goto failed;
197     }
198 
199     res = nxt_java_initHeaderNamesEnumeration(env, cl);
200     if (res != NXT_UNIT_OK) {
201         goto failed;
202     }
203 
204     return NXT_UNIT_OK;
205 
206 failed:
207 
208     (*env)->DeleteGlobalRef(env, cls);
209     return NXT_UNIT_ERROR;
210 }
211 
212 
213 jobject
214 nxt_java_newRequest(JNIEnv *env, jobject ctx, nxt_unit_request_info_t *req)
215 {
216     return (*env)->NewObject(env, nxt_java_Request_class,
217         nxt_java_Request_ctor, ctx, nxt_ptr2jlong(req),
218         nxt_ptr2jlong(req->request));
219 }
220 
221 
222 static jstring JNICALL
223 nxt_java_Request_getHeader(JNIEnv *env, jclass cls, jlong req_ptr,
224     jstring name, jint name_len)
225 {
226     const char          *name_str;
227     nxt_unit_field_t    *f;
228     nxt_unit_request_t  *r;
229 
230     name_str = (*env)->GetStringUTFChars(env, name, NULL);
231     if (name_str == NULL) {
232         return NULL;
233     }
234 
235     r = nxt_jlong2ptr(req_ptr);
236 
237     f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
238                             name_str, name_len);
239 
240     (*env)->ReleaseStringUTFChars(env, name, name_str);
241 
242     if (f == NULL) {
243         return NULL;
244     }
245 
246     return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&f->value));
247 }
248 
249 
250 static jobject JNICALL
251 nxt_java_Request_getHeaderNames(JNIEnv *env, jclass cls, jlong req_ptr)
252 {
253     nxt_unit_request_t  *r;
254 
255     r = nxt_jlong2ptr(req_ptr);
256 
257     return nxt_java_newHeaderNamesEnumeration(env, r->fields, r->fields_count);
258 }
259 
260 
261 static jobject JNICALL
262 nxt_java_Request_getHeaders(JNIEnv *env, jclass cls, jlong req_ptr,
263     jstring name, jint name_len)
264 {
265     const char          *name_str;
266     nxt_unit_field_t    *f;
267     nxt_unit_request_t  *r;
268 
269     name_str = (*env)->GetStringUTFChars(env, name, NULL);
270     if (name_str == NULL) {
271         return NULL;
272     }
273 
274     r = nxt_jlong2ptr(req_ptr);
275 
276     f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
277                             name_str, name_len);
278 
279     (*env)->ReleaseStringUTFChars(env, name, name_str);
280 
281     if (f == NULL) {
282         f = r->fields + r->fields_count;
283     }
284 
285     return nxt_java_newHeadersEnumeration(env, r->fields, r->fields_count,
286                                           f - r->fields);
287 }
288 
289 
290 static jint JNICALL
291 nxt_java_Request_getIntHeader(JNIEnv *env, jclass cls, jlong req_ptr,
292     jstring name, jint name_len)
293 {
294     jint                res;
295     char                *value, *end;
296     const char          *name_str;
297     nxt_unit_field_t    *f;
298     nxt_unit_request_t  *r;
299 
300     res = -1;
301 
302     name_str = (*env)->GetStringUTFChars(env, name, NULL);
303     if (name_str == NULL) {
304         return res;
305     }
306 
307     r = nxt_jlong2ptr(req_ptr);
308 
309     f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
310                             name_str, name_len);
311 
312     (*env)->ReleaseStringUTFChars(env, name, name_str);
313 
314     if (f == NULL) {
315         return res;
316     }
317 
318     value = nxt_unit_sptr_get(&f->value);
319     end = value + f->value_length;
320 
321     res = strtol(value, &end, 10);
322 
323     if (end < value + f->value_length) {
324         // TODO throw NumberFormatException.forInputString(value)
325     }
326 
327     return res;
328 }
329 
330 
331 static jstring JNICALL
332 nxt_java_Request_getMethod(JNIEnv *env, jclass cls, jlong req_ptr)
333 {
334     nxt_unit_request_t  *r;
335 
336     r = nxt_jlong2ptr(req_ptr);
337 
338     return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&r->method));
339 }
340 
341 
342 static jstring JNICALL
343 nxt_java_Request_getQueryString(JNIEnv *env, jclass cls, jlong req_ptr)
344 {
345     char                *query;
346     nxt_unit_request_t  *r;
347 
348     r = nxt_jlong2ptr(req_ptr);
349 
350     if (r->query.offset != 0) {
351         query = nxt_unit_sptr_get(&r->query);
352         return (*env)->NewStringUTF(env, query);
353     }
354 
355     return NULL;
356 }
357 
358 
359 static jstring JNICALL
360 nxt_java_Request_getRequestURI(JNIEnv *env, jclass cls, jlong req_ptr)
361 {
362     char                *target, *query;
363     nxt_unit_request_t  *r;
364 
365     r = nxt_jlong2ptr(req_ptr);
366 
367     target = nxt_unit_sptr_get(&r->target);
368 
369     if (r->query.offset != 0) {
370         query = nxt_unit_sptr_get(&r->query);
371         return nxt_java_newString(env, target, query - target - 1);
372     }
373 
374     return (*env)->NewStringUTF(env, target);
375 }
376 
377 
378 static jlong JNICALL
379 nxt_java_Request_getContentLength(JNIEnv *env, jclass cls, jlong req_ptr)
380 {
381     nxt_unit_request_t  *r;
382 
383     r = nxt_jlong2ptr(req_ptr);
384 
385     return r->content_length;
386 }
387 
388 
389 static jstring JNICALL
390 nxt_java_Request_getContentType(JNIEnv *env, jclass cls, jlong req_ptr)
391 {
392     nxt_unit_field_t    *f;
393     nxt_unit_request_t  *r;
394 
395     r = nxt_jlong2ptr(req_ptr);
396 
397     if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
398         f = r->fields + r->content_type_field;
399 
400         return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&f->value));
401     }
402 
403     return NULL;
404 }
405 
406 
407 static jstring JNICALL
408 nxt_java_Request_getLocalAddr(JNIEnv *env, jclass cls, jlong req_ptr)
409 {
410     nxt_unit_request_t  *r;
411 
412     r = nxt_jlong2ptr(req_ptr);
413 
414     return nxt_java_newString(env, nxt_unit_sptr_get(&r->local),
415                               r->local_length);
416 }
417 
418 
419 static jstring JNICALL
420 nxt_java_Request_getLocalName(JNIEnv *env, jclass cls, jlong req_ptr)
421 {
422     char                *local, *colon;
423     nxt_unit_request_t  *r;
424 
425     r = nxt_jlong2ptr(req_ptr);
426 
427     local = nxt_unit_sptr_get(&r->local);
428     colon = memchr(local, ':', r->local_length);
429 
430     if (colon == NULL) {
431         colon = local + r->local_length;
432     }
433 
434     return nxt_java_newString(env, local, colon - local);
435 }
436 
437 
438 static jint JNICALL
439 nxt_java_Request_getLocalPort(JNIEnv *env, jclass cls, jlong req_ptr)
440 {
441     jint                res;
442     char                *local, *colon, tmp;
443     nxt_unit_request_t  *r;
444 
445     r = nxt_jlong2ptr(req_ptr);
446 
447     local = nxt_unit_sptr_get(&r->local);
448     colon = memchr(local, ':', r->local_length);
449 
450     if (colon == NULL) {
451         return 80;
452     }
453 
454     tmp = local[r->local_length];
455 
456     local[r->local_length] = '\0';
457 
458     res = strtol(colon + 1, NULL, 10);
459 
460     local[r->local_length] = tmp;
461 
462     return res;
463 }
464 
465 
466 static jstring JNICALL
467 nxt_java_Request_getProtocol(JNIEnv *env, jclass cls, jlong req_ptr)
468 {
469     nxt_unit_request_t  *r;
470 
471     r = nxt_jlong2ptr(req_ptr);
472 
473     return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&r->version));
474 }
475 
476 
477 static jstring JNICALL
478 nxt_java_Request_getRemoteAddr(JNIEnv *env, jclass cls, jlong req_ptr)
479 {
480     nxt_unit_request_t  *r;
481 
482     r = nxt_jlong2ptr(req_ptr);
483 
484     return nxt_java_newString(env, nxt_unit_sptr_get(&r->remote),
485                               r->remote_length);
486 }
487 
488 
489 static jstring JNICALL
490 nxt_java_Request_getRemoteHost(JNIEnv *env, jclass cls, jlong req_ptr)
491 {
492     char                *remote, *colon;
493     nxt_unit_request_t  *r;
494 
495     r = nxt_jlong2ptr(req_ptr);
496 
497     remote = nxt_unit_sptr_get(&r->remote);
498     colon = memchr(remote, ':', r->remote_length);
499 
500     if (colon == NULL) {
501         colon = remote + r->remote_length;
502     }
503 
504     return nxt_java_newString(env, remote, colon - remote);
505 }
506 
507 
508 static jint JNICALL
509 nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls, jlong req_ptr)
510 {
511     jint                res;
512     char                *remote, *colon, tmp;
513     nxt_unit_request_t  *r;
514 
515     r = nxt_jlong2ptr(req_ptr);
516 
517     remote = nxt_unit_sptr_get(&r->remote);
518     colon = memchr(remote, ':', r->remote_length);
519 
520     if (colon == NULL) {
521         return 80;
522     }
523 
524     tmp = remote[r->remote_length];
525 
526     remote[r->remote_length] = '\0';
527 
528     res = strtol(colon + 1, NULL, 10);
529 
530     remote[r->remote_length] = tmp;
531 
532     return res;
533 }
534 
535 
536 static jstring JNICALL
537 nxt_java_Request_getScheme(JNIEnv *env, jclass cls, jlong req_ptr)
538 {
539     return (*env)->NewStringUTF(env, "http");
540 }
541 
542 
543 static jstring JNICALL
544 nxt_java_Request_getServerName(JNIEnv *env, jclass cls, jlong req_ptr)
545 {
546     char                *host, *colon;
547     nxt_unit_field_t    *f;
548     nxt_unit_request_t  *r;
549 
550     r = nxt_jlong2ptr(req_ptr);
551 
552     f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
553                             "Host", 4);
554     if (f != NULL) {
555         host = nxt_unit_sptr_get(&f->value);
556 
557         colon = memchr(host, ':', f->value_length);
558 
559         if (colon == NULL) {
560             colon = host + f->value_length;
561         }
562 
563         return nxt_java_newString(env, host, colon - host);
564     }
565 
566     return nxt_java_Request_getLocalName(env, cls, req_ptr);
567 }
568 
569 
570 static jint JNICALL
571 nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, jlong req_ptr)
572 {
573     jint                res;
574     char                *host, *colon, tmp;
575     nxt_unit_field_t    *f;
576     nxt_unit_request_t  *r;
577 
578     r = nxt_jlong2ptr(req_ptr);
579 
580     f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
581                             "Host", 4);
582     if (f != NULL) {
583         host = nxt_unit_sptr_get(&f->value);
584 
585         colon = memchr(host, ':', f->value_length);
586 
587         if (colon == NULL) {
588             return 80;
589         }
590 
591         tmp = host[f->value_length];
592 
593         host[f->value_length] = '\0';
594 
595         res = strtol(colon + 1, NULL, 10);
596 
597         host[f->value_length] = tmp;
598 
599         return res;
600     }
601 
602     return nxt_java_Request_getLocalPort(env, cls, req_ptr);
603 }
604 
605 
606 static void JNICALL
607 nxt_java_Request_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg,
608     jint msg_len)
609 {
610     const char               *msg_str;
611     nxt_unit_request_info_t  *req;
612 
613     req = nxt_jlong2ptr(req_info_ptr);
614 
615     msg_str = (*env)->GetStringUTFChars(env, msg, NULL);
616     if (msg_str == NULL) {
617         return;
618     }
619 
620     nxt_unit_req_log(req, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str);
621 
622     (*env)->ReleaseStringUTFChars(env, msg, msg_str);
623 }
624 
625 
626 static void JNICALL
627 nxt_java_Request_trace(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg,
628     jint msg_len)
629 {
630 #if (NXT_DEBUG)
631     const char               *msg_str;
632     nxt_unit_request_info_t  *req;
633 
634     req = nxt_jlong2ptr(req_info_ptr);
635 
636     msg_str = (*env)->GetStringUTFChars(env, msg, NULL);
637     if (msg_str == NULL) {
638         return;
639     }
640 
641     nxt_unit_req_debug(req, "%.*s", msg_len, msg_str);
642 
643     (*env)->ReleaseStringUTFChars(env, msg, msg_str);
644 #endif
645 }
646 
647 
648 static jobject JNICALL
649 nxt_java_Request_getResponse(JNIEnv *env, jclass cls, jlong req_info_ptr)
650 {
651     nxt_unit_request_info_t  *req;
652     nxt_java_request_data_t  *data;
653 
654     req = nxt_jlong2ptr(req_info_ptr);
655     data = req->data;
656 
657     return data->jresp;
658 }
659