Coverage Report

Created: 2025-07-11 06:49

/src/unit/src/nxt_http_variables.c
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright (C) NGINX, Inc.
4
 */
5
6
#include <nxt_router.h>
7
#include <nxt_http.h>
8
#include <nxt_h1proto.h>
9
10
11
static nxt_int_t nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str,
12
    void *ctx, void *data);
13
static nxt_int_t nxt_http_var_request_time(nxt_task_t *task, nxt_str_t *str,
14
    void *ctx, void *data);
15
static nxt_int_t nxt_http_var_method(nxt_task_t *task, nxt_str_t *str,
16
    void *ctx, void *data);
17
static nxt_int_t nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str,
18
    void *ctx, void *data);
19
static nxt_int_t nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx,
20
    void *data);
21
static nxt_int_t nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx,
22
    void *data);
23
static nxt_int_t nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str,
24
    void *ctx, void *data);
25
static nxt_int_t nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str,
26
    void *ctx, void *data);
27
static u_char *nxt_http_log_date(u_char *buf, nxt_realtime_t *now,
28
    struct tm *tm, size_t size, const char *format);
29
static nxt_int_t nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str,
30
    void *ctx, void *data);
31
static nxt_int_t nxt_http_var_request_id(nxt_task_t *task, nxt_str_t *str,
32
    void *ctx, void *data);
33
static nxt_int_t nxt_http_var_status(nxt_task_t *task, nxt_str_t *str,
34
    void *ctx, void *data);
35
static nxt_int_t nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str,
36
    void *ctx, void *data);
37
static nxt_int_t nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str,
38
    void *ctx, void *data);
39
static nxt_int_t nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str,
40
    void *ctx, void *data);
41
static nxt_int_t nxt_http_var_response_connection(nxt_task_t *task,
42
    nxt_str_t *str, void *ctx, void *data);
43
static nxt_int_t nxt_http_var_response_content_length(nxt_task_t *task,
44
    nxt_str_t *str, void *ctx, void *data);
45
static nxt_int_t nxt_http_var_response_transfer_encoding(nxt_task_t *task,
46
    nxt_str_t *str, void *ctx, void *data);
47
static nxt_int_t nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx,
48
    void *data);
49
static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str,
50
    void *ctx, void *data);
51
static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str,
52
    void *ctx, void *data);
53
static nxt_int_t nxt_http_var_response_header(nxt_task_t *task, nxt_str_t *str,
54
    void *ctx, void *data);
55
56
57
static nxt_var_decl_t  nxt_http_vars[] = {
58
    {
59
        .name = nxt_string("dollar"),
60
        .handler = nxt_http_var_dollar,
61
        .cacheable = 1,
62
    }, {
63
        .name = nxt_string("request_time"),
64
        .handler = nxt_http_var_request_time,
65
        .cacheable = 1,
66
    }, {
67
        .name = nxt_string("method"),
68
        .handler = nxt_http_var_method,
69
        .cacheable = 1,
70
    }, {
71
        .name = nxt_string("request_uri"),
72
        .handler = nxt_http_var_request_uri,
73
        .cacheable = 1,
74
    }, {
75
        .name = nxt_string("uri"),
76
        .handler = nxt_http_var_uri,
77
        .cacheable = 0,
78
    }, {
79
        .name = nxt_string("host"),
80
        .handler = nxt_http_var_host,
81
        .cacheable = 1,
82
    }, {
83
        .name = nxt_string("remote_addr"),
84
        .handler = nxt_http_var_remote_addr,
85
        .cacheable = 1,
86
    }, {
87
        .name = nxt_string("time_local"),
88
        .handler = nxt_http_var_time_local,
89
        .cacheable = 1,
90
    }, {
91
        .name = nxt_string("request_line"),
92
        .handler = nxt_http_var_request_line,
93
        .cacheable = 1,
94
    }, {
95
        .name = nxt_string("request_id"),
96
        .handler = nxt_http_var_request_id,
97
        .cacheable = 1,
98
    }, {
99
        .name = nxt_string("status"),
100
        .handler = nxt_http_var_status,
101
        .cacheable = 1,
102
    }, {
103
        .name = nxt_string("body_bytes_sent"),
104
        .handler = nxt_http_var_body_bytes_sent,
105
        .cacheable = 1,
106
    }, {
107
        .name = nxt_string("header_referer"),
108
        .handler = nxt_http_var_referer,
109
        .cacheable = 1,
110
    }, {
111
        .name = nxt_string("response_header_connection"),
112
        .handler = nxt_http_var_response_connection,
113
        .cacheable = 1,
114
    }, {
115
        .name = nxt_string("response_header_content_length"),
116
        .handler = nxt_http_var_response_content_length,
117
        .cacheable = 1,
118
    }, {
119
        .name = nxt_string("response_header_transfer_encoding"),
120
        .handler = nxt_http_var_response_transfer_encoding,
121
        .cacheable = 1,
122
    }, {
123
        .name = nxt_string("header_user_agent"),
124
        .handler = nxt_http_var_user_agent,
125
        .cacheable = 1,
126
    },
127
};
128
129
130
nxt_int_t
131
nxt_http_register_variables(void)
132
0
{
133
0
    return nxt_var_register(nxt_http_vars, nxt_nitems(nxt_http_vars));
134
0
}
135
136
137
nxt_int_t
138
nxt_http_unknown_var_ref(nxt_mp_t *mp, nxt_var_ref_t *ref, nxt_str_t *name)
139
3.08k
{
140
3.08k
    int64_t    hash;
141
3.08k
    nxt_str_t  str, *lower;
142
143
3.08k
    if (nxt_str_start(name, "response_header_", 16)) {
144
80
        ref->handler = nxt_http_var_response_header;
145
80
        ref->cacheable = 0;
146
147
80
        str.start = name->start + 16;
148
80
        str.length = name->length - 16;
149
150
80
        if (str.length == 0) {
151
2
            return NXT_ERROR;
152
2
        }
153
154
78
        lower = nxt_str_alloc(mp, str.length);
155
78
        if (nxt_slow_path(lower == NULL)) {
156
0
            return NXT_ERROR;
157
0
        }
158
159
78
        nxt_memcpy_lowcase(lower->start, str.start, str.length);
160
161
78
        ref->data = lower;
162
163
78
        return NXT_OK;
164
78
    }
165
166
3.00k
    if (nxt_str_start(name, "header_", 7)) {
167
165
        ref->handler = nxt_http_var_header;
168
165
        ref->cacheable = 1;
169
170
165
        str.start = name->start + 7;
171
165
        str.length = name->length - 7;
172
173
165
        if (str.length == 0) {
174
1
            return NXT_ERROR;
175
1
        }
176
177
164
        hash = nxt_http_header_hash(mp, &str);
178
164
        if (nxt_slow_path(hash == -1)) {
179
0
            return NXT_ERROR;
180
0
        }
181
182
2.84k
    } else if (nxt_str_start(name, "arg_", 4)) {
183
2.55k
        ref->handler = nxt_http_var_arg;
184
2.55k
        ref->cacheable = 1;
185
186
2.55k
        str.start = name->start + 4;
187
2.55k
        str.length = name->length - 4;
188
189
2.55k
        if (str.length == 0) {
190
3
            return NXT_ERROR;
191
3
        }
192
193
2.54k
        hash = nxt_http_argument_hash(mp, &str);
194
2.54k
        if (nxt_slow_path(hash == -1)) {
195
0
            return NXT_ERROR;
196
0
        }
197
198
2.54k
    } else if (nxt_str_start(name, "cookie_", 7)) {
199
154
        ref->handler = nxt_http_var_cookie;
200
154
        ref->cacheable = 1;
201
202
154
        str.start = name->start + 7;
203
154
        str.length = name->length - 7;
204
205
154
        if (str.length == 0) {
206
1
            return NXT_ERROR;
207
1
        }
208
209
153
        hash = nxt_http_cookie_hash(mp, &str);
210
153
        if (nxt_slow_path(hash == -1)) {
211
0
            return NXT_ERROR;
212
0
        }
213
214
153
    } else {
215
136
        return NXT_ERROR;
216
136
    }
217
218
2.86k
    ref->data = nxt_var_field_new(mp, &str, (uint32_t) hash);
219
2.86k
    if (nxt_slow_path(ref->data == NULL)) {
220
0
        return NXT_ERROR;
221
0
    }
222
223
2.86k
    return NXT_OK;
224
2.86k
}
225
226
227
static nxt_int_t
228
nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
229
0
{
230
0
    nxt_str_set(str, "$");
231
232
0
    return NXT_OK;
233
0
}
234
235
236
static nxt_int_t
237
nxt_http_var_request_time(nxt_task_t *task, nxt_str_t *str, void *ctx,
238
    void *data)
239
0
{
240
0
    u_char              *p;
241
0
    nxt_msec_t          ms;
242
0
    nxt_nsec_t          now;
243
0
    nxt_http_request_t  *r;
244
245
0
    r = ctx;
246
247
0
    now = nxt_thread_monotonic_time(task->thread);
248
0
    ms = (now - r->start_time) / 1000000;
249
250
0
    str->start = nxt_mp_nget(r->mem_pool, NXT_TIME_T_LEN + 4);
251
0
    if (nxt_slow_path(str->start == NULL)) {
252
0
        return NXT_ERROR;
253
0
    }
254
255
0
    p = nxt_sprintf(str->start, str->start + NXT_TIME_T_LEN, "%T.%03M",
256
0
                    (nxt_time_t) ms / 1000, ms % 1000);
257
258
0
    str->length = p - str->start;
259
260
0
    return NXT_OK;
261
0
}
262
263
264
static nxt_int_t
265
nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
266
0
{
267
0
    nxt_http_request_t  *r;
268
269
0
    r = ctx;
270
271
0
    *str = *r->method;
272
273
0
    return NXT_OK;
274
0
}
275
276
277
static nxt_int_t
278
nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, void *ctx,
279
    void *data)
280
0
{
281
0
    nxt_http_request_t  *r;
282
283
0
    r = ctx;
284
285
0
    *str = r->target;
286
287
0
    return NXT_OK;
288
0
}
289
290
291
static nxt_int_t
292
nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
293
0
{
294
0
    nxt_http_request_t  *r;
295
296
0
    r = ctx;
297
298
0
    *str = *r->path;
299
300
0
    return NXT_OK;
301
0
}
302
303
304
static nxt_int_t
305
nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
306
0
{
307
0
    nxt_http_request_t  *r;
308
309
0
    r = ctx;
310
311
0
    *str = r->host;
312
313
0
    return NXT_OK;
314
0
}
315
316
317
static nxt_int_t
318
nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, void *ctx,
319
    void *data)
320
0
{
321
0
    nxt_http_request_t  *r;
322
323
0
    r = ctx;
324
325
0
    str->length = r->remote->address_length;
326
0
    str->start = nxt_sockaddr_address(r->remote);
327
328
0
    return NXT_OK;
329
0
}
330
331
332
static nxt_int_t
333
nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
334
0
{
335
0
    nxt_http_request_t  *r;
336
337
0
    static nxt_time_string_t  date_cache = {
338
0
        (nxt_atomic_uint_t) -1,
339
0
        nxt_http_log_date,
340
0
        "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
341
0
        nxt_length("31/Dec/1986:19:40:00 +0300"),
342
0
        NXT_THREAD_TIME_LOCAL,
343
0
        NXT_THREAD_TIME_SEC,
344
0
    };
345
346
0
    r = ctx;
347
348
0
    str->length = date_cache.size;
349
350
0
    str->start = nxt_mp_nget(r->mem_pool, str->length);
351
0
    if (nxt_slow_path(str->start == NULL)) {
352
0
        return NXT_ERROR;
353
0
    }
354
355
0
    str->length = nxt_thread_time_string(task->thread, &date_cache, str->start)
356
0
                  - str->start;
357
358
0
    return NXT_OK;
359
0
}
360
361
362
static u_char *
363
nxt_http_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
364
    size_t size, const char *format)
365
0
{
366
0
    u_char  sign;
367
0
    time_t  gmtoff;
368
369
0
    static const char * const  month[] = { "Jan", "Feb", "Mar", "Apr", "May",
370
0
                                           "Jun", "Jul", "Aug", "Sep", "Oct",
371
0
                                           "Nov", "Dec" };
372
373
0
    gmtoff = nxt_timezone(tm) / 60;
374
375
0
    if (gmtoff < 0) {
376
0
        gmtoff = -gmtoff;
377
0
        sign = '-';
378
379
0
    } else {
380
0
        sign = '+';
381
0
    }
382
383
0
    return nxt_sprintf(buf, buf + size, format,
384
0
                       tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
385
0
                       tm->tm_hour, tm->tm_min, tm->tm_sec,
386
0
                       sign, gmtoff / 60, gmtoff % 60);
387
0
}
388
389
390
static nxt_int_t
391
nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, void *ctx,
392
    void *data)
393
0
{
394
0
    nxt_http_request_t  *r;
395
396
0
    r = ctx;
397
398
0
    *str = r->request_line;
399
400
0
    return NXT_OK;
401
0
}
402
403
404
static nxt_int_t
405
nxt_http_var_request_id(nxt_task_t *task, nxt_str_t *str, void *ctx,
406
    void *data)
407
0
{
408
0
    nxt_random_t        *rand;
409
0
    nxt_http_request_t  *r;
410
411
0
    r = ctx;
412
413
0
    str->start = nxt_mp_nget(r->mem_pool, 32);
414
0
    if (nxt_slow_path(str->start == NULL)) {
415
0
        return NXT_ERROR;
416
0
    }
417
418
0
    str->length = 32;
419
420
0
    rand = &task->thread->random;
421
422
0
    (void) nxt_sprintf(str->start, str->start + 32, "%08xD%08xD%08xD%08xD",
423
0
                       nxt_random(rand), nxt_random(rand),
424
0
                       nxt_random(rand), nxt_random(rand));
425
426
0
    return NXT_OK;
427
0
}
428
429
430
static nxt_int_t
431
nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
432
    void *data)
433
0
{
434
0
    u_char              *p;
435
0
    nxt_off_t           bytes;
436
0
    nxt_http_request_t  *r;
437
438
0
    r = ctx;
439
440
0
    str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
441
0
    if (nxt_slow_path(str->start == NULL)) {
442
0
        return NXT_ERROR;
443
0
    }
444
445
0
    bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
446
447
0
    p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O", bytes);
448
449
0
    str->length = p - str->start;
450
451
0
    return NXT_OK;
452
0
}
453
454
455
static nxt_int_t
456
nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
457
0
{
458
0
    nxt_http_request_t  *r;
459
460
0
    r = ctx;
461
462
0
    str->start = nxt_mp_nget(r->mem_pool, 3);
463
0
    if (nxt_slow_path(str->start == NULL)) {
464
0
        return NXT_ERROR;
465
0
    }
466
467
0
    (void) nxt_sprintf(str->start, str->start + 3, "%03d", r->status);
468
469
0
    str->length = 3;
470
471
0
    return NXT_OK;
472
0
}
473
474
475
static nxt_int_t
476
nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
477
0
{
478
0
    nxt_http_request_t  *r;
479
480
0
    r = ctx;
481
482
0
    if (r->referer != NULL) {
483
0
        str->start = r->referer->value;
484
0
        str->length = r->referer->value_length;
485
486
0
    } else {
487
0
        nxt_str_null(str);
488
0
    }
489
490
0
    return NXT_OK;
491
0
}
492
493
494
static nxt_int_t
495
nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
496
0
{
497
0
    nxt_http_request_t  *r;
498
499
0
    r = ctx;
500
501
0
    if (r->user_agent != NULL) {
502
0
        str->start = r->user_agent->value;
503
0
        str->length = r->user_agent->value_length;
504
505
0
    } else {
506
0
        nxt_str_null(str);
507
0
    }
508
509
0
    return NXT_OK;
510
0
}
511
512
513
static nxt_int_t
514
nxt_http_var_response_connection(nxt_task_t *task, nxt_str_t *str, void *ctx,
515
    void *data)
516
0
{
517
0
    nxt_int_t           conn;
518
0
    nxt_bool_t          http11;
519
0
    nxt_h1proto_t       *h1p;
520
0
    nxt_http_request_t  *r;
521
522
0
    static const nxt_str_t  connection[3] = {
523
0
        nxt_string("close"),
524
0
        nxt_string("keep-alive"),
525
0
        nxt_string("Upgrade"),
526
0
    };
527
528
0
    r = ctx;
529
0
    h1p = r->proto.h1;
530
531
0
    conn = -1;
532
533
0
    if (r->websocket_handshake && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) {
534
0
        conn = 2;
535
536
0
    } else {
537
0
        http11 = nxt_h1p_is_http11(h1p);
538
539
0
        if (http11 ^ h1p->keepalive) {
540
0
            conn = h1p->keepalive;
541
0
        }
542
0
    }
543
544
0
    if (conn >= 0) {
545
0
        *str = connection[conn];
546
547
0
    } else {
548
0
        nxt_str_null(str);
549
0
    }
550
551
0
    return NXT_OK;
552
0
}
553
554
555
static nxt_int_t
556
nxt_http_var_response_content_length(nxt_task_t *task, nxt_str_t *str,
557
    void *ctx, void *data)
558
0
{
559
0
    u_char              *p;
560
0
    nxt_http_request_t  *r;
561
562
0
    r = ctx;
563
564
0
    if (r->resp.content_length != NULL) {
565
0
        str->length = r->resp.content_length->value_length;
566
0
        str->start = r->resp.content_length->value;
567
568
0
        return NXT_OK;
569
0
    }
570
571
0
    if (r->resp.content_length_n >= 0) {
572
0
        str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
573
0
        if (str->start == NULL) {
574
0
            return NXT_ERROR;
575
0
        }
576
577
0
        p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN,
578
0
                        "%O", r->resp.content_length_n);
579
580
0
        str->length = p - str->start;
581
582
0
        return NXT_OK;
583
0
    }
584
585
0
    nxt_str_null(str);
586
587
0
    return NXT_OK;
588
0
}
589
590
591
static nxt_int_t
592
nxt_http_var_response_transfer_encoding(nxt_task_t *task, nxt_str_t *str,
593
    void *ctx, void *data)
594
0
{
595
0
    nxt_http_request_t  *r;
596
597
0
    r = ctx;
598
599
0
    if (r->proto.h1->chunked) {
600
0
        nxt_str_set(str, "chunked");
601
602
0
    } else {
603
0
        nxt_str_null(str);
604
0
    }
605
606
0
    return NXT_OK;
607
0
}
608
609
610
static nxt_int_t
611
nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
612
0
{
613
0
    nxt_array_t            *args;
614
0
    nxt_var_field_t        *vf;
615
0
    nxt_http_request_t     *r;
616
0
    nxt_http_name_value_t  *nv, *start;
617
618
0
    r = ctx;
619
0
    vf = data;
620
621
0
    args = nxt_http_arguments_parse(r);
622
0
    if (nxt_slow_path(args == NULL)) {
623
0
        return NXT_ERROR;
624
0
    }
625
626
0
    start = args->elts;
627
0
    nv = start + args->nelts - 1;
628
629
0
    while (nv >= start) {
630
631
0
        if (vf->hash == nv->hash
632
0
            && vf->name.length == nv->name_length
633
0
            && memcmp(vf->name.start, nv->name, nv->name_length) == 0)
634
0
        {
635
0
            str->start = nv->value;
636
0
            str->length = nv->value_length;
637
638
0
            return NXT_OK;
639
0
        }
640
641
0
        nv--;
642
0
    }
643
644
0
    nxt_str_null(str);
645
646
0
    return NXT_OK;
647
0
}
648
649
650
static nxt_int_t
651
nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
652
0
{
653
0
    nxt_var_field_t     *vf;
654
0
    nxt_http_field_t    *f;
655
0
    nxt_http_request_t  *r;
656
657
0
    r = ctx;
658
0
    vf = data;
659
660
0
    nxt_list_each(f, r->fields) {
661
662
0
        if (vf->hash == f->hash
663
0
            && vf->name.length == f->name_length
664
0
            && nxt_strncasecmp(vf->name.start, f->name, f->name_length) == 0)
665
0
        {
666
0
            str->start = f->value;
667
0
            str->length = f->value_length;
668
669
0
            return NXT_OK;
670
0
        }
671
672
0
    } nxt_list_loop;
673
674
0
    nxt_str_null(str);
675
676
0
    return NXT_OK;
677
0
}
678
679
680
static nxt_int_t
681
nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
682
0
{
683
0
    nxt_array_t            *cookies;
684
0
    nxt_var_field_t        *vf;
685
0
    nxt_http_request_t     *r;
686
0
    nxt_http_name_value_t  *nv, *end;
687
688
0
    r = ctx;
689
0
    vf = data;
690
691
0
    cookies = nxt_http_cookies_parse(r);
692
0
    if (nxt_slow_path(cookies == NULL)) {
693
0
        return NXT_ERROR;
694
0
    }
695
696
0
    nv = cookies->elts;
697
0
    end = nv + cookies->nelts;
698
699
0
    while (nv < end) {
700
701
0
        if (vf->hash == nv->hash
702
0
            && vf->name.length == nv->name_length
703
0
            && memcmp(vf->name.start, nv->name, nv->name_length) == 0)
704
0
        {
705
0
            str->start = nv->value;
706
0
            str->length = nv->value_length;
707
708
0
            return NXT_OK;
709
0
        }
710
711
0
        nv++;
712
0
    }
713
714
0
    nxt_str_null(str);
715
716
0
    return NXT_OK;
717
0
}
718
719
720
static int
721
nxt_http_field_name_cmp(nxt_str_t *name, nxt_http_field_t *field)
722
0
{
723
0
    size_t  i;
724
0
    u_char  c1, c2;
725
726
0
    if (name->length != field->name_length) {
727
0
        return 1;
728
0
    }
729
730
0
    for (i = 0; i < name->length; i++) {
731
0
        c1 = name->start[i];
732
0
        c2 = field->name[i];
733
734
0
        if (c2 >= 'A' && c2 <= 'Z') {
735
0
            c2 |= 0x20;
736
737
0
        } else if (c2 == '-') {
738
0
            c2 = '_';
739
0
        }
740
741
0
        if (c1 != c2) {
742
0
            return 1;
743
0
        }
744
0
    }
745
746
0
    return 0;
747
0
}
748
749
750
static nxt_int_t
751
nxt_http_var_response_header(nxt_task_t *task, nxt_str_t *str, void *ctx,
752
    void *data)
753
0
{
754
0
    nxt_str_t           *name;
755
0
    nxt_http_field_t    *f;
756
0
    nxt_http_request_t  *r;
757
758
0
    r = ctx;
759
0
    name = data;
760
761
0
    nxt_list_each(f, r->resp.fields) {
762
763
0
        if (f->skip) {
764
0
            continue;
765
0
        }
766
767
0
        if (nxt_http_field_name_cmp(name, f) == 0) {
768
0
            str->start = f->value;
769
0
            str->length = f->value_length;
770
771
0
            return NXT_OK;
772
0
        }
773
774
0
    } nxt_list_loop;
775
776
0
    nxt_str_null(str);
777
778
0
    return NXT_OK;
779
0
}