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