Coverage Report

Created: 2025-03-14 06:17

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