~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/ngx_http_variables.c

Version: ~ [ nginx-0.6.26 ] ~ [ nginx-0.5.35 ] ~ [ nginx-0.5.20 ] ~ [ nginx-0.5.19 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_event.h>
 10 #include <ngx_http.h>
 11 #include <nginx.h>
 12 
 13 
 14 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
 15     ngx_http_variable_value_t *v, uintptr_t data);
 16 static void ngx_http_variable_request_set(ngx_http_request_t *r,
 17     ngx_http_variable_value_t *v, uintptr_t data);
 18 static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
 19     ngx_http_variable_value_t *v, uintptr_t data);
 20 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
 21     ngx_http_variable_value_t *v, uintptr_t data);
 22 static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
 23     ngx_http_variable_value_t *v, uintptr_t data);
 24 
 25 static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
 26     ngx_http_variable_value_t *v, uintptr_t data);
 27 static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
 28     ngx_http_variable_value_t *v, uintptr_t data);
 29 
 30 static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
 31     ngx_http_variable_value_t *v, uintptr_t data);
 32 static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
 33     ngx_http_variable_value_t *v, uintptr_t data);
 34 static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
 35     ngx_http_variable_value_t *v, uintptr_t data);
 36 static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
 37     ngx_http_variable_value_t *v, uintptr_t data);
 38 static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
 39     ngx_http_variable_value_t *v, uintptr_t data);
 40 static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
 41     ngx_http_variable_value_t *v, uintptr_t data);
 42 static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
 43     ngx_http_variable_value_t *v, uintptr_t data);
 44 static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
 45     ngx_http_variable_value_t *v, uintptr_t data);
 46 static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
 47     ngx_http_variable_value_t *v, uintptr_t data);
 48 static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r,
 49     ngx_http_variable_value_t *v, uintptr_t data);
 50 static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r,
 51     ngx_http_variable_value_t *v, uintptr_t data);
 52 static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r,
 53     ngx_http_variable_value_t *v, uintptr_t data);
 54 static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
 55     ngx_http_variable_value_t *v, uintptr_t data);
 56 static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
 57     ngx_http_variable_value_t *v, uintptr_t data);
 58 static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
 59     ngx_http_variable_value_t *v, uintptr_t data);
 60 static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r,
 61     ngx_http_variable_value_t *v, uintptr_t data);
 62 
 63 static ngx_int_t ngx_http_variable_sent_content_type(ngx_http_request_t *r,
 64     ngx_http_variable_value_t *v, uintptr_t data);
 65 static ngx_int_t ngx_http_variable_sent_content_length(ngx_http_request_t *r,
 66     ngx_http_variable_value_t *v, uintptr_t data);
 67 static ngx_int_t ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
 68     ngx_http_variable_value_t *v, uintptr_t data);
 69 static ngx_int_t ngx_http_variable_sent_connection(ngx_http_request_t *r,
 70     ngx_http_variable_value_t *v, uintptr_t data);
 71 static ngx_int_t ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
 72     ngx_http_variable_value_t *v, uintptr_t data);
 73 static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
 74     ngx_http_variable_value_t *v, uintptr_t data);
 75 
 76 static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r,
 77     ngx_http_variable_value_t *v, uintptr_t data);
 78 
 79 /*
 80  * TODO:
 81  *     Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
 82  *                 REMOTE_HOST (null), REMOTE_IDENT (null),
 83  *                 SERVER_SOFTWARE
 84  *
 85  *     Apache SSI: DOCUMENT_NAME, LAST_MODIFIED, USER_NAME (file owner)
 86  */
 87 
 88 /*
 89  * the $http_host, $http_user_agent, $http_referer, $http_via,
 90  * and $http_x_forwarded_for variables may be handled by generic
 91  * ngx_http_variable_unknown_header_in(), but for perfomance reasons
 92  * they are handled using dedicated entries
 93  */
 94 
 95 static ngx_http_variable_t  ngx_http_core_variables[] = {
 96 
 97     { ngx_string("http_host"), NULL, ngx_http_variable_header,
 98       offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
 99 
100     { ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
101       offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
102 
103     { ngx_string("http_referer"), NULL, ngx_http_variable_header,
104       offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
105 
106 #if (NGX_HTTP_GZIP)
107     { ngx_string("http_via"), NULL, ngx_http_variable_header,
108       offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
109 #endif
110 
111 #if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
112     { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
113       offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
114 #endif
115 
116     { ngx_string("http_cookie"), NULL, ngx_http_variable_headers,
117       offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
118 
119     { ngx_string("content_length"), NULL, ngx_http_variable_header,
120       offsetof(ngx_http_request_t, headers_in.content_length), 0, 0 },
121 
122     { ngx_string("content_type"), NULL, ngx_http_variable_header,
123       offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
124 
125     { ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
126 
127     { ngx_string("binary_remote_addr"), NULL,
128       ngx_http_variable_binary_remote_addr, 0, 0, 0 },
129 
130     { ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
131 
132     { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
133 
134     { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
135 
136     { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
137 
138     { ngx_string("server_protocol"), NULL, ngx_http_variable_request,
139       offsetof(ngx_http_request_t, http_protocol), 0, 0 },
140 
141     { ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
142 
143     { ngx_string("request_uri"), NULL, ngx_http_variable_request,
144       offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
145 
146     { ngx_string("uri"), NULL, ngx_http_variable_request,
147       offsetof(ngx_http_request_t, uri),
148       NGX_HTTP_VAR_NOCACHEABLE, 0 },
149 
150     { ngx_string("document_uri"), NULL, ngx_http_variable_request,
151       offsetof(ngx_http_request_t, uri),
152       NGX_HTTP_VAR_NOCACHEABLE, 0 },
153 
154     { ngx_string("request"), NULL, ngx_http_variable_request,
155       offsetof(ngx_http_request_t, request_line), 0, 0 },
156 
157     { ngx_string("document_root"), NULL,
158       ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
159 
160     { ngx_string("query_string"), NULL, ngx_http_variable_request,
161       offsetof(ngx_http_request_t, args),
162       NGX_HTTP_VAR_NOCACHEABLE, 0 },
163 
164     { ngx_string("args"),
165       ngx_http_variable_request_set,
166       ngx_http_variable_request,
167       offsetof(ngx_http_request_t, args),
168       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
169 
170     { ngx_string("is_args"), NULL, ngx_http_variable_is_args,
171       0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
172 
173     { ngx_string("request_filename"), NULL,
174       ngx_http_variable_request_filename, 0,
175       NGX_HTTP_VAR_NOCACHEABLE, 0 },
176 
177     { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
178 
179     { ngx_string("request_method"), NULL,
180       ngx_http_variable_request_method, 0, 0, 0 },
181 
182     { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
183 
184     { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
185       0, 0, 0 },
186 
187     { ngx_string("request_completion"), NULL,
188       ngx_http_variable_request_completion,
189       0, 0, 0 },
190 
191     { ngx_string("request_body_file"), NULL,
192       ngx_http_variable_request_body_file,
193       0, 0, 0 },
194 
195     { ngx_string("sent_http_content_type"), NULL,
196       ngx_http_variable_sent_content_type, 0, 0, 0 },
197 
198     { ngx_string("sent_http_content_length"), NULL,
199       ngx_http_variable_sent_content_length, 0, 0, 0 },
200 
201     { ngx_string("sent_http_last_modified"), NULL,
202       ngx_http_variable_sent_last_modified, 0, 0, 0 },
203 
204     { ngx_string("sent_http_connection"), NULL,
205       ngx_http_variable_sent_connection, 0, 0, 0 },
206 
207     { ngx_string("sent_http_keep_alive"), NULL,
208       ngx_http_variable_sent_keep_alive, 0, 0, 0 },
209 
210     { ngx_string("sent_http_transfer_encoding"), NULL,
211       ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
212 
213     { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
214       offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
215 
216     { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
217       ngx_http_variable_request,
218       offsetof(ngx_http_request_t, limit_rate),
219       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
220 
221     { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version,
222       0, 0, 0 },
223 
224     { ngx_null_string, NULL, NULL, 0, 0, 0 }
225 };
226 
227 
228 ngx_http_variable_value_t  ngx_http_variable_null_value =
229     ngx_http_variable("");
230 ngx_http_variable_value_t  ngx_http_variable_true_value =
231     ngx_http_variable("1");
232 
233 
234 ngx_http_variable_t *
235 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
236 {
237     ngx_int_t                   rc;
238     ngx_uint_t                  i;
239     ngx_hash_key_t             *key;
240     ngx_http_variable_t        *v;
241     ngx_http_core_main_conf_t  *cmcf;
242 
243     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
244 
245     key = cmcf->variables_keys->keys.elts;
246     for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
247         if (name->len != key[i].key.len
248             || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
249         {
250             continue;
251         }
252 
253         v = key[i].value;
254 
255         if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
256             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
257                                "the duplicate \"%V\" variable", name);
258             return NULL;
259         }
260 
261         return v;
262     }
263 
264     v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
265     if (v == NULL) {
266         return NULL;
267     }
268 
269     v->name.len = name->len;
270     v->name.data = ngx_palloc(cf->pool, name->len);
271     if (v->name.data == NULL) {
272         return NULL;
273     }
274 
275     for (i = 0; i < name->len; i++) {
276         v->name.data[i] = ngx_tolower(name->data[i]);
277     }
278 
279     v->set_handler = NULL;
280     v->get_handler = NULL;
281     v->data = 0;
282     v->flags = flags;
283     v->index = 0;
284 
285     rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
286 
287     if (rc == NGX_ERROR) {
288         return NULL;
289     }
290 
291     if (rc == NGX_BUSY) {
292         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
293                            "conflicting variable name \"%V\"", name);
294         return NULL;
295     }
296 
297     return v;
298 }
299 
300 
301 ngx_int_t
302 ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
303 {
304     ngx_uint_t                  i;
305     ngx_http_variable_t        *v;
306     ngx_http_core_main_conf_t  *cmcf;
307 
308     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
309 
310     v = cmcf->variables.elts;
311 
312     if (v == NULL) {
313         if (ngx_array_init(&cmcf->variables, cf->pool, 4,
314                            sizeof(ngx_http_variable_t)) == NGX_ERROR)
315         {
316             return NGX_ERROR;
317         }
318 
319     } else {
320         for (i = 0; i < cmcf->variables.nelts; i++) {
321             if (name->len != v[i].name.len
322                 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
323             {
324                 continue;
325             }
326 
327             return i;
328         }
329     }
330 
331     v = ngx_array_push(&cmcf->variables);
332     if (v == NULL) {
333         return NGX_ERROR;
334     }
335 
336     v->name.len = name->len;
337     v->name.data = ngx_palloc(cf->pool, name->len);
338     if (v->name.data == NULL) {
339         return NGX_ERROR;
340     }
341 
342     for (i = 0; i < name->len; i++) {
343         v->name.data[i] = ngx_tolower(name->data[i]);
344     }
345 
346     v->set_handler = NULL;
347     v->get_handler = NULL;
348     v->data = 0;
349     v->flags = 0;
350     v->index = cmcf->variables.nelts - 1;
351 
352     return cmcf->variables.nelts - 1;
353 }
354 
355 
356 ngx_http_variable_value_t *
357 ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
358 {
359     ngx_http_variable_t        *v;
360     ngx_http_core_main_conf_t  *cmcf;
361 
362     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
363 
364     if (cmcf->variables.nelts <= index) {
365         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
366                       "unknown variable index: %d", index);
367         return NULL;
368     }
369 
370     if (r->variables[index].not_found || r->variables[index].valid) {
371         return &r->variables[index];
372     }
373 
374     v = cmcf->variables.elts;
375 
376     if (v[index].get_handler(r, &r->variables[index], v[index].data)
377         == NGX_OK)
378     {
379         if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
380             r->variables[index].no_cacheable = 1;
381         }
382 
383         return &r->variables[index];
384     }
385 
386     r->variables[index].valid = 0;
387     r->variables[index].not_found = 1;
388 
389     return NULL;
390 }
391 
392 
393 ngx_http_variable_value_t *
394 ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
395 {
396     ngx_http_variable_value_t  *v;
397 
398     v = &r->variables[index];
399 
400     if (v->valid) {
401         if (!v->no_cacheable) {
402             return v;
403         }
404 
405         v->valid = 0;
406         v->not_found = 0;
407     }
408 
409     return ngx_http_get_indexed_variable(r, index);
410 }
411 
412 
413 ngx_http_variable_value_t *
414 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
415     ngx_uint_t nowarn)
416 {
417     ngx_http_variable_t        *v;
418     ngx_http_variable_value_t  *vv;
419     ngx_http_core_main_conf_t  *cmcf;
420 
421     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
422 
423     v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
424 
425     if (v) {
426         if (v->flags & NGX_HTTP_VAR_INDEXED) {
427             return ngx_http_get_indexed_variable(r, v->index);
428 
429         } else {
430 
431             vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
432 
433             if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
434                 return vv;
435             }
436 
437             return NULL;
438         }
439     }
440 
441     vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
442     if (vv == NULL) {
443         return NULL;
444     }
445 
446     if (ngx_strncmp(name->data, "http_", 5) == 0) {
447 
448         if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
449             == NGX_OK)
450         {
451             return vv;
452         }
453 
454         return NULL;
455     }
456 
457     if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
458 
459         if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
460             == NGX_OK)
461         {
462             return vv;
463         }
464 
465         return NULL;
466     }
467 
468     if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) {
469 
470         if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
471             == NGX_OK)
472         {
473             return vv;
474         }
475 
476         return NULL;
477     }
478 
479     vv->not_found = 1;
480 
481     if (nowarn == 0) {
482         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
483                       "unknown \"%V\" variable", name);
484     }
485 
486     return vv;
487 }
488 
489 
490 static ngx_int_t
491 ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
492     uintptr_t data)
493 {
494     ngx_str_t  *s;
495 
496     s = (ngx_str_t *) ((char *) r + data);
497 
498     if (s->data) {
499         v->len = s->len;
500         v->valid = 1;
501         v->no_cacheable = 0;
502         v->not_found = 0;
503         v->data = s->data;
504 
505     } else {
506         v->not_found = 1;
507     }
508 
509     return NGX_OK;
510 }
511 
512 
513 static void
514 ngx_http_variable_request_set(ngx_http_request_t *r,
515     ngx_http_variable_value_t *v, uintptr_t data)
516 {
517     ngx_str_t  *s;
518 
519     s = (ngx_str_t *) ((char *) r + data);
520 
521     s->len = v->len;
522     s->data = v->data;
523 }
524 
525 
526 static void
527 ngx_http_variable_request_set_size(ngx_http_request_t *r,
528     ngx_http_variable_value_t *v, uintptr_t data)
529 {
530     ssize_t    s, *sp;
531     ngx_str_t  val;
532 
533     val.len = v->len;
534     val.data = v->data;
535 
536     s = ngx_parse_size(&val);
537 
538     if (s == NGX_ERROR) {
539         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
540                       "invalid size \"%V\"", &val);
541         return;
542     }
543 
544     sp = (ssize_t *) ((char *) r + data);
545 
546     *sp = s;
547 
548     return;
549 }
550 
551 
552 static ngx_int_t
553 ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
554     uintptr_t data)
555 {
556     ngx_table_elt_t  *h;
557 
558     h = *(ngx_table_elt_t **) ((char *) r + data);
559 
560     if (h) {
561         v->len = h->value.len;
562         v->valid = 1;
563         v->no_cacheable = 0;
564         v->not_found = 0;
565         v->data = h->value.data;
566 
567     } else {
568         v->not_found = 1;
569     }
570 
571     return NGX_OK;
572 }
573 
574 
575 static ngx_int_t
576 ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v,
577     uintptr_t data)
578 {
579     ssize_t            len;
580     u_char            *p;
581     ngx_uint_t         i, n;
582     ngx_array_t       *a;
583     ngx_table_elt_t  **h;
584 
585     a = (ngx_array_t *) ((char *) r + data);
586 
587     n = a->nelts;
588 
589     if (n == 0) {
590         v->not_found = 1;
591         return NGX_OK;
592     }
593 
594     v->valid = 1;
595     v->no_cacheable = 0;
596     v->not_found = 0;
597 
598     h = a->elts;
599 
600     if (n == 1) {
601         v->len = (*h)->value.len;
602         v->data = (*h)->value.data;
603 
604         return NGX_OK;
605     }
606 
607     len = - (ssize_t) (sizeof("; ") - 1);
608 
609     for (i = 0; i < n; i++) {
610         len += h[i]->value.len + sizeof("; ") - 1;
611     }
612 
613     p = ngx_palloc(r->pool, len);
614     if (p == NULL) {
615         return NGX_ERROR;
616     }
617 
618     v->len = len;
619     v->data = p;
620 
621     for (i = 0; /* void */ ; i++) {
622         p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
623 
624         if (i == n - 1) {
625             break;
626         }
627 
628         *p++ = ';'; *p++ = ' ';
629     }
630 
631     return NGX_OK;
632 }
633 
634 
635 static ngx_int_t
636 ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
637     ngx_http_variable_value_t *v, uintptr_t data)
638 {
639     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
640                                             &r->headers_in.headers.part,
641                                             sizeof("http_") - 1);
642 }
643 
644 
645 static ngx_int_t
646 ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
647     ngx_http_variable_value_t *v, uintptr_t data)
648 {
649     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
650                                             &r->headers_out.headers.part,
651                                             sizeof("sent_http_") - 1);
652 }
653 
654 
655 ngx_int_t
656 ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
657     ngx_list_part_t *part, size_t prefix)
658 {
659     u_char            ch;
660     ngx_uint_t        i, n;
661     ngx_table_elt_t  *header;
662 
663     header = part->elts;
664 
665     for (i = 0; /* void */ ; i++) {
666 
667         if (i >= part->nelts) {
668             if (part->next == NULL) {
669                 break;
670             }
671 
672             part = part->next;
673             header = part->elts;
674             i = 0;
675         }
676 
677         for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
678             ch = header[i].key.data[n];
679 
680             if (ch >= 'A' && ch <= 'Z') {
681                 ch |= 0x20;
682 
683             } else if (ch == '-') {
684                 ch = '_';
685             }
686 
687             if (var->data[n + prefix] != ch) {
688                 break;
689             }
690         }
691 
692         if (n + prefix == var->len && n == header[i].key.len) {
693             v->len = header[i].value.len;
694             v->valid = 1;
695             v->no_cacheable = 0;
696             v->not_found = 0;
697             v->data = header[i].value.data;
698 
699             return NGX_OK;
700         }
701     }
702 
703     v->not_found = 1;
704 
705     return NGX_OK;
706 }
707 
708 
709 static ngx_int_t
710 ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
711     uintptr_t data)
712 {
713     ngx_http_core_srv_conf_t  *cscf;
714 
715     if (r->host_start == NULL) {
716 
717         if (r->headers_in.host) {
718             v->len = r->headers_in.host_name_len;
719             v->data = r->headers_in.host->value.data;
720 
721         } else {
722             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
723 
724             v->len = cscf->server_name.len;
725             v->data = cscf->server_name.data;
726         }
727 
728     } else if (r->host_end) {
729         v->len = r->host_end - r->host_start;
730         v->data = r->host_start;
731 
732     } else {
733         v->not_found = 1;
734         return NGX_OK;
735     }
736 
737     v->valid = 1;
738     v->no_cacheable = 0;
739     v->not_found = 0;
740 
741     return NGX_OK;
742 }
743 
744 
745 static ngx_int_t
746 ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
747     ngx_http_variable_value_t *v, uintptr_t data)
748 {
749     struct sockaddr_in  *sin;
750 
751     /* AF_INET only */
752 
753     sin = (struct sockaddr_in *) r->connection->sockaddr;
754 
755     v->len = sizeof(in_addr_t);
756     v->valid = 1;
757     v->no_cacheable = 0;
758     v->not_found = 0;
759     v->data = (u_char *) &sin->sin_addr.s_addr;
760 
761     return NGX_OK;
762 }
763 
764 
765 static ngx_int_t
766 ngx_http_variable_remote_addr(ngx_http_request_t *r,
767     ngx_http_variable_value_t *v, uintptr_t data)
768 {
769     v->len = r->connection->addr_text.len;
770     v->valid = 1;
771     v->no_cacheable = 0;
772     v->not_found = 0;
773     v->data = r->connection->addr_text.data;
774 
775     return NGX_OK;
776 }
777 
778 
779 static ngx_int_t
780 ngx_http_variable_remote_port(ngx_http_request_t *r,
781     ngx_http_variable_value_t *v, uintptr_t data)
782 {
783     ngx_uint_t           port;
784     struct sockaddr_in  *sin;
785 
786     v->len = 0;
787     v->valid = 1;
788     v->no_cacheable = 0;
789     v->not_found = 0;
790 
791     v->data = ngx_palloc(r->pool, sizeof("65535") - 1);
792     if (v->data == NULL) {
793         return NGX_ERROR;
794     }
795 
796     /* AF_INET only */
797 
798     if (r->connection->sockaddr->sa_family == AF_INET) {
799         sin = (struct sockaddr_in *) r->connection->sockaddr;
800 
801         port = ntohs(sin->sin_port);
802 
803         if (port > 0 && port < 65536) {
804             v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
805         }
806     }
807 
808     return NGX_OK;
809 }
810 
811 
812 static ngx_int_t
813 ngx_http_variable_server_addr(ngx_http_request_t *r,
814     ngx_http_variable_value_t *v, uintptr_t data)
815 {
816     ngx_str_t  s;
817 
818     s.data = ngx_palloc(r->pool, INET_ADDRSTRLEN);
819     if (s.data == NULL) {
820         return NGX_ERROR;
821     }
822 
823     if (ngx_http_server_addr(r, &s) != NGX_OK) {
824         return NGX_ERROR;
825     }
826 
827     v->len = s.len;
828     v->valid = 1;
829     v->no_cacheable = 0;
830     v->not_found = 0;
831     v->data = s.data;
832 
833     return NGX_OK;
834 }
835 
836 
837 static ngx_int_t
838 ngx_http_variable_server_port(ngx_http_request_t *r,
839     ngx_http_variable_value_t *v, uintptr_t data)
840 {
841     v->len = r->port_text->len - 1;
842     v->valid = 1;
843     v->no_cacheable = 0;
844     v->not_found = 0;
845     v->data = r->port_text->data + 1;
846 
847     return NGX_OK;
848 }
849 
850 
851 static ngx_int_t
852 ngx_http_variable_scheme(ngx_http_request_t *r,
853     ngx_http_variable_value_t *v, uintptr_t data)
854 {
855 #if (NGX_HTTP_SSL)
856 
857     if (r->connection->ssl) {
858         v->len = sizeof("https") - 1;
859         v->valid = 1;
860         v->no_cacheable = 0;
861         v->not_found = 0;
862         v->data = (u_char *) "https";
863 
864         return NGX_OK;
865     }
866 
867 #endif
868 
869     v->len = sizeof("http") - 1;
870     v->valid = 1;
871     v->no_cacheable = 0;
872     v->not_found = 0;
873     v->data = (u_char *) "http";
874 
875     return NGX_OK;
876 }
877 
878 
879 static ngx_int_t
880 ngx_http_variable_is_args(ngx_http_request_t *r,
881     ngx_http_variable_value_t *v, uintptr_t data)
882 {
883     v->valid = 1;
884     v->no_cacheable = 0;
885     v->not_found = 0;
886 
887     if (r->args.len == 0) {
888         v->len = 0;
889         v->data = NULL;
890         return NGX_OK;
891     }
892 
893     v->len = 1;
894     v->data = (u_char *) "?";
895 
896     return NGX_OK;
897 }
898 
899 
900 static ngx_int_t
901 ngx_http_variable_document_root(ngx_http_request_t *r,
902     ngx_http_variable_value_t *v, uintptr_t data)
903 {
904     ngx_str_t                  path;
905     ngx_http_core_loc_conf_t  *clcf;
906 
907     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
908 
909     if (clcf->root_lengths == NULL) {
910         v->len = clcf->root.len;
911         v->valid = 1;
912         v->no_cacheable = 0;
913         v->not_found = 0;
914         v->data = clcf->root.data;
915 
916     } else {
917         if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 0,
918                                 clcf->root_values->elts)
919             == NULL)
920         {
921             return NGX_ERROR;
922         }
923 
924         if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0)
925             == NGX_ERROR)
926         {
927             return NGX_ERROR;
928         }
929 
930         v->len = path.len;
931         v->valid = 1;
932         v->no_cacheable = 0;
933         v->not_found = 0;
934         v->data = path.data;
935     }
936 
937     return NGX_OK;
938 }
939 
940 
941 static ngx_int_t
942 ngx_http_variable_request_filename(ngx_http_request_t *r,
943     ngx_http_variable_value_t *v, uintptr_t data)
944 {
945     size_t     root;
946     ngx_str_t  path;
947 
948     if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
949         return NGX_ERROR;
950     }
951 
952     /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */
953 
954     v->len = path.len - 1;
955     v->valid = 1;
956     v->no_cacheable = 0;
957     v->not_found = 0;
958     v->data = path.data;
959 
960     return NGX_OK;
961 }
962 
963 
964 static ngx_int_t
965 ngx_http_variable_server_name(ngx_http_request_t *r,
966     ngx_http_variable_value_t *v, uintptr_t data)
967 {
968     ngx_http_core_srv_conf_t  *cscf;
969 
970     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
971 
972     v->len = cscf->server_name.len;
973     v->valid = 1;
974     v->no_cacheable = 0;
975     v->not_found = 0;
976     v->data = cscf->server_name.data;
977 
978     return NGX_OK;
979 }