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 }