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_client_ip(nxt_task_t *task,
14 nxt_http_request_t *r);
15 static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr(
16 nxt_http_request_t *r, u_char *start, size_t len);
17 static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data);
18 static void nxt_http_request_proto_info(nxt_task_t *task,
19 nxt_http_request_t *r);
20 static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
21 void *data);
22 static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
23
24 static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now,
25 struct tm *tm, size_t size, const char *format);
26
27 static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array,
28 u_char *name, size_t name_length, uint32_t hash, u_char *start,
29 u_char *end);
30 static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start,
31 u_char *end);
32 static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name,
33 size_t name_length, u_char *start, u_char *end);
34
35
36 #define NXT_HTTP_COOKIE_HASH \
37 (nxt_http_field_hash_end( \
38 nxt_http_field_hash_char( \
39 nxt_http_field_hash_char( \
40 nxt_http_field_hash_char( \
41 nxt_http_field_hash_char( \
42 nxt_http_field_hash_char( \
43 nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \
44 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
45
46
47 static const nxt_http_request_state_t nxt_http_request_init_state;
48 static const nxt_http_request_state_t nxt_http_request_body_state;
49
50
51 nxt_time_string_t nxt_http_date_cache = {
52 (nxt_atomic_uint_t) -1,
53 nxt_http_date_cache_handler,
54 NULL,
55 NXT_HTTP_DATE_LEN,
56 NXT_THREAD_TIME_GMT,
57 NXT_THREAD_TIME_SEC,
58 };
59
60
61 nxt_int_t
nxt_http_init(nxt_task_t * task)62 nxt_http_init(nxt_task_t *task)
63 {
64 nxt_int_t ret;
65
66 ret = nxt_h1p_init(task);
67
68 if (ret != NXT_OK) {
69 return ret;
70 }
71
72 return nxt_http_response_hash_init(task);
73 }
74
75
76 nxt_int_t
nxt_http_request_host(void * ctx,nxt_http_field_t * field,uintptr_t data)77 nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data)
78 {
79 nxt_int_t ret;
80 nxt_str_t host;
81 nxt_http_request_t *r;
82
83 r = ctx;
84
85 if (nxt_slow_path(r->host.start != NULL)) {
86 return NXT_HTTP_BAD_REQUEST;
87 }
88
89 host.length = field->value_length;
90 host.start = field->value;
91
92 ret = nxt_http_validate_host(&host, r->mem_pool);
93
94 if (nxt_fast_path(ret == NXT_OK)) {
95 r->host = host;
96 }
97
98 return ret;
99 }
100
101
102 static nxt_int_t
nxt_http_validate_host(nxt_str_t * host,nxt_mp_t * mp)103 nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp)
104 {
105 u_char *h, ch;
106 size_t i, dot_pos, host_length;
107 nxt_bool_t lowcase;
108
109 enum {
110 sw_usual,
111 sw_literal,
112 sw_rest
113 } state;
114
115 dot_pos = host->length;
116 host_length = host->length;
117
118 h = host->start;
119
120 lowcase = 0;
121 state = sw_usual;
122
123 for (i = 0; i < host->length; i++) {
124 ch = h[i];
125
126 if (ch > ']') {
127 /* Short path. */
128 continue;
129 }
130
131 switch (ch) {
132
133 case '.':
134 if (dot_pos == i - 1) {
135 return NXT_HTTP_BAD_REQUEST;
136 }
137
138 dot_pos = i;
139 break;
140
141 case ':':
142 if (state == sw_usual) {
143 host_length = i;
144 state = sw_rest;
145 }
146
147 break;
148
149 case '[':
150 if (i == 0) {
151 state = sw_literal;
152 }
153
154 break;
155
156 case ']':
157 if (state == sw_literal) {
158 host_length = i + 1;
159 state = sw_rest;
160 }
161
162 break;
163
164 case '/':
165 return NXT_HTTP_BAD_REQUEST;
166
167 default:
168 if (ch >= 'A' && ch <= 'Z') {
169 lowcase = 1;
170 }
171
172 break;
173 }
174 }
175
176 if (dot_pos == host_length - 1) {
177 host_length--;
178 }
179
180 host->length = host_length;
181
182 if (lowcase) {
183 host->start = nxt_mp_nget(mp, host_length);
184 if (nxt_slow_path(host->start == NULL)) {
185 return NXT_HTTP_INTERNAL_SERVER_ERROR;
186 }
187
188 nxt_memcpy_lowcase(host->start, h, host_length);
189 }
190
191 return NXT_OK;
192 }
193
194
195 nxt_int_t
nxt_http_request_field(void * ctx,nxt_http_field_t * field,uintptr_t offset)196 nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset)
197 {
198 nxt_http_request_t *r;
199
200 r = ctx;
201
202 nxt_value_at(nxt_http_field_t *, r, offset) = field;
203
204 return NXT_OK;
205 }
206
207
208 nxt_int_t
nxt_http_request_content_length(void * ctx,nxt_http_field_t * field,uintptr_t data)209 nxt_http_request_content_length(void *ctx, nxt_http_field_t *field,
210 uintptr_t data)
211 {
212 nxt_off_t n, max_body_size;
213 nxt_http_request_t *r;
214
215 r = ctx;
216
217 if (nxt_fast_path(r->content_length == NULL)) {
218 r->content_length = field;
219
220 n = nxt_off_t_parse(field->value, field->value_length);
221
222 if (nxt_fast_path(n >= 0)) {
223 r->content_length_n = n;
224
225 max_body_size = r->conf->socket_conf->max_body_size;
226
227 if (nxt_slow_path(n > max_body_size)) {
228 return NXT_HTTP_PAYLOAD_TOO_LARGE;
229 }
230
231 return NXT_OK;
232 }
233 }
234
235 return NXT_HTTP_BAD_REQUEST;
236 }
237
238
239 nxt_http_request_t *
nxt_http_request_create(nxt_task_t * task)240 nxt_http_request_create(nxt_task_t *task)
241 {
242 nxt_mp_t *mp;
243 nxt_buf_t *last;
244 nxt_http_request_t *r;
245
246 mp = nxt_mp_create(4096, 128, 512, 32);
247 if (nxt_slow_path(mp == NULL)) {
248 return NULL;
249 }
250
251 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t));
252 if (nxt_slow_path(r == NULL)) {
253 goto fail;
254 }
255
256 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
257 if (nxt_slow_path(r->resp.fields == NULL)) {
258 goto fail;
259 }
260
261 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE);
262 if (nxt_slow_path(last == NULL)) {
263 goto fail;
264 }
265
266 nxt_buf_set_sync(last);
267 nxt_buf_set_last(last);
268 last->completion_handler = nxt_http_request_done;
269 last->parent = r;
270 r->last = last;
271
272 r->mem_pool = mp;
273 r->content_length_n = -1;
274 r->resp.content_length_n = -1;
275 r->state = &nxt_http_request_init_state;
276
277 return r;
278
279 fail:
280
281 nxt_mp_release(mp);
282
283 return NULL;
284 }
285
286
287 static const nxt_http_request_state_t nxt_http_request_init_state
288 nxt_aligned(64) =
289 {
290 .ready_handler = nxt_http_request_start,
291 .error_handler = nxt_http_request_close_handler,
292 };
293
294
295 static void
nxt_http_request_start(nxt_task_t * task,void * obj,void * data)296 nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
297 {
298 nxt_int_t ret;
299 nxt_http_request_t *r;
300
301 r = obj;
302
303 r->state = &nxt_http_request_body_state;
304
305 ret = nxt_http_request_client_ip(task, r);
306 if (nxt_slow_path(ret != NXT_OK)) {
307 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
308 }
309
310 nxt_http_request_read_body(task, r);
311 }
312
313
314 static nxt_int_t
nxt_http_request_client_ip(nxt_task_t * task,nxt_http_request_t * r)315 nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r)
316 {
317 u_char *start, *p;
318 nxt_int_t ret, i, len;
319 nxt_str_t *header;
320 nxt_array_t *fields_arr; /* of nxt_http_field_t * */
321 nxt_sockaddr_t *sa, *prev_sa;
322 nxt_http_field_t *f, **fields;
323 nxt_http_client_ip_t *client_ip;
324
325 client_ip = r->conf->socket_conf->client_ip;
326
327 if (client_ip == NULL) {
328 return NXT_OK;
329 }
330
331 ret = nxt_http_route_addr_rule(r, client_ip->source, r->remote);
332 if (ret <= 0) {
333 return NXT_OK;
334 }
335
336 header = client_ip->header;
337
338 fields_arr = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_field_t *));
339 if (nxt_slow_path(fields_arr == NULL)) {
340 return NXT_ERROR;
341 }
342
343 nxt_list_each(f, r->fields) {
344 if (f->hash == client_ip->header_hash
345 && f->name_length == client_ip->header->length
346 && f->value_length > 0
347 && nxt_memcasecmp(f->name, header->start, header->length) == 0)
348 {
349 fields = nxt_array_add(fields_arr);
350 if (nxt_slow_path(fields == NULL)) {
351 return NXT_ERROR;
352 }
353
354 *fields = f;
355 }
356 } nxt_list_loop;
357
358 prev_sa = r->remote;
359 fields = (nxt_http_field_t **) fields_arr->elts;
360
361 i = fields_arr->nelts;
362
363 while (i-- > 0) {
364 f = fields[i];
365 start = f->value;
366 len = f->value_length;
367
368 do {
369 for (p = start + len - 1; p > start; p--, len--) {
370 if (*p != ' ' && *p != ',') {
371 break;
372 }
373 }
374
375 for (/* void */; p > start; p--) {
376 if (*p == ' ' || *p == ',') {
377 p++;
378 break;
379 }
380 }
381
382 sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start));
383 if (nxt_slow_path(sa == NULL)) {
384 if (prev_sa != NULL) {
385 r->remote = prev_sa;
386 }
387
388 return NXT_OK;
389 }
390
391 if (!client_ip->recursive) {
392 r->remote = sa;
393
394 return NXT_OK;
395 }
396
397 ret = nxt_http_route_addr_rule(r, client_ip->source, sa);
398 if (ret <= 0 || (i == 0 && p == start)) {
399 r->remote = sa;
400
401 return NXT_OK;
402 }
403
404 prev_sa = sa;
405 len = p - 1 - start;
406
407 } while (len > 0);
408 }
409
410 return NXT_OK;
411 }
412
413
414 static nxt_sockaddr_t *
nxt_http_request_client_ip_sockaddr(nxt_http_request_t * r,u_char * start,size_t len)415 nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start,
416 size_t len)
417 {
418 nxt_str_t addr;
419 nxt_sockaddr_t *sa;
420
421 addr.start = start;
422 addr.length = len;
423
424 sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr);
425 if (nxt_slow_path(sa == NULL)) {
426 return NULL;
427 }
428
429 switch (sa->u.sockaddr.sa_family) {
430 case AF_INET:
431 if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) {
432 return NULL;
433 }
434
435 break;
436
437 #if (NXT_INET6)
438 case AF_INET6:
439 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) {
440 return NULL;
441 }
442
443 break;
444 #endif /* NXT_INET6 */
445
446 default:
447 return NULL;
448 }
449
450 return sa;
451 }
452
453
454 static const nxt_http_request_state_t nxt_http_request_body_state
455 nxt_aligned(64) =
456 {
457 .ready_handler = nxt_http_request_ready,
458 .error_handler = nxt_http_request_close_handler,
459 };
460
461
462 static void
nxt_http_request_ready(nxt_task_t * task,void * obj,void * data)463 nxt_http_request_ready(nxt_task_t *task, void *obj, void *data)
464 {
465 nxt_http_action_t *action;
466 nxt_http_request_t *r;
467
468 r = obj;
469 action = r->conf->socket_conf->action;
470
471 nxt_http_request_action(task, r, action);
472 }
473
474
475 void
nxt_http_request_action(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)476 nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
477 nxt_http_action_t *action)
478 {
479 if (nxt_fast_path(action != NULL)) {
480
481 do {
482 action = action->handler(task, r, action);
483
484 if (action == NULL) {
485 return;
486 }
487
488 if (action == NXT_HTTP_ACTION_ERROR) {
489 break;
490 }
491
492 } while (r->pass_count++ < 255);
493 }
494
495 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
496 }
497
498
499 nxt_http_action_t *
nxt_http_application_handler(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)500 nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r,
501 nxt_http_action_t *action)
502 {
503 nxt_debug(task, "http application handler");
504
505 /*
506 * TODO: need an application flag to get local address
507 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go.
508 */
509 nxt_http_request_proto_info(task, r);
510
511 if (r->host.length != 0) {
512 r->server_name = r->host;
513
514 } else {
515 nxt_str_set(&r->server_name, "localhost");
516 }
517
518 nxt_router_process_http_request(task, r, action);
519
520 return NULL;
521 }
522
523
524 static void
nxt_http_request_proto_info(nxt_task_t * task,nxt_http_request_t * r)525 nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r)
526 {
527 if (nxt_fast_path(r->proto.any != NULL)) {
528 nxt_http_proto[r->protocol].local_addr(task, r);
529 }
530 }
531
532
533 void
nxt_http_request_read_body(nxt_task_t * task,nxt_http_request_t * r)534 nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r)
535 {
536 if (nxt_fast_path(r->proto.any != NULL)) {
537 nxt_http_proto[r->protocol].body_read(task, r);
538 }
539 }
540
541
542 void
nxt_http_request_header_send(nxt_task_t * task,nxt_http_request_t * r,nxt_work_handler_t body_handler,void * data)543 nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r,
544 nxt_work_handler_t body_handler, void *data)
545 {
546 u_char *p, *end;
547 nxt_http_field_t *server, *date, *content_length;
548
549 /*
550 * TODO: "Server", "Date", and "Content-Length" processing should be moved
551 * to the last header filter.
552 */
553
554 server = nxt_list_zero_add(r->resp.fields);
555 if (nxt_slow_path(server == NULL)) {
556 goto fail;
557 }
558
559 nxt_http_field_set(server, "Server", NXT_SERVER);
560
561 if (r->resp.date == NULL) {
562 date = nxt_list_zero_add(r->resp.fields);
563 if (nxt_slow_path(date == NULL)) {
564 goto fail;
565 }
566
567 nxt_http_field_name_set(date, "Date");
568
569 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size);
570 if (nxt_slow_path(p == NULL)) {
571 goto fail;
572 }
573
574 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p);
575
576 date->value = p;
577 date->value_length = nxt_http_date_cache.size;
578
579 r->resp.date = date;
580 }
581
582 if (r->resp.content_length_n != -1
583 && (r->resp.content_length == NULL || r->resp.content_length->skip))
584 {
585 content_length = nxt_list_zero_add(r->resp.fields);
586 if (nxt_slow_path(content_length == NULL)) {
587 goto fail;
588 }
589
590 nxt_http_field_name_set(content_length, "Content-Length");
591
592 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
593 if (nxt_slow_path(p == NULL)) {
594 goto fail;
595 }
596
597 content_length->value = p;
598 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n);
599 content_length->value_length = end - p;
600
601 r->resp.content_length = content_length;
602 }
603
604 if (nxt_fast_path(r->proto.any != NULL)) {
605 nxt_http_proto[r->protocol].header_send(task, r, body_handler, data);
606 }
607
608 return;
609
610 fail:
611
612 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
613 }
614
615
616 void
nxt_http_request_ws_frame_start(nxt_task_t * task,nxt_http_request_t * r,nxt_buf_t * ws_frame)617 nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r,
618 nxt_buf_t *ws_frame)
619 {
620 if (r->proto.any != NULL) {
621 nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame);
622 }
623 }
624
625
626 void
nxt_http_request_send(nxt_task_t * task,nxt_http_request_t * r,nxt_buf_t * out)627 nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
628 {
629 if (nxt_fast_path(r->proto.any != NULL)) {
630 nxt_http_proto[r->protocol].send(task, r, out);
631 }
632 }
633
634
635 nxt_buf_t *
nxt_http_buf_mem(nxt_task_t * task,nxt_http_request_t * r,size_t size)636 nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size)
637 {
638 nxt_buf_t *b;
639
640 b = nxt_buf_mem_alloc(r->mem_pool, size, 0);
641 if (nxt_fast_path(b != NULL)) {
642 b->completion_handler = nxt_http_request_mem_buf_completion;
643 b->parent = r;
644 nxt_mp_retain(r->mem_pool);
645
646 } else {
647 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
648 }
649
650 return b;
651 }
652
653
654 static void
nxt_http_request_mem_buf_completion(nxt_task_t * task,void * obj,void * data)655 nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data)
656 {
657 nxt_buf_t *b, *next;
658 nxt_http_request_t *r;
659
660 b = obj;
661 r = data;
662
663 do {
664 next = b->next;
665
666 nxt_mp_free(r->mem_pool, b);
667 nxt_mp_release(r->mem_pool);
668
669 b = next;
670 } while (b != NULL);
671 }
672
673
674 nxt_buf_t *
nxt_http_buf_last(nxt_http_request_t * r)675 nxt_http_buf_last(nxt_http_request_t *r)
676 {
677 nxt_buf_t *last;
678
679 last = r->last;
680 r->last = NULL;
681
682 return last;
683 }
684
685
686 static void
nxt_http_request_done(nxt_task_t * task,void * obj,void * data)687 nxt_http_request_done(nxt_task_t *task, void *obj, void *data)
688 {
689 nxt_http_request_t *r;
690
691 r = data;
692
693 nxt_debug(task, "http request done");
694
695 nxt_http_request_close_handler(task, r, r->proto.any);
696 }
697
698
699 void
nxt_http_request_error_handler(nxt_task_t * task,void * obj,void * data)700 nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
701 {
702 nxt_http_proto_t proto;
703 nxt_http_request_t *r;
704
705 r = obj;
706 proto.any = data;
707
708 nxt_debug(task, "http request error handler");
709
710 r->error = 1;
711
712 if (nxt_fast_path(proto.any != NULL)) {
713 nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r));
714 }
715 }
716
717
718 void
nxt_http_request_close_handler(nxt_task_t * task,void * obj,void * data)719 nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
720 {
721 nxt_http_proto_t proto;
722 nxt_http_request_t *r;
723 nxt_http_protocol_t protocol;
724 nxt_socket_conf_joint_t *conf;
725 nxt_router_access_log_t *access_log;
726
727 r = obj;
728 proto.any = data;
729
730 nxt_debug(task, "http request close handler");
731
732 conf = r->conf;
733
734 if (!r->logged) {
735 r->logged = 1;
736
737 access_log = conf->socket_conf->router_conf->access_log;
738
739 if (access_log != NULL) {
740 access_log->handler(task, r, access_log);
741 }
742 }
743
744 r->proto.any = NULL;
745
746 if (r->body != NULL && nxt_buf_is_file(r->body)
747 && r->body->file->fd != -1)
748 {
749 nxt_fd_close(r->body->file->fd);
750
751 r->body->file->fd = -1;
752 }
753
754 if (nxt_fast_path(proto.any != NULL)) {
755 protocol = r->protocol;
756
757 nxt_http_proto[protocol].close(task, proto, conf);
758
759 nxt_mp_release(r->mem_pool);
760 }
761 }
762
763
764 static u_char *
nxt_http_date_cache_handler(u_char * buf,nxt_realtime_t * now,struct tm * tm,size_t size,const char * format)765 nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm,
766 size_t size, const char *format)
767 {
768 return nxt_http_date(buf, tm);
769 }
770
771
772 nxt_array_t *
nxt_http_arguments_parse(nxt_http_request_t * r)773 nxt_http_arguments_parse(nxt_http_request_t *r)
774 {
775 size_t name_length;
776 u_char *p, *dst, *dst_start, *start, *end, *name;
777 uint8_t d0, d1;
778 uint32_t hash;
779 nxt_array_t *args;
780 nxt_http_name_value_t *nv;
781
782 if (r->arguments != NULL) {
783 return r->arguments;
784 }
785
786 args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
787 if (nxt_slow_path(args == NULL)) {
788 return NULL;
789 }
790
791 hash = NXT_HTTP_FIELD_HASH_INIT;
792 name = NULL;
793 name_length = 0;
794
795 dst_start = nxt_mp_nget(r->mem_pool, r->args->length);
796 if (nxt_slow_path(dst_start == NULL)) {
797 return NULL;
798 }
799
800 r->args_decoded.start = dst_start;
801
802 start = r->args->start;
803 end = start + r->args->length;
804
805 for (p = start, dst = dst_start; p < end; p++, dst++) {
806 *dst = *p;
807
808 switch (*p) {
809 case '=':
810 if (name == NULL) {
811 name_length = dst - dst_start;
812 name = dst_start;
813 dst_start = dst + 1;
814 }
815
816 continue;
817
818 case '&':
819 if (name_length != 0 || dst != dst_start) {
820 nv = nxt_http_argument(args, name, name_length, hash, dst_start,
821 dst);
822 if (nxt_slow_path(nv == NULL)) {
823 return NULL;
824 }
825 }
826
827 hash = NXT_HTTP_FIELD_HASH_INIT;
828 name_length = 0;
829 name = NULL;
830 dst_start = dst + 1;
831
832 continue;
833
834 case '+':
835 *dst = ' ';
836
837 break;
838
839 case '%':
840 if (nxt_slow_path(end - p <= 2)) {
841 break;
842 }
843
844 d0 = nxt_hex2int[p[1]];
845 d1 = nxt_hex2int[p[2]];
846
847 if (nxt_slow_path((d0 | d1) >= 16)) {
848 break;
849 }
850
851 p += 2;
852 *dst = (d0 << 4) + d1;
853
854 break;
855 }
856
857 if (name == NULL) {
858 hash = nxt_http_field_hash_char(hash, *dst);
859 }
860 }
861
862 r->args_decoded.length = dst - r->args_decoded.start;
863
864 if (name_length != 0 || dst != dst_start) {
865 nv = nxt_http_argument(args, name, name_length, hash, dst_start, dst);
866 if (nxt_slow_path(nv == NULL)) {
867 return NULL;
868 }
869 }
870
871 r->arguments = args;
872
873 return args;
874 }
875
876
877 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,u_char * end)878 nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length,
879 uint32_t hash, u_char *start, u_char *end)
880 {
881 size_t length;
882 nxt_http_name_value_t *nv;
883
884 nv = nxt_array_add(array);
885 if (nxt_slow_path(nv == NULL)) {
886 return NULL;
887 }
888
889 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
890
891 length = end - start;
892
893 if (name == NULL) {
894 name_length = length;
895 name = start;
896 length = 0;
897 }
898
899 nv->name_length = name_length;
900 nv->value_length = length;
901 nv->name = name;
902 nv->value = start;
903
904 return nv;
905 }
906
907
908 nxt_array_t *
nxt_http_cookies_parse(nxt_http_request_t * r)909 nxt_http_cookies_parse(nxt_http_request_t *r)
910 {
911 nxt_int_t ret;
912 nxt_array_t *cookies;
913 nxt_http_field_t *f;
914
915 if (r->cookies != NULL) {
916 return r->cookies;
917 }
918
919 cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
920 if (nxt_slow_path(cookies == NULL)) {
921 return NULL;
922 }
923
924 nxt_list_each(f, r->fields) {
925
926 if (f->hash != NXT_HTTP_COOKIE_HASH
927 || f->name_length != 6
928 || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
929 {
930 continue;
931 }
932
933 ret = nxt_http_cookie_parse(cookies, f->value,
934 f->value + f->value_length);
935 if (ret != NXT_OK) {
936 return NULL;
937 }
938
939 } nxt_list_loop;
940
941 r->cookies = cookies;
942
943 return cookies;
944 }
945
946
947 static nxt_int_t
nxt_http_cookie_parse(nxt_array_t * cookies,u_char * start,u_char * end)948 nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
949 {
950 size_t name_length;
951 u_char c, *p, *name;
952 nxt_http_name_value_t *nv;
953
954 name = NULL;
955 name_length = 0;
956
957 for (p = start; p < end; p++) {
958 c = *p;
959
960 if (c == '=') {
961 while (start[0] == ' ') { start++; }
962
963 name_length = p - start;
964
965 if (name_length != 0) {
966 name = start;
967 }
968
969 start = p + 1;
970
971 } else if (c == ';') {
972 if (name != NULL) {
973 nv = nxt_http_cookie(cookies, name, name_length, start, p);
974 if (nxt_slow_path(nv == NULL)) {
975 return NXT_ERROR;
976 }
977 }
978
979 name = NULL;
980 start = p + 1;
981 }
982 }
983
984 if (name != NULL) {
985 nv = nxt_http_cookie(cookies, name, name_length, start, p);
986 if (nxt_slow_path(nv == NULL)) {
987 return NXT_ERROR;
988 }
989 }
990
991 return NXT_OK;
992 }
993
994
995 static nxt_http_name_value_t *
nxt_http_cookie(nxt_array_t * array,u_char * name,size_t name_length,u_char * start,u_char * end)996 nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length,
997 u_char *start, u_char *end)
998 {
999 u_char c, *p;
1000 uint32_t hash;
1001 nxt_http_name_value_t *nv;
1002
1003 nv = nxt_array_add(array);
1004 if (nxt_slow_path(nv == NULL)) {
1005 return NULL;
1006 }
1007
1008 nv->name_length = name_length;
1009 nv->name = name;
1010
1011 hash = NXT_HTTP_FIELD_HASH_INIT;
1012
1013 for (p = name; p < name + name_length; p++) {
1014 c = *p;
1015 hash = nxt_http_field_hash_char(hash, c);
1016 }
1017
1018 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
1019
1020 while (start < end && end[-1] == ' ') { end--; }
1021
1022 nv->value_length = end - start;
1023 nv->value = start;
1024
1025 return nv;
1026 }
1027