1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #include <nxt_router.h>
8 #include <nxt_http.h>
9
10
11 static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
12 static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
13 static nxt_int_t nxt_http_request_forward(nxt_task_t *task,
14 nxt_http_request_t *r, nxt_http_forward_t *forward);
15 static void nxt_http_request_forward_client_ip(nxt_http_request_t *r,
16 nxt_http_forward_t *forward, nxt_array_t *fields);
17 static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr(
18 nxt_http_request_t *r, u_char *start, size_t len);
19 static void nxt_http_request_forward_protocol(nxt_http_request_t *r,
20 nxt_http_field_t *field);
21 static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data);
22 static void nxt_http_request_proto_info(nxt_task_t *task,
23 nxt_http_request_t *r);
24 static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
25 void *data);
26 static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
27 static nxt_int_t nxt_http_request_access_log(nxt_task_t *task,
28 nxt_http_request_t *r, nxt_router_conf_t *rtcf);
29
30 static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now,
31 struct tm *tm, size_t size, const char *format);
32
33 static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array,
34 u_char *name, size_t name_length, uint32_t hash, u_char *start,
35 const u_char *end);
36 static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start,
37 const u_char *end);
38 static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name,
39 size_t name_length, u_char *start, const u_char *end);
40
41
42 #define NXT_HTTP_COOKIE_HASH \
43 (nxt_http_field_hash_end( \
44 nxt_http_field_hash_char( \
45 nxt_http_field_hash_char( \
46 nxt_http_field_hash_char( \
47 nxt_http_field_hash_char( \
48 nxt_http_field_hash_char( \
49 nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \
50 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
51
52
53 static const nxt_http_request_state_t nxt_http_request_init_state;
54 static const nxt_http_request_state_t nxt_http_request_body_state;
55
56
57 nxt_time_string_t nxt_http_date_cache = {
58 (nxt_atomic_uint_t) -1,
59 nxt_http_date_cache_handler,
60 NULL,
61 NXT_HTTP_DATE_LEN,
62 NXT_THREAD_TIME_GMT,
63 NXT_THREAD_TIME_SEC,
64 };
65
66
67 nxt_int_t
nxt_http_init(nxt_task_t * task)68 nxt_http_init(nxt_task_t *task)
69 {
70 nxt_int_t ret;
71
72 ret = nxt_h1p_init(task);
73
74 if (ret != NXT_OK) {
75 return ret;
76 }
77
78 return nxt_http_response_hash_init(task);
79 }
80
81
82 nxt_int_t
nxt_http_request_host(void * ctx,nxt_http_field_t * field,uintptr_t data)83 nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data)
84 {
85 nxt_int_t ret;
86 nxt_str_t host;
87 nxt_http_request_t *r;
88
89 r = ctx;
90
91 if (nxt_slow_path(r->host.start != NULL)) {
92 return NXT_HTTP_BAD_REQUEST;
93 }
94
95 host.length = field->value_length;
96 host.start = field->value;
97
98 ret = nxt_http_validate_host(&host, r->mem_pool);
99
100 if (nxt_fast_path(ret == NXT_OK)) {
101 r->host = host;
102 }
103
104 return ret;
105 }
106
107
108 static nxt_int_t
nxt_http_validate_host(nxt_str_t * host,nxt_mp_t * mp)109 nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp)
110 {
111 u_char *h, ch;
112 size_t i, dot_pos, host_length;
113 nxt_bool_t lowcase;
114
115 enum {
116 sw_usual,
117 sw_literal,
118 sw_rest
119 } state;
120
121 dot_pos = host->length;
122 host_length = host->length;
123
124 h = host->start;
125
126 lowcase = 0;
127 state = sw_usual;
128
129 for (i = 0; i < host->length; i++) {
130 ch = h[i];
131
132 if (ch > ']') {
133 /* Short path. */
134 continue;
135 }
136
137 switch (ch) {
138
139 case '.':
140 if (dot_pos == i - 1) {
141 return NXT_HTTP_BAD_REQUEST;
142 }
143
144 dot_pos = i;
145 break;
146
147 case ':':
148 if (state == sw_usual) {
149 host_length = i;
150 state = sw_rest;
151 }
152
153 break;
154
155 case '[':
156 if (i == 0) {
157 state = sw_literal;
158 }
159
160 break;
161
162 case ']':
163 if (state == sw_literal) {
164 host_length = i + 1;
165 state = sw_rest;
166 }
167
168 break;
169
170 case '/':
171 return NXT_HTTP_BAD_REQUEST;
172
173 default:
174 if (ch >= 'A' && ch <= 'Z') {
175 lowcase = 1;
176 }
177
178 break;
179 }
180 }
181
182 if (dot_pos == host_length - 1) {
183 host_length--;
184 }
185
186 host->length = host_length;
187
188 if (lowcase) {
189 host->start = nxt_mp_nget(mp, host_length);
190 if (nxt_slow_path(host->start == NULL)) {
191 return NXT_HTTP_INTERNAL_SERVER_ERROR;
192 }
193
194 nxt_memcpy_lowcase(host->start, h, host_length);
195 }
196
197 return NXT_OK;
198 }
199
200
201 nxt_int_t
nxt_http_request_field(void * ctx,nxt_http_field_t * field,uintptr_t offset)202 nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset)
203 {
204 nxt_http_request_t *r;
205
206 r = ctx;
207
208 nxt_value_at(nxt_http_field_t *, r, offset) = field;
209
210 return NXT_OK;
211 }
212
213
214 nxt_int_t
nxt_http_request_content_length(void * ctx,nxt_http_field_t * field,uintptr_t data)215 nxt_http_request_content_length(void *ctx, nxt_http_field_t *field,
216 uintptr_t data)
217 {
218 nxt_off_t n, max_body_size;
219 nxt_http_request_t *r;
220
221 r = ctx;
222
223 if (nxt_fast_path(r->content_length == NULL)) {
224 r->content_length = field;
225
226 n = nxt_off_t_parse(field->value, field->value_length);
227
228 if (nxt_fast_path(n >= 0)) {
229 r->content_length_n = n;
230
231 max_body_size = r->conf->socket_conf->max_body_size;
232
233 if (nxt_slow_path(n > max_body_size)) {
234 return NXT_HTTP_PAYLOAD_TOO_LARGE;
235 }
236
237 return NXT_OK;
238 }
239 }
240
241 return NXT_HTTP_BAD_REQUEST;
242 }
243
244
245 nxt_http_request_t *
nxt_http_request_create(nxt_task_t * task)246 nxt_http_request_create(nxt_task_t *task)
247 {
248 nxt_mp_t *mp;
249 nxt_buf_t *last;
250 nxt_http_request_t *r;
251
252 mp = nxt_mp_create(4096, 128, 512, 32);
253 if (nxt_slow_path(mp == NULL)) {
254 return NULL;
255 }
256
257 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t));
258 if (nxt_slow_path(r == NULL)) {
259 goto fail;
260 }
261
262 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
263 if (nxt_slow_path(r->resp.fields == NULL)) {
264 goto fail;
265 }
266
267 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE);
268 if (nxt_slow_path(last == NULL)) {
269 goto fail;
270 }
271
272 nxt_buf_set_sync(last);
273 nxt_buf_set_last(last);
274 last->completion_handler = nxt_http_request_done;
275 last->parent = r;
276 r->last = last;
277
278 r->mem_pool = mp;
279 r->content_length_n = -1;
280 r->resp.content_length_n = -1;
281 r->state = &nxt_http_request_init_state;
282
283 r->start_time = nxt_thread_monotonic_time(task->thread);
284
285 task->thread->engine->requests_cnt++;
286
287 r->tstr_cache.var.pool = mp;
288
289 return r;
290
291 fail:
292
293 nxt_mp_release(mp);
294
295 return NULL;
296 }
297
298
299 static const nxt_http_request_state_t nxt_http_request_init_state
300 nxt_aligned(64) =
301 {
302 .ready_handler = nxt_http_request_start,
303 .error_handler = nxt_http_request_close_handler,
304 };
305
306
307 static void
nxt_http_request_start(nxt_task_t * task,void * obj,void * data)308 nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
309 {
310 nxt_int_t ret;
311 nxt_socket_conf_t *skcf;
312 nxt_http_request_t *r;
313
314 r = obj;
315
316 r->state = &nxt_http_request_body_state;
317
318 skcf = r->conf->socket_conf;
319
320 if (skcf->forwarded != NULL) {
321 ret = nxt_http_request_forward(task, r, skcf->forwarded);
322 if (nxt_slow_path(ret != NXT_OK)) {
323 goto fail;
324 }
325 }
326
327 if (skcf->client_ip != NULL) {
328 ret = nxt_http_request_forward(task, r, skcf->client_ip);
329 if (nxt_slow_path(ret != NXT_OK)) {
330 goto fail;
331 }
332 }
333
334 nxt_http_request_read_body(task, r);
335
336 return;
337
338 fail:
339 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
340 }
341
342
343 static nxt_int_t
nxt_http_request_forward(nxt_task_t * task,nxt_http_request_t * r,nxt_http_forward_t * forward)344 nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r,
345 nxt_http_forward_t *forward)
346 {
347 nxt_int_t ret;
348 nxt_array_t *client_ip_fields;
349 nxt_http_field_t *f, **fields, *protocol_field;
350 nxt_http_forward_header_t *client_ip, *protocol;
351
352 ret = nxt_http_route_addr_rule(r, forward->source, r->remote);
353 if (ret <= 0) {
354 return NXT_OK;
355 }
356
357 client_ip = &forward->client_ip;
358 protocol = &forward->protocol;
359
360 if (client_ip->header != NULL) {
361 client_ip_fields = nxt_array_create(r->mem_pool, 1,
362 sizeof(nxt_http_field_t *));
363 if (nxt_slow_path(client_ip_fields == NULL)) {
364 return NXT_ERROR;
365 }
366
367 } else {
368 client_ip_fields = NULL;
369 }
370
371 protocol_field = NULL;
372
373 nxt_list_each(f, r->fields) {
374 if (client_ip_fields != NULL
375 && f->hash == client_ip->header_hash
376 && f->value_length > 0
377 && f->name_length == client_ip->header->length
378 && nxt_memcasecmp(f->name, client_ip->header->start,
379 client_ip->header->length) == 0)
380 {
381 fields = nxt_array_add(client_ip_fields);
382 if (nxt_slow_path(fields == NULL)) {
383 return NXT_ERROR;
384 }
385
386 *fields = f;
387 }
388
389 if (protocol->header != NULL
390 && protocol_field == NULL
391 && f->hash == protocol->header_hash
392 && f->value_length > 0
393 && f->name_length == protocol->header->length
394 && nxt_memcasecmp(f->name, protocol->header->start,
395 protocol->header->length) == 0)
396 {
397 protocol_field = f;
398 }
399 } nxt_list_loop;
400
401 if (client_ip_fields != NULL) {
402 nxt_http_request_forward_client_ip(r, forward, client_ip_fields);
403 }
404
405 if (protocol_field != NULL) {
406 nxt_http_request_forward_protocol(r, protocol_field);
407 }
408
409 return NXT_OK;
410 }
411
412
413 static void
nxt_http_request_forward_client_ip(nxt_http_request_t * r,nxt_http_forward_t * forward,nxt_array_t * fields)414 nxt_http_request_forward_client_ip(nxt_http_request_t *r,
415 nxt_http_forward_t *forward, nxt_array_t *fields)
416 {
417 u_char *start, *p;
418 nxt_int_t ret, i, len;
419 nxt_sockaddr_t *sa, *prev_sa;
420 nxt_http_field_t **f;
421
422 prev_sa = r->remote;
423 f = (nxt_http_field_t **) fields->elts;
424
425 i = fields->nelts;
426
427 while (i-- > 0) {
428 start = f[i]->value;
429 len = f[i]->value_length;
430
431 do {
432 for (p = start + len - 1; p > start; p--, len--) {
433 if (*p != ' ' && *p != ',') {
434 break;
435 }
436 }
437
438 for (/* void */; p > start; p--) {
439 if (*p == ' ' || *p == ',') {
440 p++;
441 break;
442 }
443 }
444
445 sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start));
446 if (nxt_slow_path(sa == NULL)) {
447 if (prev_sa != NULL) {
448 r->remote = prev_sa;
449 }
450
451 return;
452 }
453
454 if (!forward->recursive) {
455 r->remote = sa;
456 return;
457 }
458
459 ret = nxt_http_route_addr_rule(r, forward->source, sa);
460 if (ret <= 0 || (i == 0 && p == start)) {
461 r->remote = sa;
462 return;
463 }
464
465 prev_sa = sa;
466 len = p - 1 - start;
467
468 } while (len > 0);
469 }
470 }
471
472
473 static nxt_sockaddr_t *
nxt_http_request_client_ip_sockaddr(nxt_http_request_t * r,u_char * start,size_t len)474 nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start,
475 size_t len)
476 {
477 nxt_str_t addr;
478 nxt_sockaddr_t *sa;
479
480 addr.start = start;
481 addr.length = len;
482
483 sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr);
484 if (nxt_slow_path(sa == NULL)) {
485 return NULL;
486 }
487
488 switch (sa->u.sockaddr.sa_family) {
489 case AF_INET:
490 if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) {
491 return NULL;
492 }
493
494 break;
495
496 #if (NXT_INET6)
497 case AF_INET6:
498 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) {
499 return NULL;
500 }
501
502 break;
503 #endif /* NXT_INET6 */
504
505 default:
506 return NULL;
507 }
508
509 return sa;
510 }
511
512
513 static void
nxt_http_request_forward_protocol(nxt_http_request_t * r,nxt_http_field_t * field)514 nxt_http_request_forward_protocol(nxt_http_request_t *r,
515 nxt_http_field_t *field)
516 {
517 if (field->value_length == 4) {
518 if (nxt_memcasecmp(field->value, "http", 4) == 0) {
519 r->tls = 0;
520 }
521
522 } else if (field->value_length == 5) {
523 if (nxt_memcasecmp(field->value, "https", 5) == 0) {
524 r->tls = 1;
525 }
526
527 } else if (field->value_length == 2) {
528 if (nxt_memcasecmp(field->value, "on", 2) == 0) {
529 r->tls = 1;
530 }
531 }
532 }
533
534
535 static const nxt_http_request_state_t nxt_http_request_body_state
536 nxt_aligned(64) =
537 {
538 .ready_handler = nxt_http_request_ready,
539 .error_handler = nxt_http_request_close_handler,
540 };
541
542
543 static void
nxt_http_request_ready(nxt_task_t * task,void * obj,void * data)544 nxt_http_request_ready(nxt_task_t *task, void *obj, void *data)
545 {
546 nxt_http_action_t *action;
547 nxt_http_request_t *r;
548
549 r = obj;
550 action = r->conf->socket_conf->action;
551
552 nxt_http_request_action(task, r, action);
553 }
554
555
556 void
nxt_http_request_action(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)557 nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
558 nxt_http_action_t *action)
559 {
560 nxt_int_t ret;
561
562 if (nxt_fast_path(action != NULL)) {
563
564 do {
565 ret = nxt_http_rewrite(task, r);
566 if (nxt_slow_path(ret != NXT_OK)) {
567 break;
568 }
569
570 action = action->handler(task, r, action);
571
572 if (action == NULL) {
573 return;
574 }
575
576 if (action == NXT_HTTP_ACTION_ERROR) {
577 break;
578 }
579
580 } while (r->pass_count++ < 255);
581 }
582
583 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
584 }
585
586
587 nxt_http_action_t *
nxt_http_application_handler(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)588 nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r,
589 nxt_http_action_t *action)
590 {
591 nxt_debug(task, "http application handler");
592
593 /*
594 * TODO: need an application flag to get local address
595 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go.
596 */
597 nxt_http_request_proto_info(task, r);
598
599 if (r->host.length != 0) {
600 r->server_name = r->host;
601
602 } else {
603 nxt_str_set(&r->server_name, "localhost");
604 }
605
606 nxt_router_process_http_request(task, r, action);
607
608 return NULL;
609 }
610
611
612 static void
nxt_http_request_proto_info(nxt_task_t * task,nxt_http_request_t * r)613 nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r)
614 {
615 if (nxt_fast_path(r->proto.any != NULL)) {
616 nxt_http_proto[r->protocol].local_addr(task, r);
617 }
618 }
619
620
621 void
nxt_http_request_read_body(nxt_task_t * task,nxt_http_request_t * r)622 nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r)
623 {
624 if (nxt_fast_path(r->proto.any != NULL)) {
625 nxt_http_proto[r->protocol].body_read(task, r);
626 }
627 }
628
629
630 void
nxt_http_request_header_send(nxt_task_t * task,nxt_http_request_t * r,nxt_work_handler_t body_handler,void * data)631 nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r,
632 nxt_work_handler_t body_handler, void *data)
633 {
634 u_char *p, *end, *server_string;
635 nxt_int_t ret;
636 nxt_http_field_t *server, *date, *content_length;
637 nxt_socket_conf_t *skcf;
638
639 ret = nxt_http_set_headers(r);
640 if (nxt_slow_path(ret != NXT_OK)) {
641 goto fail;
642 }
643
644 /*
645 * TODO: "Server", "Date", and "Content-Length" processing should be moved
646 * to the last header filter.
647 */
648
649 server = nxt_list_zero_add(r->resp.fields);
650 if (nxt_slow_path(server == NULL)) {
651 goto fail;
652 }
653
654 skcf = r->conf->socket_conf;
655 server_string = (u_char *) (skcf->server_version ? NXT_SERVER : NXT_NAME);
656
657 nxt_http_field_name_set(server, "Server");
658 server->value = server_string;
659 server->value_length = nxt_strlen(server_string);
660
661 if (r->resp.date == NULL) {
662 date = nxt_list_zero_add(r->resp.fields);
663 if (nxt_slow_path(date == NULL)) {
664 goto fail;
665 }
666
667 nxt_http_field_name_set(date, "Date");
668
669 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size);
670 if (nxt_slow_path(p == NULL)) {
671 goto fail;
672 }
673
674 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p);
675
676 date->value = p;
677 date->value_length = nxt_http_date_cache.size;
678
679 r->resp.date = date;
680 }
681
682 if (r->resp.content_length_n != -1
683 && (r->resp.content_length == NULL || r->resp.content_length->skip))
684 {
685 content_length = nxt_list_zero_add(r->resp.fields);
686 if (nxt_slow_path(content_length == NULL)) {
687 goto fail;
688 }
689
690 nxt_http_field_name_set(content_length, "Content-Length");
691
692 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
693 if (nxt_slow_path(p == NULL)) {
694 goto fail;
695 }
696
697 content_length->value = p;
698 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n);
699 content_length->value_length = end - p;
700
701 r->resp.content_length = content_length;
702 }
703
704 if (nxt_fast_path(r->proto.any != NULL)) {
705 nxt_http_proto[r->protocol].header_send(task, r, body_handler, data);
706 }
707
708 return;
709
710 fail:
711
712 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
713 }
714
715
716 void
nxt_http_request_ws_frame_start(nxt_task_t * task,nxt_http_request_t * r,nxt_buf_t * ws_frame)717 nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r,
718 nxt_buf_t *ws_frame)
719 {
720 if (r->proto.any != NULL) {
721 nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame);
722 }
723 }
724
725
726 void
nxt_http_request_send(nxt_task_t * task,nxt_http_request_t * r,nxt_buf_t * out)727 nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
728 {
729 if (nxt_fast_path(r->proto.any != NULL)) {
730 nxt_http_proto[r->protocol].send(task, r, out);
731 }
732 }
733
734
735 nxt_buf_t *
nxt_http_buf_mem(nxt_task_t * task,nxt_http_request_t * r,size_t size)736 nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size)
737 {
738 nxt_buf_t *b;
739
740 b = nxt_buf_mem_alloc(r->mem_pool, size, 0);
741 if (nxt_fast_path(b != NULL)) {
742 b->completion_handler = nxt_http_request_mem_buf_completion;
743 b->parent = r;
744 nxt_mp_retain(r->mem_pool);
745
746 } else {
747 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
748 }
749
750 return b;
751 }
752
753
754 static void
nxt_http_request_mem_buf_completion(nxt_task_t * task,void * obj,void * data)755 nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data)
756 {
757 nxt_buf_t *b, *next;
758 nxt_http_request_t *r;
759
760 b = obj;
761 r = data;
762
763 do {
764 next = b->next;
765
766 nxt_mp_free(r->mem_pool, b);
767 nxt_mp_release(r->mem_pool);
768
769 b = next;
770 } while (b != NULL);
771 }
772
773
774 nxt_buf_t *
nxt_http_buf_last(nxt_http_request_t * r)775 nxt_http_buf_last(nxt_http_request_t *r)
776 {
777 nxt_buf_t *last;
778
779 last = r->last;
780 r->last = NULL;
781
782 return last;
783 }
784
785
786 static void
nxt_http_request_done(nxt_task_t * task,void * obj,void * data)787 nxt_http_request_done(nxt_task_t *task, void *obj, void *data)
788 {
789 nxt_http_request_t *r;
790
791 r = data;
792
793 nxt_debug(task, "http request done");
794
795 nxt_http_request_close_handler(task, r, r->proto.any);
796 }
797
798
799 void
nxt_http_request_error_handler(nxt_task_t * task,void * obj,void * data)800 nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
801 {
802 nxt_http_proto_t proto;
803 nxt_http_request_t *r;
804
805 r = obj;
806 proto.any = data;
807
808 nxt_debug(task, "http request error handler");
809
810 r->error = 1;
811
812 if (nxt_fast_path(proto.any != NULL)) {
813 nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r));
814 }
815 }
816
817
818 void
nxt_http_request_close_handler(nxt_task_t * task,void * obj,void * data)819 nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
820 {
821 nxt_int_t ret;
822 nxt_http_proto_t proto;
823 nxt_router_conf_t *rtcf;
824 nxt_http_request_t *r;
825 nxt_http_protocol_t protocol;
826 nxt_socket_conf_joint_t *conf;
827
828 r = obj;
829 proto.any = data;
830
831 conf = r->conf;
832 rtcf = conf->socket_conf->router_conf;
833
834 if (!r->logged) {
835 r->logged = 1;
836
837 if (rtcf->access_log != NULL) {
838 ret = nxt_http_request_access_log(task, r, rtcf);
839 if (ret == NXT_OK) {
840 return;
841 }
842 }
843 }
844
845 nxt_debug(task, "http request close handler");
846
847 r->proto.any = NULL;
848
849 if (r->body != NULL && nxt_buf_is_file(r->body)
850 && r->body->file->fd != -1)
851 {
852 nxt_fd_close(r->body->file->fd);
853
854 r->body->file->fd = -1;
855 }
856
857 if (r->tstr_query != NULL) {
858 nxt_tstr_query_release(r->tstr_query);
859 }
860
861 if (nxt_fast_path(proto.any != NULL)) {
862 protocol = r->protocol;
863
864 nxt_http_proto[protocol].close(task, proto, conf);
865
866 nxt_mp_release(r->mem_pool);
867 }
868 }
869
870
871 static nxt_int_t
nxt_http_request_access_log(nxt_task_t * task,nxt_http_request_t * r,nxt_router_conf_t * rtcf)872 nxt_http_request_access_log(nxt_task_t *task, nxt_http_request_t *r,
873 nxt_router_conf_t *rtcf)
874 {
875 nxt_int_t ret;
876 nxt_str_t str;
877 nxt_bool_t expr;
878 nxt_router_access_log_t *access_log;
879
880 access_log = rtcf->access_log;
881
882 expr = 1;
883
884 if (rtcf->log_expr != NULL) {
885
886 if (nxt_tstr_is_const(rtcf->log_expr)) {
887 nxt_tstr_str(rtcf->log_expr, &str);
888
889 } else {
890 ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
891 &r->tstr_cache, r, r->mem_pool);
892 if (nxt_slow_path(ret != NXT_OK)) {
893 return NXT_DECLINED;
894 }
895
896 nxt_tstr_query(task, r->tstr_query, rtcf->log_expr, &str);
897
898 if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) {
899 return NXT_DECLINED;
900 }
901 }
902
903 if (str.length == 0
904 || nxt_str_eq(&str, "0", 1)
905 || nxt_str_eq(&str, "false", 5)
906 || nxt_str_eq(&str, "null", 4)
907 || nxt_str_eq(&str, "undefined", 9))
908 {
909 expr = 0;
910 }
911 }
912
913 if (rtcf->log_negate ^ expr) {
914 access_log->handler(task, r, access_log, rtcf->log_format);
915 return NXT_OK;
916 }
917
918 return NXT_DECLINED;
919 }
920
921
922 static u_char *
nxt_http_date_cache_handler(u_char * buf,nxt_realtime_t * now,struct tm * tm,size_t size,const char * format)923 nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm,
924 size_t size, const char *format)
925 {
926 return nxt_http_date(buf, tm);
927 }
928
929
930 nxt_array_t *
nxt_http_arguments_parse(nxt_http_request_t * r)931 nxt_http_arguments_parse(nxt_http_request_t *r)
932 {
933 size_t name_length;
934 u_char *p, *dst, *dst_start, *start, *end, *name;
935 uint8_t d0, d1;
936 uint32_t hash;
937 nxt_array_t *args;
938 nxt_http_name_value_t *nv;
939
940 if (r->arguments != NULL) {
941 return r->arguments;
942 }
943
944 args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
945 if (nxt_slow_path(args == NULL)) {
946 return NULL;
947 }
948
949 hash = NXT_HTTP_FIELD_HASH_INIT;
950 name = NULL;
951 name_length = 0;
952
953 dst_start = nxt_mp_nget(r->mem_pool, r->args->length);
954 if (nxt_slow_path(dst_start == NULL)) {
955 return NULL;
956 }
957
958 r->args_decoded.start = dst_start;
959
960 start = r->args->start;
961 end = start + r->args->length;
962
963 for (p = start, dst = dst_start; p < end; p++, dst++) {
964 *dst = *p;
965
966 switch (*p) {
967 case '=':
968 if (name == NULL) {
969 name_length = dst - dst_start;
970 name = dst_start;
971 dst_start = dst + 1;
972 }
973
974 continue;
975
976 case '&':
977 if (name_length != 0 || dst != dst_start) {
978 nv = nxt_http_argument(args, name, name_length, hash, dst_start,
979 dst);
980 if (nxt_slow_path(nv == NULL)) {
981 return NULL;
982 }
983 }
984
985 hash = NXT_HTTP_FIELD_HASH_INIT;
986 name_length = 0;
987 name = NULL;
988 dst_start = dst + 1;
989
990 continue;
991
992 case '+':
993 *dst = ' ';
994
995 break;
996
997 case '%':
998 if (nxt_slow_path(end - p <= 2)) {
999 break;
1000 }
1001
1002 d0 = nxt_hex2int[p[1]];
1003 d1 = nxt_hex2int[p[2]];
1004
1005 if (nxt_slow_path((d0 | d1) >= 16)) {
1006 break;
1007 }
1008
1009 p += 2;
1010 *dst = (d0 << 4) + d1;
1011
1012 break;
1013 }
1014
1015 if (name == NULL) {
1016 hash = nxt_http_field_hash_char(hash, *dst);
1017 }
1018 }
1019
1020 r->args_decoded.length = dst - r->args_decoded.start;
1021
1022 if (name_length != 0 || dst != dst_start) {
1023 nv = nxt_http_argument(args, name, name_length, hash, dst_start, dst);
1024 if (nxt_slow_path(nv == NULL)) {
1025 return NULL;
1026 }
1027 }
1028
1029 r->arguments = args;
1030
1031 return args;
1032 }
1033
1034
1035 static nxt_http_name_value_t *
nxt_http_argument(nxt_array_t * array,u_char * name,size_t name_length,uint32_t hash,u_char * start,const u_char * end)1036 nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length,
1037 uint32_t hash, u_char *start, const u_char *end)
1038 {
1039 size_t length;
1040 nxt_http_name_value_t *nv;
1041
1042 nv = nxt_array_add(array);
1043 if (nxt_slow_path(nv == NULL)) {
1044 return NULL;
1045 }
1046
1047 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
1048
1049 length = end - start;
1050
1051 if (name == NULL) {
1052 name_length = length;
1053 name = start;
1054 length = 0;
1055 }
1056
1057 nv->name_length = name_length;
1058 nv->value_length = length;
1059 nv->name = name;
1060 nv->value = start;
1061
1062 return nv;
1063 }
1064
1065
1066 nxt_array_t *
nxt_http_cookies_parse(nxt_http_request_t * r)1067 nxt_http_cookies_parse(nxt_http_request_t *r)
1068 {
1069 nxt_int_t ret;
1070 nxt_array_t *cookies;
1071 nxt_http_field_t *f;
1072
1073 if (r->cookies != NULL) {
1074 return r->cookies;
1075 }
1076
1077 cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
1078 if (nxt_slow_path(cookies == NULL)) {
1079 return NULL;
1080 }
1081
1082 nxt_list_each(f, r->fields) {
1083
1084 if (f->hash != NXT_HTTP_COOKIE_HASH
1085 || f->name_length != 6
1086 || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
1087 {
1088 continue;
1089 }
1090
1091 ret = nxt_http_cookie_parse(cookies, f->value,
1092 f->value + f->value_length);
1093 if (ret != NXT_OK) {
1094 return NULL;
1095 }
1096
1097 } nxt_list_loop;
1098
1099 r->cookies = cookies;
1100
1101 return cookies;
1102 }
1103
1104
1105 static nxt_int_t
nxt_http_cookie_parse(nxt_array_t * cookies,u_char * start,const u_char * end)1106 nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, const u_char *end)
1107 {
1108 size_t name_length;
1109 u_char c, *p, *name;
1110 nxt_http_name_value_t *nv;
1111
1112 name = NULL;
1113 name_length = 0;
1114
1115 for (p = start; p < end; p++) {
1116 c = *p;
1117
1118 if (c == '=' && name == NULL) {
1119 while (start[0] == ' ') { start++; }
1120
1121 name_length = p - start;
1122 name = start;
1123
1124 start = p + 1;
1125
1126 } else if (c == ';') {
1127 if (name != NULL) {
1128 nv = nxt_http_cookie(cookies, name, name_length, start, p);
1129 if (nxt_slow_path(nv == NULL)) {
1130 return NXT_ERROR;
1131 }
1132 }
1133
1134 name = NULL;
1135 start = p + 1;
1136 }
1137 }
1138
1139 if (name != NULL) {
1140 nv = nxt_http_cookie(cookies, name, name_length, start, p);
1141 if (nxt_slow_path(nv == NULL)) {
1142 return NXT_ERROR;
1143 }
1144 }
1145
1146 return NXT_OK;
1147 }
1148
1149
1150 static nxt_http_name_value_t *
nxt_http_cookie(nxt_array_t * array,u_char * name,size_t name_length,u_char * start,const u_char * end)1151 nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length,
1152 u_char *start, const u_char *end)
1153 {
1154 u_char c, *p;
1155 uint32_t hash;
1156 nxt_http_name_value_t *nv;
1157
1158 nv = nxt_array_add(array);
1159 if (nxt_slow_path(nv == NULL)) {
1160 return NULL;
1161 }
1162
1163 nv->name_length = name_length;
1164 nv->name = name;
1165
1166 hash = NXT_HTTP_FIELD_HASH_INIT;
1167
1168 for (p = name; p < name + name_length; p++) {
1169 c = *p;
1170 hash = nxt_http_field_hash_char(hash, c);
1171 }
1172
1173 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
1174
1175 while (start < end && end[-1] == ' ') { end--; }
1176
1177 nv->value_length = end - start;
1178 nv->value = start;
1179
1180 return nv;
1181 }
1182
1183
1184 int64_t
nxt_http_field_hash(nxt_mp_t * mp,nxt_str_t * name,nxt_bool_t case_sensitive,uint8_t encoding)1185 nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive,
1186 uint8_t encoding)
1187 {
1188 u_char c, *p, *src, *start, *end, plus;
1189 uint8_t d0, d1;
1190 uint32_t hash;
1191 nxt_str_t str;
1192 nxt_uint_t i;
1193
1194 str.length = name->length;
1195
1196 str.start = nxt_mp_nget(mp, str.length);
1197 if (nxt_slow_path(str.start == NULL)) {
1198 return -1;
1199 }
1200
1201 p = str.start;
1202
1203 hash = NXT_HTTP_FIELD_HASH_INIT;
1204
1205 if (encoding == NXT_HTTP_URI_ENCODING_NONE) {
1206 for (i = 0; i < name->length; i++) {
1207 c = name->start[i];
1208 *p++ = c;
1209
1210 c = case_sensitive ? c : nxt_lowcase(c);
1211 hash = nxt_http_field_hash_char(hash, c);
1212 }
1213
1214 goto end;
1215 }
1216
1217 plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+';
1218
1219 start = name->start;
1220 end = start + name->length;
1221
1222 for (src = start; src < end; src++) {
1223 c = *src;
1224
1225 switch (c) {
1226 case '%':
1227 if (nxt_slow_path(end - src <= 2)) {
1228 return -1;
1229 }
1230
1231 d0 = nxt_hex2int[src[1]];
1232 d1 = nxt_hex2int[src[2]];
1233 src += 2;
1234
1235 if (nxt_slow_path((d0 | d1) >= 16)) {
1236 return -1;
1237 }
1238
1239 c = (d0 << 4) + d1;
1240 *p++ = c;
1241 break;
1242
1243 case '+':
1244 c = plus;
1245 *p++ = c;
1246 break;
1247
1248 default:
1249 *p++ = c;
1250 break;
1251 }
1252
1253 c = case_sensitive ? c : nxt_lowcase(c);
1254 hash = nxt_http_field_hash_char(hash, c);
1255 }
1256
1257 str.length = p - str.start;
1258
1259 end:
1260
1261 *name = str;
1262
1263 return nxt_http_field_hash_end(hash) & 0xFFFF;
1264 }
1265
1266
1267 int64_t
nxt_http_argument_hash(nxt_mp_t * mp,nxt_str_t * name)1268 nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name)
1269 {
1270 return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_PLUS);
1271 }
1272
1273
1274 int64_t
nxt_http_header_hash(nxt_mp_t * mp,nxt_str_t * name)1275 nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name)
1276 {
1277 u_char c, *p;
1278 uint32_t i, hash;
1279 nxt_str_t str;
1280
1281 str.length = name->length;
1282
1283 str.start = nxt_mp_nget(mp, str.length);
1284 if (nxt_slow_path(str.start == NULL)) {
1285 return -1;
1286 }
1287
1288 p = str.start;
1289 hash = NXT_HTTP_FIELD_HASH_INIT;
1290
1291 for (i = 0; i < name->length; i++) {
1292 c = name->start[i];
1293
1294 if (c >= 'A' && c <= 'Z') {
1295 *p = c | 0x20;
1296
1297 } else if (c == '_') {
1298 *p = '-';
1299
1300 } else {
1301 *p = c;
1302 }
1303
1304 hash = nxt_http_field_hash_char(hash, *p);
1305 p++;
1306 }
1307
1308 *name = str;
1309
1310 return nxt_http_field_hash_end(hash) & 0xFFFF;
1311 }
1312
1313
1314 int64_t
nxt_http_cookie_hash(nxt_mp_t * mp,nxt_str_t * name)1315 nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name)
1316 {
1317 return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE);
1318 }
1319