xref: /unit/src/nxt_http_request.c (revision 2746:2adebf2bf59c)
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