fix extension
[nginx.git] / nginx / src / http / ngx_http_variables.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10 #include <nginx.h>
11
12
13 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
14     ngx_http_variable_value_t *v, uintptr_t data);
15 static void ngx_http_variable_request_set(ngx_http_request_t *r,
16     ngx_http_variable_value_t *v, uintptr_t data);
17 static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
18     ngx_http_variable_value_t *v, uintptr_t data);
19 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
20     ngx_http_variable_value_t *v, uintptr_t data);
21 static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
22     ngx_http_variable_value_t *v, uintptr_t data);
23
24 static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
25     ngx_http_variable_value_t *v, uintptr_t data);
26 static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
27     ngx_http_variable_value_t *v, uintptr_t data);
28 static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
29     ngx_http_variable_value_t *v, uintptr_t data);
30 static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
31     ngx_http_variable_value_t *v, uintptr_t data);
32
33 static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
34     ngx_http_variable_value_t *v, uintptr_t data);
35 static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
36     ngx_http_variable_value_t *v, uintptr_t data);
37 static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
38     ngx_http_variable_value_t *v, uintptr_t data);
39 static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
40     ngx_http_variable_value_t *v, uintptr_t data);
41 static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
42     ngx_http_variable_value_t *v, uintptr_t data);
43 static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
44     ngx_http_variable_value_t *v, uintptr_t data);
45 static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
46     ngx_http_variable_value_t *v, uintptr_t data);
47 static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
48     ngx_http_variable_value_t *v, uintptr_t data);
49 static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
50     ngx_http_variable_value_t *v, uintptr_t data);
51 static ngx_int_t ngx_http_variable_realpath_root(ngx_http_request_t *r,
52     ngx_http_variable_value_t *v, uintptr_t data);
53 static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r,
54     ngx_http_variable_value_t *v, uintptr_t data);
55 static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r,
56     ngx_http_variable_value_t *v, uintptr_t data);
57 static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r,
58     ngx_http_variable_value_t *v, uintptr_t data);
59 static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
60     ngx_http_variable_value_t *v, uintptr_t data);
61 static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
62     ngx_http_variable_value_t *v, uintptr_t data);
63 static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
64     ngx_http_variable_value_t *v, uintptr_t data);
65 static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r,
66     ngx_http_variable_value_t *v, uintptr_t data);
67
68 static ngx_int_t ngx_http_variable_sent_content_type(ngx_http_request_t *r,
69     ngx_http_variable_value_t *v, uintptr_t data);
70 static ngx_int_t ngx_http_variable_sent_content_length(ngx_http_request_t *r,
71     ngx_http_variable_value_t *v, uintptr_t data);
72 static ngx_int_t ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
73     ngx_http_variable_value_t *v, uintptr_t data);
74 static ngx_int_t ngx_http_variable_sent_connection(ngx_http_request_t *r,
75     ngx_http_variable_value_t *v, uintptr_t data);
76 static ngx_int_t ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
77     ngx_http_variable_value_t *v, uintptr_t data);
78 static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
79     ngx_http_variable_value_t *v, uintptr_t data);
80
81 static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r,
82     ngx_http_variable_value_t *v, uintptr_t data);
83 static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r,
84     ngx_http_variable_value_t *v, uintptr_t data);
85 static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r,
86     ngx_http_variable_value_t *v, uintptr_t data);
87
88 /*
89  * TODO:
90  *     Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
91  *                 REMOTE_HOST (null), REMOTE_IDENT (null),
92  *                 SERVER_SOFTWARE
93  *
94  *     Apache SSI: DOCUMENT_NAME, LAST_MODIFIED, USER_NAME (file owner)
95  */
96
97 /*
98  * the $http_host, $http_user_agent, $http_referer, $http_via,
99  * and $http_x_forwarded_for variables may be handled by generic
100  * ngx_http_variable_unknown_header_in(), but for perfomance reasons
101  * they are handled using dedicated entries
102  */
103
104 static ngx_http_variable_t  ngx_http_core_variables[] = {
105
106     { ngx_string("http_host"), NULL, ngx_http_variable_header,
107       offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
108
109     { ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
110       offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
111
112     { ngx_string("http_referer"), NULL, ngx_http_variable_header,
113       offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
114
115 #if (NGX_HTTP_GZIP)
116     { ngx_string("http_via"), NULL, ngx_http_variable_header,
117       offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
118 #endif
119
120 #if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
121     { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
122       offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
123 #endif
124
125     { ngx_string("http_cookie"), NULL, ngx_http_variable_headers,
126       offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
127
128     { ngx_string("content_length"), NULL, ngx_http_variable_header,
129       offsetof(ngx_http_request_t, headers_in.content_length), 0, 0 },
130
131     { ngx_string("content_type"), NULL, ngx_http_variable_header,
132       offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
133
134     { ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
135
136     { ngx_string("binary_remote_addr"), NULL,
137       ngx_http_variable_binary_remote_addr, 0, 0, 0 },
138
139     { ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
140
141     { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
142
143     { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
144
145     { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
146
147     { ngx_string("server_protocol"), NULL, ngx_http_variable_request,
148       offsetof(ngx_http_request_t, http_protocol), 0, 0 },
149
150     { ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
151
152     { ngx_string("request_uri"), NULL, ngx_http_variable_request,
153       offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
154
155     { ngx_string("uri"), NULL, ngx_http_variable_request,
156       offsetof(ngx_http_request_t, uri),
157       NGX_HTTP_VAR_NOCACHEABLE, 0 },
158
159     { ngx_string("document_uri"), NULL, ngx_http_variable_request,
160       offsetof(ngx_http_request_t, uri),
161       NGX_HTTP_VAR_NOCACHEABLE, 0 },
162
163     { ngx_string("request"), NULL, ngx_http_variable_request,
164       offsetof(ngx_http_request_t, request_line), 0, 0 },
165
166     { ngx_string("document_root"), NULL,
167       ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
168
169     { ngx_string("realpath_root"), NULL,
170       ngx_http_variable_realpath_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
171
172     { ngx_string("query_string"), NULL, ngx_http_variable_request,
173       offsetof(ngx_http_request_t, args),
174       NGX_HTTP_VAR_NOCACHEABLE, 0 },
175
176     { ngx_string("args"),
177       ngx_http_variable_request_set,
178       ngx_http_variable_request,
179       offsetof(ngx_http_request_t, args),
180       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
181
182     { ngx_string("is_args"), NULL, ngx_http_variable_is_args,
183       0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
184
185     { ngx_string("request_filename"), NULL,
186       ngx_http_variable_request_filename, 0,
187       NGX_HTTP_VAR_NOCACHEABLE, 0 },
188
189     { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
190
191     { ngx_string("request_method"), NULL,
192       ngx_http_variable_request_method, 0, 0, 0 },
193
194     { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
195
196     { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
197       0, 0, 0 },
198
199     { ngx_string("request_completion"), NULL,
200       ngx_http_variable_request_completion,
201       0, 0, 0 },
202
203     { ngx_string("request_body_file"), NULL,
204       ngx_http_variable_request_body_file,
205       0, 0, 0 },
206
207     { ngx_string("sent_http_content_type"), NULL,
208       ngx_http_variable_sent_content_type, 0, 0, 0 },
209
210     { ngx_string("sent_http_content_length"), NULL,
211       ngx_http_variable_sent_content_length, 0, 0, 0 },
212
213     { ngx_string("sent_http_last_modified"), NULL,
214       ngx_http_variable_sent_last_modified, 0, 0, 0 },
215
216     { ngx_string("sent_http_connection"), NULL,
217       ngx_http_variable_sent_connection, 0, 0, 0 },
218
219     { ngx_string("sent_http_keep_alive"), NULL,
220       ngx_http_variable_sent_keep_alive, 0, 0, 0 },
221
222     { ngx_string("sent_http_transfer_encoding"), NULL,
223       ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
224
225     { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
226       offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
227
228     { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
229       ngx_http_variable_request,
230       offsetof(ngx_http_request_t, limit_rate),
231       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
232
233     { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version,
234       0, 0, 0 },
235
236     { ngx_string("hostname"), NULL, ngx_http_variable_hostname,
237       0, 0, 0 },
238
239     { ngx_string("pid"), NULL, ngx_http_variable_pid,
240       0, 0, 0 },
241
242     { ngx_null_string, NULL, NULL, 0, 0, 0 }
243 };
244
245
246 ngx_http_variable_value_t  ngx_http_variable_null_value =
247     ngx_http_variable("");
248 ngx_http_variable_value_t  ngx_http_variable_true_value =
249     ngx_http_variable("1");
250
251
252 ngx_http_variable_t *
253 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
254 {
255     ngx_int_t                   rc;
256     ngx_uint_t                  i;
257     ngx_hash_key_t             *key;
258     ngx_http_variable_t        *v;
259     ngx_http_core_main_conf_t  *cmcf;
260
261     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
262
263     key = cmcf->variables_keys->keys.elts;
264     for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
265         if (name->len != key[i].key.len
266             || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
267         {
268             continue;
269         }
270
271         v = key[i].value;
272
273         if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
274             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
275                                "the duplicate \"%V\" variable", name);
276             return NULL;
277         }
278
279         return v;
280     }
281
282     v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
283     if (v == NULL) {
284         return NULL;
285     }
286
287     v->name.len = name->len;
288     v->name.data = ngx_pnalloc(cf->pool, name->len);
289     if (v->name.data == NULL) {
290         return NULL;
291     }
292
293     ngx_strlow(v->name.data, name->data, name->len);
294
295     v->set_handler = NULL;
296     v->get_handler = NULL;
297     v->data = 0;
298     v->flags = flags;
299     v->index = 0;
300
301     rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
302
303     if (rc == NGX_ERROR) {
304         return NULL;
305     }
306
307     if (rc == NGX_BUSY) {
308         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
309                            "conflicting variable name \"%V\"", name);
310         return NULL;
311     }
312
313     return v;
314 }
315
316
317 ngx_int_t
318 ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
319 {
320     ngx_uint_t                  i;
321     ngx_http_variable_t        *v;
322     ngx_http_core_main_conf_t  *cmcf;
323
324     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
325
326     v = cmcf->variables.elts;
327
328     if (v == NULL) {
329         if (ngx_array_init(&cmcf->variables, cf->pool, 4,
330                            sizeof(ngx_http_variable_t)) == NGX_ERROR)
331         {
332             return NGX_ERROR;
333         }
334
335     } else {
336         for (i = 0; i < cmcf->variables.nelts; i++) {
337             if (name->len != v[i].name.len
338                 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
339             {
340                 continue;
341             }
342
343             return i;
344         }
345     }
346
347     v = ngx_array_push(&cmcf->variables);
348     if (v == NULL) {
349         return NGX_ERROR;
350     }
351
352     v->name.len = name->len;
353     v->name.data = ngx_pnalloc(cf->pool, name->len);
354     if (v->name.data == NULL) {
355         return NGX_ERROR;
356     }
357
358     ngx_strlow(v->name.data, name->data, name->len);
359
360     v->set_handler = NULL;
361     v->get_handler = NULL;
362     v->data = 0;
363     v->flags = 0;
364     v->index = cmcf->variables.nelts - 1;
365
366     return cmcf->variables.nelts - 1;
367 }
368
369
370 ngx_http_variable_value_t *
371 ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
372 {
373     ngx_http_variable_t        *v;
374     ngx_http_core_main_conf_t  *cmcf;
375
376     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
377
378     if (cmcf->variables.nelts <= index) {
379         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
380                       "unknown variable index: %d", index);
381         return NULL;
382     }
383
384     if (r->variables[index].not_found || r->variables[index].valid) {
385         return &r->variables[index];
386     }
387
388     v = cmcf->variables.elts;
389
390     if (v[index].get_handler(r, &r->variables[index], v[index].data)
391         == NGX_OK)
392     {
393         if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
394             r->variables[index].no_cacheable = 1;
395         }
396
397         return &r->variables[index];
398     }
399
400     r->variables[index].valid = 0;
401     r->variables[index].not_found = 1;
402
403     return NULL;
404 }
405
406
407 ngx_http_variable_value_t *
408 ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
409 {
410     ngx_http_variable_value_t  *v;
411
412     v = &r->variables[index];
413
414     if (v->valid) {
415         if (!v->no_cacheable) {
416             return v;
417         }
418
419         v->valid = 0;
420         v->not_found = 0;
421     }
422
423     return ngx_http_get_indexed_variable(r, index);
424 }
425
426
427 ngx_http_variable_value_t *
428 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
429     ngx_uint_t nowarn)
430 {
431     ngx_http_variable_t        *v;
432     ngx_http_variable_value_t  *vv;
433     ngx_http_core_main_conf_t  *cmcf;
434
435     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
436
437     v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
438
439     if (v) {
440         if (v->flags & NGX_HTTP_VAR_INDEXED) {
441             return ngx_http_get_indexed_variable(r, v->index);
442
443         } else {
444
445             vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
446
447             if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
448                 return vv;
449             }
450
451             return NULL;
452         }
453     }
454
455     vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
456     if (vv == NULL) {
457         return NULL;
458     }
459
460     if (ngx_strncmp(name->data, "http_", 5) == 0) {
461
462         if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
463             == NGX_OK)
464         {
465             return vv;
466         }
467
468         return NULL;
469     }
470
471     if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
472
473         if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
474             == NGX_OK)
475         {
476             return vv;
477         }
478
479         return NULL;
480     }
481
482     if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) {
483
484         if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
485             == NGX_OK)
486         {
487             return vv;
488         }
489
490         return NULL;
491     }
492
493     if (ngx_strncmp(name->data, "cookie_", 7) == 0) {
494
495         if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
496             return vv;
497         }
498
499         return NULL;
500     }
501
502     if (ngx_strncmp(name->data, "arg_", 4) == 0) {
503
504         if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
505             return vv;
506         }
507
508         return NULL;
509     }
510
511     vv->not_found = 1;
512
513     if (nowarn == 0) {
514         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
515                       "unknown \"%V\" variable", name);
516     }
517
518     return vv;
519 }
520
521
522 static ngx_int_t
523 ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
524     uintptr_t data)
525 {
526     ngx_str_t  *s;
527
528     s = (ngx_str_t *) ((char *) r + data);
529
530     if (s->data) {
531         v->len = s->len;
532         v->valid = 1;
533         v->no_cacheable = 0;
534         v->not_found = 0;
535         v->data = s->data;
536
537     } else {
538         v->not_found = 1;
539     }
540
541     return NGX_OK;
542 }
543
544
545 static void
546 ngx_http_variable_request_set(ngx_http_request_t *r,
547     ngx_http_variable_value_t *v, uintptr_t data)
548 {
549     ngx_str_t  *s;
550
551     s = (ngx_str_t *) ((char *) r + data);
552
553     s->len = v->len;
554     s->data = v->data;
555 }
556
557
558 static void
559 ngx_http_variable_request_set_size(ngx_http_request_t *r,
560     ngx_http_variable_value_t *v, uintptr_t data)
561 {
562     ssize_t    s, *sp;
563     ngx_str_t  val;
564
565     val.len = v->len;
566     val.data = v->data;
567
568     s = ngx_parse_size(&val);
569
570     if (s == NGX_ERROR) {
571         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
572                       "invalid size \"%V\"", &val);
573         return;
574     }
575
576     sp = (ssize_t *) ((char *) r + data);
577
578     *sp = s;
579
580     return;
581 }
582
583
584 static ngx_int_t
585 ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
586     uintptr_t data)
587 {
588     ngx_table_elt_t  *h;
589
590     h = *(ngx_table_elt_t **) ((char *) r + data);
591
592     if (h) {
593         v->len = h->value.len;
594         v->valid = 1;
595         v->no_cacheable = 0;
596         v->not_found = 0;
597         v->data = h->value.data;
598
599     } else {
600         v->not_found = 1;
601     }
602
603     return NGX_OK;
604 }
605
606
607 static ngx_int_t
608 ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v,
609     uintptr_t data)
610 {
611     ssize_t            len;
612     u_char            *p;
613     ngx_uint_t         i, n;
614     ngx_array_t       *a;
615     ngx_table_elt_t  **h;
616
617     a = (ngx_array_t *) ((char *) r + data);
618
619     n = a->nelts;
620
621     if (n == 0) {
622         v->not_found = 1;
623         return NGX_OK;
624     }
625
626     v->valid = 1;
627     v->no_cacheable = 0;
628     v->not_found = 0;
629
630     h = a->elts;
631
632     if (n == 1) {
633         v->len = (*h)->value.len;
634         v->data = (*h)->value.data;
635
636         return NGX_OK;
637     }
638
639     len = - (ssize_t) (sizeof("; ") - 1);
640
641     for (i = 0; i < n; i++) {
642         len += h[i]->value.len + sizeof("; ") - 1;
643     }
644
645     p = ngx_pnalloc(r->pool, len);
646     if (p == NULL) {
647         return NGX_ERROR;
648     }
649
650     v->len = len;
651     v->data = p;
652
653     for (i = 0; /* void */ ; i++) {
654         p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
655
656         if (i == n - 1) {
657             break;
658         }
659
660         *p++ = ';'; *p++ = ' ';
661     }
662
663     return NGX_OK;
664 }
665
666
667 static ngx_int_t
668 ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
669     ngx_http_variable_value_t *v, uintptr_t data)
670 {
671     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
672                                             &r->headers_in.headers.part,
673                                             sizeof("http_") - 1);
674 }
675
676
677 static ngx_int_t
678 ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
679     ngx_http_variable_value_t *v, uintptr_t data)
680 {
681     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
682                                             &r->headers_out.headers.part,
683                                             sizeof("sent_http_") - 1);
684 }
685
686
687 ngx_int_t
688 ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
689     ngx_list_part_t *part, size_t prefix)
690 {
691     u_char            ch;
692     ngx_uint_t        i, n;
693     ngx_table_elt_t  *header;
694
695     header = part->elts;
696
697     for (i = 0; /* void */ ; i++) {
698
699         if (i >= part->nelts) {
700             if (part->next == NULL) {
701                 break;
702             }
703
704             part = part->next;
705             header = part->elts;
706             i = 0;
707         }
708
709         for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
710             ch = header[i].key.data[n];
711
712             if (ch >= 'A' && ch <= 'Z') {
713                 ch |= 0x20;
714
715             } else if (ch == '-') {
716                 ch = '_';
717             }
718
719             if (var->data[n + prefix] != ch) {
720                 break;
721             }
722         }
723
724         if (n + prefix == var->len && n == header[i].key.len) {
725             v->len = header[i].value.len;
726             v->valid = 1;
727             v->no_cacheable = 0;
728             v->not_found = 0;
729             v->data = header[i].value.data;
730
731             return NGX_OK;
732         }
733     }
734
735     v->not_found = 1;
736
737     return NGX_OK;
738 }
739
740
741 static ngx_int_t
742 ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
743     uintptr_t data)
744 {
745     ngx_str_t *name = (ngx_str_t *) data;
746
747     ngx_str_t  cookie, s;
748
749     s.len = name->len - (sizeof("cookie_") - 1);
750     s.data = name->data + sizeof("cookie_") - 1;
751
752     if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
753         == NGX_DECLINED)
754     {
755         v->not_found = 1;
756         return NGX_OK;
757     }
758
759     v->len = cookie.len;
760     v->valid = 1;
761     v->no_cacheable = 0;
762     v->not_found = 0;
763     v->data = cookie.data;
764
765     return NGX_OK;
766 }
767
768
769 static ngx_int_t
770 ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
771     uintptr_t data)
772 {
773     ngx_str_t *name = (ngx_str_t *) data;
774
775     u_char     *arg;
776     size_t      len;
777     ngx_str_t   value;
778
779     len = name->len - (sizeof("arg_") - 1);
780     arg = name->data + sizeof("arg_") - 1;
781
782     if (ngx_http_arg(r, arg, len, &value) != NGX_OK) {
783         v->not_found = 1;
784         return NGX_OK;
785     }
786
787     v->data = value.data;
788     v->len = value.len;
789     v->valid = 1;
790     v->no_cacheable = 0;
791     v->not_found = 0;
792
793     return NGX_OK;
794 }
795
796
797 static ngx_int_t
798 ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
799     uintptr_t data)
800 {
801     ngx_http_core_srv_conf_t  *cscf;
802
803     if (r->headers_in.server.len) {
804         v->len = r->headers_in.server.len;
805         v->data = r->headers_in.server.data;
806
807     } else {
808         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
809
810         v->len = cscf->server_name.len;
811         v->data = cscf->server_name.data;
812     }
813
814     v->valid = 1;
815     v->no_cacheable = 0;
816     v->not_found = 0;
817
818     return NGX_OK;
819 }
820
821
822 static ngx_int_t
823 ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
824     ngx_http_variable_value_t *v, uintptr_t data)
825 {
826     struct sockaddr_in  *sin;
827
828     /* AF_INET only */
829
830     sin = (struct sockaddr_in *) r->connection->sockaddr;
831
832     v->len = sizeof(in_addr_t);
833     v->valid = 1;
834     v->no_cacheable = 0;
835     v->not_found = 0;
836     v->data = (u_char *) &sin->sin_addr.s_addr;
837
838     return NGX_OK;
839 }
840
841
842 static ngx_int_t
843 ngx_http_variable_remote_addr(ngx_http_request_t *r,
844     ngx_http_variable_value_t *v, uintptr_t data)
845 {
846     v->len = r->connection->addr_text.len;
847     v->valid = 1;
848     v->no_cacheable = 0;
849     v->not_found = 0;
850     v->data = r->connection->addr_text.data;
851
852     return NGX_OK;
853 }
854
855
856 static ngx_int_t
857 ngx_http_variable_remote_port(ngx_http_request_t *r,
858     ngx_http_variable_value_t *v, uintptr_t data)
859 {
860     ngx_uint_t           port;
861     struct sockaddr_in  *sin;
862
863     v->len = 0;
864     v->valid = 1;
865     v->no_cacheable = 0;
866     v->not_found = 0;
867
868     v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
869     if (v->data == NULL) {
870         return NGX_ERROR;
871     }
872
873     /* AF_INET only */
874
875     if (r->connection->sockaddr->sa_family == AF_INET) {
876         sin = (struct sockaddr_in *) r->connection->sockaddr;
877
878         port = ntohs(sin->sin_port);
879
880         if (port > 0 && port < 65536) {
881             v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
882         }
883     }
884
885     return NGX_OK;
886 }
887
888
889 static ngx_int_t
890 ngx_http_variable_server_addr(ngx_http_request_t *r,
891     ngx_http_variable_value_t *v, uintptr_t data)
892 {
893     ngx_str_t  s;
894
895     s.data = ngx_pnalloc(r->pool, NGX_INET_ADDRSTRLEN);
896     if (s.data == NULL) {
897         return NGX_ERROR;
898     }
899
900     if (ngx_http_server_addr(r, &s) != NGX_OK) {
901         return NGX_ERROR;
902     }
903
904     v->len = s.len;
905     v->valid = 1;
906     v->no_cacheable = 0;
907     v->not_found = 0;
908     v->data = s.data;
909
910     return NGX_OK;
911 }
912
913
914 static ngx_int_t
915 ngx_http_variable_server_port(ngx_http_request_t *r,
916     ngx_http_variable_value_t *v, uintptr_t data)
917 {
918     v->len = r->port_text->len - 1;
919     v->valid = 1;
920     v->no_cacheable = 0;
921     v->not_found = 0;
922     v->data = r->port_text->data + 1;
923
924     return NGX_OK;
925 }
926
927
928 static ngx_int_t
929 ngx_http_variable_scheme(ngx_http_request_t *r,
930     ngx_http_variable_value_t *v, uintptr_t data)
931 {
932 #if (NGX_HTTP_SSL)
933
934     if (r->connection->ssl) {
935         v->len = sizeof("https") - 1;
936         v->valid = 1;
937         v->no_cacheable = 0;
938         v->not_found = 0;
939         v->data = (u_char *) "https";
940
941         return NGX_OK;
942     }
943
944 #endif
945
946     v->len = sizeof("http") - 1;
947     v->valid = 1;
948     v->no_cacheable = 0;
949     v->not_found = 0;
950     v->data = (u_char *) "http";
951
952     return NGX_OK;
953 }
954
955
956 static ngx_int_t
957 ngx_http_variable_is_args(ngx_http_request_t *r,
958     ngx_http_variable_value_t *v, uintptr_t data)
959 {
960     v->valid = 1;
961     v->no_cacheable = 0;
962     v->not_found = 0;
963
964     if (r->args.len == 0) {
965         v->len = 0;
966         v->data = NULL;
967         return NGX_OK;
968     }
969
970     v->len = 1;
971     v->data = (u_char *) "?";
972
973     return NGX_OK;
974 }
975
976
977 static ngx_int_t
978 ngx_http_variable_document_root(ngx_http_request_t *r,
979     ngx_http_variable_value_t *v, uintptr_t data)
980 {
981     ngx_str_t                  path;
982     ngx_http_core_loc_conf_t  *clcf;
983
984     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
985
986     if (clcf->root_lengths == NULL) {
987         v->len = clcf->root.len;
988         v->valid = 1;
989         v->no_cacheable = 0;
990         v->not_found = 0;
991         v->data = clcf->root.data;
992
993     } else {
994         if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 0,
995                                 clcf->root_values->elts)
996             == NULL)
997         {
998             return NGX_ERROR;
999         }
1000
1001         if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0)
1002             == NGX_ERROR)
1003         {
1004             return NGX_ERROR;
1005         }
1006
1007         v->len = path.len;
1008         v->valid = 1;
1009         v->no_cacheable = 0;
1010         v->not_found = 0;
1011         v->data = path.data;
1012     }
1013
1014     return NGX_OK;
1015 }
1016
1017
1018 static ngx_int_t
1019 ngx_http_variable_realpath_root(ngx_http_request_t *r,
1020     ngx_http_variable_value_t *v, uintptr_t data)
1021 {
1022     size_t                     len;
1023     ngx_str_t                  path;
1024     ngx_http_core_loc_conf_t  *clcf;
1025     u_char                     real[NGX_MAX_PATH];
1026
1027     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1028
1029     if (clcf->root_lengths == NULL) {
1030         path = clcf->root;
1031
1032     } else {
1033         if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 1,
1034                                 clcf->root_values->elts)
1035             == NULL)
1036         {
1037             return NGX_ERROR;
1038         }
1039
1040         path.data[path.len - 1] = '\0';
1041
1042         if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0)
1043             == NGX_ERROR)
1044         {
1045             return NGX_ERROR;
1046         }
1047     }
1048
1049     if (ngx_realpath(path.data, real) == NULL) {
1050         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
1051                       ngx_realpath_n " \"%s\" failed", path.data);
1052         return NGX_ERROR;
1053     }
1054
1055     len = ngx_strlen(real);
1056
1057     v->data = ngx_pnalloc(r->pool, len);
1058     if (v->data == NULL) {
1059         return NGX_ERROR;
1060     }
1061
1062     v->len = len;
1063     v->valid = 1;
1064     v->no_cacheable = 0;
1065     v->not_found = 0;
1066
1067     ngx_memcpy(v->data, real, len);
1068
1069     return NGX_OK;
1070 }
1071
1072
1073 static ngx_int_t
1074 ngx_http_variable_request_filename(ngx_http_request_t *r,
1075     ngx_http_variable_value_t *v, uintptr_t data)
1076 {
1077     size_t     root;
1078     ngx_str_t  path;
1079
1080     if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
1081         return NGX_ERROR;
1082     }
1083
1084     /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */
1085
1086     v->len = path.len - 1;
1087     v->valid = 1;
1088     v->no_cacheable = 0;
1089     v->not_found = 0;
1090     v->data = path.data;
1091
1092     return NGX_OK;
1093 }
1094
1095
1096 static ngx_int_t
1097 ngx_http_variable_server_name(ngx_http_request_t *r,
1098     ngx_http_variable_value_t *v, uintptr_t data)
1099 {
1100     ngx_http_core_srv_conf_t  *cscf;
1101
1102     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1103
1104     v->len = cscf->server_name.len;
1105     v->valid = 1;
1106     v->no_cacheable = 0;
1107     v->not_found = 0;
1108     v->data = cscf->server_name.data;
1109
1110     return NGX_OK;
1111 }
1112
1113
1114 static ngx_int_t
1115 ngx_http_variable_request_method(ngx_http_request_t *r,
1116     ngx_http_variable_value_t *v, uintptr_t data)
1117 {
1118     if (r->main->method_name.data) {
1119         v->len = r->main->method_name.len;
1120         v->valid = 1;
1121         v->no_cacheable = 0;
1122         v->not_found = 0;
1123         v->data = r->main->method_name.data;
1124
1125     } else {
1126         v->not_found = 1;
1127     }
1128
1129     return NGX_OK;
1130 }
1131
1132
1133 static ngx_int_t
1134 ngx_http_variable_remote_user(ngx_http_request_t *r,
1135     ngx_http_variable_value_t *v, uintptr_t data)
1136 {
1137     ngx_int_t  rc;
1138
1139     rc = ngx_http_auth_basic_user(r);
1140
1141     if (rc == NGX_DECLINED) {
1142         v->not_found = 1;
1143         return NGX_OK;
1144     }
1145
1146     if (rc == NGX_ERROR) {
1147         return NGX_ERROR;
1148     }
1149
1150     v->len = r->headers_in.user.len;
1151     v->valid = 1;
1152     v->no_cacheable = 0;
1153     v->not_found = 0;
1154     v->data = r->headers_in.user.data;
1155
1156     return NGX_OK;
1157 }
1158
1159
1160 static ngx_int_t
1161 ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
1162     ngx_http_variable_value_t *v, uintptr_t data)
1163 {
1164     off_t    sent;
1165     u_char  *p;
1166
1167     sent = r->connection->sent - r->header_size;
1168
1169     if (sent < 0) {
1170         sent = 0;
1171     }
1172
1173     p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1174     if (p == NULL) {
1175         return NGX_ERROR;
1176     }
1177
1178     v->len = ngx_sprintf(p, "%O", sent) - p;
1179     v->valid = 1;
1180     v->no_cacheable = 0;
1181     v->not_found = 0;
1182     v->data = p;
1183
1184     return NGX_OK;
1185 }
1186
1187
1188 static ngx_int_t
1189 ngx_http_variable_sent_content_type(ngx_http_request_t *r,
1190     ngx_http_variable_value_t *v, uintptr_t data)
1191 {
1192     if (r->headers_out.content_type.len) {
1193         v->len = r->headers_out.content_type.len;
1194         v->valid = 1;
1195         v->no_cacheable = 0;
1196         v->not_found = 0;
1197         v->data = r->headers_out.content_type.data;
1198
1199     } else {
1200         v->not_found = 1;
1201     }
1202
1203     return NGX_OK;
1204 }
1205
1206
1207 static ngx_int_t
1208 ngx_http_variable_sent_content_length(ngx_http_request_t *r,
1209     ngx_http_variable_value_t *v, uintptr_t data)
1210 {
1211     u_char  *p;
1212
1213     if (r->headers_out.content_length) {
1214         v->len = r->headers_out.content_length->value.len;
1215         v->valid = 1;
1216         v->no_cacheable = 0;
1217         v->not_found = 0;
1218         v->data = r->headers_out.content_length->value.data;
1219
1220         return NGX_OK;
1221     }
1222
1223     if (r->headers_out.content_length_n >= 0) {
1224         p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1225         if (p == NULL) {
1226             return NGX_ERROR;
1227         }
1228
1229         v->len = ngx_sprintf(p, "%O", r->headers_out.content_length_n) - p;
1230         v->valid = 1;
1231         v->no_cacheable = 0;
1232         v->not_found = 0;
1233         v->data = p;
1234
1235         return NGX_OK;
1236     }
1237
1238     v->not_found = 1;
1239
1240     return NGX_OK;
1241 }
1242
1243
1244 static ngx_int_t
1245 ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
1246     ngx_http_variable_value_t *v, uintptr_t data)
1247 {
1248     u_char  *p;
1249
1250     if (r->headers_out.last_modified) {
1251         v->len = r->headers_out.last_modified->value.len;
1252         v->valid = 1;
1253         v->no_cacheable = 0;
1254         v->not_found = 0;
1255         v->data = r->headers_out.last_modified->value.data;
1256
1257         return NGX_OK;
1258     }
1259
1260     if (r->headers_out.last_modified_time >= 0) {
1261         p = ngx_pnalloc(r->pool,
1262                    sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1);
1263         if (p == NULL) {
1264             return NGX_ERROR;
1265         }
1266
1267         v->len = ngx_http_time(p, r->headers_out.last_modified_time) - p;
1268         v->valid = 1;
1269         v->no_cacheable = 0;
1270         v->not_found = 0;
1271         v->data = p;
1272
1273         return NGX_OK;
1274     }
1275
1276     v->not_found = 1;
1277
1278     return NGX_OK;
1279 }
1280
1281
1282 static ngx_int_t
1283 ngx_http_variable_sent_connection(ngx_http_request_t *r,
1284     ngx_http_variable_value_t *v, uintptr_t data)
1285 {
1286     size_t   len;
1287     char    *p;
1288
1289     if (r->keepalive) {
1290         len = sizeof("keep-alive") - 1;
1291         p = "keep-alive";
1292
1293     } else {
1294         len = sizeof("close") - 1;
1295         p = "close";
1296     }
1297
1298     v->len = len;
1299     v->valid = 1;
1300     v->no_cacheable = 0;
1301     v->not_found = 0;
1302     v->data = (u_char *) p;
1303
1304     return NGX_OK;
1305 }
1306
1307
1308 static ngx_int_t
1309 ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
1310     ngx_http_variable_value_t *v, uintptr_t data)
1311 {
1312     u_char                    *p;
1313     ngx_http_core_loc_conf_t  *clcf;
1314
1315     if (r->keepalive) {
1316         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1317
1318         if (clcf->keepalive_header) {
1319
1320             p = ngx_pnalloc(r->pool, sizeof("timeout=") - 1 + NGX_TIME_T_LEN);
1321             if (p == NULL) {
1322                 return NGX_ERROR;
1323             }
1324
1325             v->len = ngx_sprintf(p, "timeout=%T", clcf->keepalive_header) - p;
1326             v->valid = 1;
1327             v->no_cacheable = 0;
1328             v->not_found = 0;
1329             v->data = p;
1330
1331             return NGX_OK;
1332         }
1333     }
1334
1335     v->not_found = 1;
1336
1337     return NGX_OK;
1338 }
1339
1340
1341 static ngx_int_t
1342 ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
1343     ngx_http_variable_value_t *v, uintptr_t data)
1344 {
1345     if (r->chunked) {
1346         v->len = sizeof("chunked") - 1;
1347         v->valid = 1;
1348         v->no_cacheable = 0;
1349         v->not_found = 0;
1350         v->data = (u_char *) "chunked";
1351
1352     } else {
1353         v->not_found = 1;
1354     }
1355
1356     return NGX_OK;
1357 }
1358
1359
1360 static ngx_int_t
1361 ngx_http_variable_request_completion(ngx_http_request_t *r,
1362     ngx_http_variable_value_t *v, uintptr_t data)
1363 {
1364     if (r->request_complete) {
1365         v->len = 2;
1366         v->valid = 1;
1367         v->no_cacheable = 0;
1368         v->not_found = 0;
1369         v->data = (u_char *) "OK";
1370
1371         return NGX_OK;
1372     }
1373
1374     v->len = 0;
1375     v->valid = 1;
1376     v->no_cacheable = 0;
1377     v->not_found = 0;
1378     v->data = (u_char *) "";
1379
1380     return NGX_OK;
1381 }
1382
1383
1384 static ngx_int_t
1385 ngx_http_variable_request_body_file(ngx_http_request_t *r,
1386     ngx_http_variable_value_t *v, uintptr_t data)
1387 {
1388     if (r->request_body == NULL || r->request_body->temp_file == NULL) {
1389         v->not_found = 1;
1390
1391         return NGX_OK;
1392     }
1393
1394     v->len = r->request_body->temp_file->file.name.len;
1395     v->valid = 1;
1396     v->no_cacheable = 0;
1397     v->not_found = 0;
1398     v->data = r->request_body->temp_file->file.name.data;
1399
1400     return NGX_OK;
1401 }
1402
1403
1404 static ngx_int_t
1405 ngx_http_variable_nginx_version(ngx_http_request_t *r,
1406     ngx_http_variable_value_t *v, uintptr_t data)
1407 {
1408     v->len = sizeof(NGINX_VERSION) - 1;
1409     v->valid = 1;
1410     v->no_cacheable = 0;
1411     v->not_found = 0;
1412     v->data = (u_char *) NGINX_VERSION;
1413
1414     return NGX_OK;
1415 }
1416
1417
1418 static ngx_int_t
1419 ngx_http_variable_hostname(ngx_http_request_t *r,
1420     ngx_http_variable_value_t *v, uintptr_t data)
1421 {
1422     v->len = ngx_cycle->hostname.len;
1423     v->valid = 1;
1424     v->no_cacheable = 0;
1425     v->not_found = 0;
1426     v->data = ngx_cycle->hostname.data;
1427
1428     return NGX_OK;
1429 }
1430
1431
1432 static ngx_int_t
1433 ngx_http_variable_pid(ngx_http_request_t *r,
1434     ngx_http_variable_value_t *v, uintptr_t data)
1435 {
1436     u_char  *p;
1437
1438     p = ngx_pnalloc(r->pool, NGX_INT64_LEN);
1439     if (p == NULL) {
1440         return NGX_ERROR;
1441     }
1442
1443     v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
1444     v->valid = 1;
1445     v->no_cacheable = 0;
1446     v->not_found = 0;
1447     v->data = p;
1448
1449     return NGX_OK;
1450 }
1451
1452
1453 ngx_int_t
1454 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
1455 {
1456     ngx_int_t                   rc;
1457     ngx_http_variable_t        *v;
1458     ngx_http_core_main_conf_t  *cmcf;
1459
1460     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1461
1462     cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
1463                                        sizeof(ngx_hash_keys_arrays_t));
1464     if (cmcf->variables_keys == NULL) {
1465         return NGX_ERROR;
1466     }
1467
1468     cmcf->variables_keys->pool = cf->pool;
1469     cmcf->variables_keys->temp_pool = cf->pool;
1470
1471     if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
1472         != NGX_OK)
1473     {
1474         return NGX_ERROR;
1475     }
1476
1477     for (v = ngx_http_core_variables; v->name.len; v++) {
1478         rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
1479                               NGX_HASH_READONLY_KEY);
1480
1481         if (rc == NGX_OK) {
1482             continue;
1483         }
1484
1485         if (rc == NGX_BUSY) {
1486             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1487                                "conflicting variable name \"%V\"", &v->name);
1488         }
1489
1490         return NGX_ERROR;
1491     }
1492
1493     return NGX_OK;
1494 }
1495
1496
1497 ngx_int_t
1498 ngx_http_variables_init_vars(ngx_conf_t *cf)
1499 {
1500     ngx_uint_t                  i, n;
1501     ngx_hash_key_t             *key;
1502     ngx_hash_init_t             hash;
1503     ngx_http_variable_t        *v, *av;
1504     ngx_http_core_main_conf_t  *cmcf;
1505
1506     /* set the handlers for the indexed http variables */
1507
1508     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1509
1510     v = cmcf->variables.elts;
1511     key = cmcf->variables_keys->keys.elts;
1512
1513     for (i = 0; i < cmcf->variables.nelts; i++) {
1514
1515         for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1516
1517             av = key[n].value;
1518
1519             if (av->get_handler
1520                 && v[i].name.len == key[n].key.len
1521                 && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
1522                    == 0)
1523             {
1524                 v[i].get_handler = av->get_handler;
1525                 v[i].data = av->data;
1526
1527                 av->flags |= NGX_HTTP_VAR_INDEXED;
1528                 v[i].flags = av->flags;
1529
1530                 av->index = i;
1531
1532                 goto next;
1533             }
1534         }
1535
1536         if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
1537             v[i].get_handler = ngx_http_variable_unknown_header_in;
1538             v[i].data = (uintptr_t) &v[i].name;
1539
1540             continue;
1541         }
1542
1543         if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) {
1544             v[i].get_handler = ngx_http_variable_unknown_header_out;
1545             v[i].data = (uintptr_t) &v[i].name;
1546
1547             continue;
1548         }
1549
1550         if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) {
1551             v[i].get_handler = ngx_http_upstream_header_variable;
1552             v[i].data = (uintptr_t) &v[i].name;
1553             v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
1554
1555             continue;
1556         }
1557
1558         if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) {
1559             v[i].get_handler = ngx_http_variable_cookie;
1560             v[i].data = (uintptr_t) &v[i].name;
1561
1562             continue;
1563         }
1564
1565         if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
1566             v[i].get_handler = ngx_http_variable_argument;
1567             v[i].data = (uintptr_t) &v[i].name;
1568
1569             continue;
1570         }
1571
1572         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1573                       "unknown \"%V\" variable", &v[i].name);
1574
1575         return NGX_ERROR;
1576
1577     next:
1578         continue;
1579     }
1580
1581
1582     for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1583         av = key[n].value;
1584
1585         if (av->flags & NGX_HTTP_VAR_NOHASH) {
1586             key[n].key.data = NULL;
1587         }
1588     }
1589
1590
1591     hash.hash = &cmcf->variables_hash;
1592     hash.key = ngx_hash_key;
1593     hash.max_size = cmcf->variables_hash_max_size;
1594     hash.bucket_size = cmcf->variables_hash_bucket_size;
1595     hash.name = "variables_hash";
1596     hash.pool = cf->pool;
1597     hash.temp_pool = NULL;
1598
1599     if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
1600                       cmcf->variables_keys->keys.nelts)
1601         != NGX_OK)
1602     {
1603         return NGX_ERROR;
1604     }
1605
1606     cmcf->variables_keys = NULL;
1607
1608     return NGX_OK;
1609 }
1610
1611
1612 void
1613 ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp,
1614     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1615 {
1616     ngx_rbtree_node_t               **p;
1617     ngx_http_variable_value_node_t   *vvn, *vvt;
1618
1619     for ( ;; ) {
1620
1621         vvn = (ngx_http_variable_value_node_t *) node;
1622         vvt = (ngx_http_variable_value_node_t *) temp;
1623
1624         if (node->key != temp->key) {
1625
1626             p = (node->key < temp->key) ? &temp->left : &temp->right;
1627
1628         } else if (vvn->len != vvt->len) {
1629
1630             p = (vvn->len < vvt->len) ? &temp->left : &temp->right;
1631
1632         } else {
1633             p = (ngx_memcmp(vvn->value->data, vvt->value->data, vvn->len) < 0)
1634                  ? &temp->left : &temp->right;
1635         }
1636
1637         if (*p == sentinel) {
1638             break;
1639         }
1640
1641         temp = *p;
1642     }
1643
1644     *p = node;
1645     node->parent = temp;
1646     node->left = sentinel;
1647     node->right = sentinel;
1648     ngx_rbt_red(node);
1649 }
1650
1651
1652 ngx_http_variable_value_t *
1653 ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val,
1654     uint32_t hash)
1655 {
1656     ngx_int_t                        rc;
1657     ngx_rbtree_node_t               *node, *sentinel;
1658     ngx_http_variable_value_node_t  *vvn;
1659
1660     node = rbtree->root;
1661     sentinel = rbtree->sentinel;
1662
1663     while (node != sentinel) {
1664
1665         vvn = (ngx_http_variable_value_node_t *) node;
1666
1667         if (hash != node->key) {
1668             node = (hash < node->key) ? node->left : node->right;
1669             continue;
1670         }
1671
1672         if (val->len != vvn->len) {
1673             node = (val->len < vvn->len) ? node->left : node->right;
1674             continue;
1675         }
1676
1677         rc = ngx_memcmp(val->data, vvn->value->data, val->len);
1678
1679         if (rc < 0) {
1680             node = node->left;
1681             continue;
1682         }
1683
1684         if (rc > 0) {
1685             node = node->right;
1686             continue;
1687         }
1688
1689         return vvn->value;
1690     }
1691
1692     return NULL;
1693 }