Coverage Report

Created: 2024-07-23 06:07

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