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