Annotation of embedaddon/nginx/src/http/ngx_http_variables.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
4: * Copyright (C) Nginx, Inc.
5: */
6:
7:
8: #include <ngx_config.h>
9: #include <ngx_core.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 ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
19: ngx_http_variable_value_t *v, uintptr_t data);
20: static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
21: ngx_http_variable_value_t *v, uintptr_t data);
22: static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
23: ngx_http_variable_value_t *v, uintptr_t data);
24:
25: static ngx_int_t ngx_http_variable_cookies(ngx_http_request_t *r,
26: ngx_http_variable_value_t *v, uintptr_t data);
27: static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
28: ngx_http_variable_value_t *v, uintptr_t data);
29: static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r,
30: ngx_http_variable_value_t *v, uintptr_t data, u_char sep);
31:
32: static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
33: ngx_http_variable_value_t *v, uintptr_t data);
34: static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
35: ngx_http_variable_value_t *v, uintptr_t data);
36: static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r,
37: ngx_http_variable_value_t *v, uintptr_t data);
38: static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
39: ngx_http_variable_value_t *v, uintptr_t data);
40: static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
41: ngx_http_variable_value_t *v, uintptr_t data);
42: #if (NGX_HAVE_TCP_INFO)
43: static ngx_int_t ngx_http_variable_tcpinfo(ngx_http_request_t *r,
44: ngx_http_variable_value_t *v, uintptr_t data);
45: #endif
46:
47: static ngx_int_t ngx_http_variable_content_length(ngx_http_request_t *r,
48: ngx_http_variable_value_t *v, uintptr_t data);
49: static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
50: ngx_http_variable_value_t *v, uintptr_t data);
51: static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
52: ngx_http_variable_value_t *v, uintptr_t data);
53: static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
54: ngx_http_variable_value_t *v, uintptr_t data);
55: static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
56: ngx_http_variable_value_t *v, uintptr_t data);
57: static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
58: ngx_http_variable_value_t *v, uintptr_t data);
59: static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
60: ngx_http_variable_value_t *v, uintptr_t data);
61: static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
62: ngx_http_variable_value_t *v, uintptr_t data);
63: static ngx_int_t ngx_http_variable_https(ngx_http_request_t *r,
64: ngx_http_variable_value_t *v, uintptr_t data);
65: static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
66: ngx_http_variable_value_t *v, uintptr_t data);
67: static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
68: ngx_http_variable_value_t *v, uintptr_t data);
69: static ngx_int_t ngx_http_variable_realpath_root(ngx_http_request_t *r,
70: ngx_http_variable_value_t *v, uintptr_t data);
71: static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r,
72: ngx_http_variable_value_t *v, uintptr_t data);
73: static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r,
74: ngx_http_variable_value_t *v, uintptr_t data);
75: static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r,
76: ngx_http_variable_value_t *v, uintptr_t data);
77: static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
78: ngx_http_variable_value_t *v, uintptr_t data);
79: static ngx_int_t ngx_http_variable_bytes_sent(ngx_http_request_t *r,
80: ngx_http_variable_value_t *v, uintptr_t data);
81: static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
82: ngx_http_variable_value_t *v, uintptr_t data);
83: static ngx_int_t ngx_http_variable_pipe(ngx_http_request_t *r,
84: ngx_http_variable_value_t *v, uintptr_t data);
85: static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
86: ngx_http_variable_value_t *v, uintptr_t data);
87: static ngx_int_t ngx_http_variable_request_body(ngx_http_request_t *r,
88: ngx_http_variable_value_t *v, uintptr_t data);
89: static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r,
90: ngx_http_variable_value_t *v, uintptr_t data);
91: static ngx_int_t ngx_http_variable_request_length(ngx_http_request_t *r,
92: ngx_http_variable_value_t *v, uintptr_t data);
93: static ngx_int_t ngx_http_variable_request_time(ngx_http_request_t *r,
94: ngx_http_variable_value_t *v, uintptr_t data);
95: static ngx_int_t ngx_http_variable_status(ngx_http_request_t *r,
96: ngx_http_variable_value_t *v, uintptr_t data);
97:
98: static ngx_int_t ngx_http_variable_sent_content_type(ngx_http_request_t *r,
99: ngx_http_variable_value_t *v, uintptr_t data);
100: static ngx_int_t ngx_http_variable_sent_content_length(ngx_http_request_t *r,
101: ngx_http_variable_value_t *v, uintptr_t data);
102: static ngx_int_t ngx_http_variable_sent_location(ngx_http_request_t *r,
103: ngx_http_variable_value_t *v, uintptr_t data);
104: static ngx_int_t ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
105: ngx_http_variable_value_t *v, uintptr_t data);
106: static ngx_int_t ngx_http_variable_sent_connection(ngx_http_request_t *r,
107: ngx_http_variable_value_t *v, uintptr_t data);
108: static ngx_int_t ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
109: ngx_http_variable_value_t *v, uintptr_t data);
110: static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
111: ngx_http_variable_value_t *v, uintptr_t data);
112:
113: static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r,
114: ngx_http_variable_value_t *v, uintptr_t data);
115: static ngx_int_t ngx_http_variable_connection_requests(ngx_http_request_t *r,
116: ngx_http_variable_value_t *v, uintptr_t data);
117:
118: static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r,
119: ngx_http_variable_value_t *v, uintptr_t data);
120: static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r,
121: ngx_http_variable_value_t *v, uintptr_t data);
122: static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r,
123: ngx_http_variable_value_t *v, uintptr_t data);
124: static ngx_int_t ngx_http_variable_msec(ngx_http_request_t *r,
125: ngx_http_variable_value_t *v, uintptr_t data);
126: static ngx_int_t ngx_http_variable_time_iso8601(ngx_http_request_t *r,
127: ngx_http_variable_value_t *v, uintptr_t data);
128: static ngx_int_t ngx_http_variable_time_local(ngx_http_request_t *r,
129: ngx_http_variable_value_t *v, uintptr_t data);
130:
131: /*
132: * TODO:
133: * Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
134: * REMOTE_HOST (null), REMOTE_IDENT (null),
135: * SERVER_SOFTWARE
136: *
137: * Apache SSI: DOCUMENT_NAME, LAST_MODIFIED, USER_NAME (file owner)
138: */
139:
140: /*
141: * the $http_host, $http_user_agent, $http_referer, and $http_via
142: * variables may be handled by generic
143: * ngx_http_variable_unknown_header_in(), but for performance reasons
144: * they are handled using dedicated entries
145: */
146:
147: static ngx_http_variable_t ngx_http_core_variables[] = {
148:
149: { ngx_string("http_host"), NULL, ngx_http_variable_header,
150: offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
151:
152: { ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
153: offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
154:
155: { ngx_string("http_referer"), NULL, ngx_http_variable_header,
156: offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
157:
158: #if (NGX_HTTP_GZIP)
159: { ngx_string("http_via"), NULL, ngx_http_variable_header,
160: offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
161: #endif
162:
163: #if (NGX_HTTP_X_FORWARDED_FOR)
164: { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers,
165: offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
166: #endif
167:
168: { ngx_string("http_cookie"), NULL, ngx_http_variable_cookies,
169: offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
170:
171: { ngx_string("content_length"), NULL, ngx_http_variable_content_length,
172: 0, 0, 0 },
173:
174: { ngx_string("content_type"), NULL, ngx_http_variable_header,
175: offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
176:
177: { ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
178:
179: { ngx_string("binary_remote_addr"), NULL,
180: ngx_http_variable_binary_remote_addr, 0, 0, 0 },
181:
182: { ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
183:
184: { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
185:
186: { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
187:
188: { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
189:
190: { ngx_string("server_protocol"), NULL, ngx_http_variable_request,
191: offsetof(ngx_http_request_t, http_protocol), 0, 0 },
192:
193: { ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
194:
195: { ngx_string("https"), NULL, ngx_http_variable_https, 0, 0, 0 },
196:
197: { ngx_string("request_uri"), NULL, ngx_http_variable_request,
198: offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
199:
200: { ngx_string("uri"), NULL, ngx_http_variable_request,
201: offsetof(ngx_http_request_t, uri),
202: NGX_HTTP_VAR_NOCACHEABLE, 0 },
203:
204: { ngx_string("document_uri"), NULL, ngx_http_variable_request,
205: offsetof(ngx_http_request_t, uri),
206: NGX_HTTP_VAR_NOCACHEABLE, 0 },
207:
208: { ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 },
209:
210: { ngx_string("document_root"), NULL,
211: ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
212:
213: { ngx_string("realpath_root"), NULL,
214: ngx_http_variable_realpath_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
215:
216: { ngx_string("query_string"), NULL, ngx_http_variable_request,
217: offsetof(ngx_http_request_t, args),
218: NGX_HTTP_VAR_NOCACHEABLE, 0 },
219:
220: { ngx_string("args"),
221: ngx_http_variable_request_set,
222: ngx_http_variable_request,
223: offsetof(ngx_http_request_t, args),
224: NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
225:
226: { ngx_string("is_args"), NULL, ngx_http_variable_is_args,
227: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
228:
229: { ngx_string("request_filename"), NULL,
230: ngx_http_variable_request_filename, 0,
231: NGX_HTTP_VAR_NOCACHEABLE, 0 },
232:
233: { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
234:
235: { ngx_string("request_method"), NULL,
236: ngx_http_variable_request_method, 0,
237: NGX_HTTP_VAR_NOCACHEABLE, 0 },
238:
239: { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
240:
241: { ngx_string("bytes_sent"), NULL, ngx_http_variable_bytes_sent,
242: 0, 0, 0 },
243:
244: { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
245: 0, 0, 0 },
246:
247: { ngx_string("pipe"), NULL, ngx_http_variable_pipe,
248: 0, 0, 0 },
249:
250: { ngx_string("request_completion"), NULL,
251: ngx_http_variable_request_completion,
252: 0, 0, 0 },
253:
254: { ngx_string("request_body"), NULL,
255: ngx_http_variable_request_body,
256: 0, 0, 0 },
257:
258: { ngx_string("request_body_file"), NULL,
259: ngx_http_variable_request_body_file,
260: 0, 0, 0 },
261:
262: { ngx_string("request_length"), NULL, ngx_http_variable_request_length,
263: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
264:
265: { ngx_string("request_time"), NULL, ngx_http_variable_request_time,
266: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
267:
268: { ngx_string("status"), NULL,
269: ngx_http_variable_status, 0,
270: NGX_HTTP_VAR_NOCACHEABLE, 0 },
271:
272: { ngx_string("sent_http_content_type"), NULL,
273: ngx_http_variable_sent_content_type, 0, 0, 0 },
274:
275: { ngx_string("sent_http_content_length"), NULL,
276: ngx_http_variable_sent_content_length, 0, 0, 0 },
277:
278: { ngx_string("sent_http_location"), NULL,
279: ngx_http_variable_sent_location, 0, 0, 0 },
280:
281: { ngx_string("sent_http_last_modified"), NULL,
282: ngx_http_variable_sent_last_modified, 0, 0, 0 },
283:
284: { ngx_string("sent_http_connection"), NULL,
285: ngx_http_variable_sent_connection, 0, 0, 0 },
286:
287: { ngx_string("sent_http_keep_alive"), NULL,
288: ngx_http_variable_sent_keep_alive, 0, 0, 0 },
289:
290: { ngx_string("sent_http_transfer_encoding"), NULL,
291: ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
292:
293: { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
294: offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
295:
296: { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
297: ngx_http_variable_request_get_size,
298: offsetof(ngx_http_request_t, limit_rate),
299: NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
300:
301: { ngx_string("connection"), NULL,
302: ngx_http_variable_connection, 0, 0, 0 },
303:
304: { ngx_string("connection_requests"), NULL,
305: ngx_http_variable_connection_requests, 0, 0, 0 },
306:
307: { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version,
308: 0, 0, 0 },
309:
310: { ngx_string("hostname"), NULL, ngx_http_variable_hostname,
311: 0, 0, 0 },
312:
313: { ngx_string("pid"), NULL, ngx_http_variable_pid,
314: 0, 0, 0 },
315:
316: { ngx_string("msec"), NULL, ngx_http_variable_msec,
317: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
318:
319: { ngx_string("time_iso8601"), NULL, ngx_http_variable_time_iso8601,
320: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
321:
322: { ngx_string("time_local"), NULL, ngx_http_variable_time_local,
323: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
324:
325: #if (NGX_HAVE_TCP_INFO)
326: { ngx_string("tcpinfo_rtt"), NULL, ngx_http_variable_tcpinfo,
327: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
328:
329: { ngx_string("tcpinfo_rttvar"), NULL, ngx_http_variable_tcpinfo,
330: 1, NGX_HTTP_VAR_NOCACHEABLE, 0 },
331:
332: { ngx_string("tcpinfo_snd_cwnd"), NULL, ngx_http_variable_tcpinfo,
333: 2, NGX_HTTP_VAR_NOCACHEABLE, 0 },
334:
335: { ngx_string("tcpinfo_rcv_space"), NULL, ngx_http_variable_tcpinfo,
336: 3, NGX_HTTP_VAR_NOCACHEABLE, 0 },
337: #endif
338:
339: { ngx_null_string, NULL, NULL, 0, 0, 0 }
340: };
341:
342:
343: ngx_http_variable_value_t ngx_http_variable_null_value =
344: ngx_http_variable("");
345: ngx_http_variable_value_t ngx_http_variable_true_value =
346: ngx_http_variable("1");
347:
348:
349: ngx_http_variable_t *
350: ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
351: {
352: ngx_int_t rc;
353: ngx_uint_t i;
354: ngx_hash_key_t *key;
355: ngx_http_variable_t *v;
356: ngx_http_core_main_conf_t *cmcf;
357:
358: if (name->len == 0) {
359: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
360: "invalid variable name \"$\"");
361: return NULL;
362: }
363:
364: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
365:
366: key = cmcf->variables_keys->keys.elts;
367: for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
368: if (name->len != key[i].key.len
369: || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
370: {
371: continue;
372: }
373:
374: v = key[i].value;
375:
376: if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
377: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
378: "the duplicate \"%V\" variable", name);
379: return NULL;
380: }
381:
382: return v;
383: }
384:
385: v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
386: if (v == NULL) {
387: return NULL;
388: }
389:
390: v->name.len = name->len;
391: v->name.data = ngx_pnalloc(cf->pool, name->len);
392: if (v->name.data == NULL) {
393: return NULL;
394: }
395:
396: ngx_strlow(v->name.data, name->data, name->len);
397:
398: v->set_handler = NULL;
399: v->get_handler = NULL;
400: v->data = 0;
401: v->flags = flags;
402: v->index = 0;
403:
404: rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
405:
406: if (rc == NGX_ERROR) {
407: return NULL;
408: }
409:
410: if (rc == NGX_BUSY) {
411: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
412: "conflicting variable name \"%V\"", name);
413: return NULL;
414: }
415:
416: return v;
417: }
418:
419:
420: ngx_int_t
421: ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
422: {
423: ngx_uint_t i;
424: ngx_http_variable_t *v;
425: ngx_http_core_main_conf_t *cmcf;
426:
427: if (name->len == 0) {
428: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
429: "invalid variable name \"$\"");
430: return NGX_ERROR;
431: }
432:
433: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
434:
435: v = cmcf->variables.elts;
436:
437: if (v == NULL) {
438: if (ngx_array_init(&cmcf->variables, cf->pool, 4,
439: sizeof(ngx_http_variable_t))
440: != NGX_OK)
441: {
442: return NGX_ERROR;
443: }
444:
445: } else {
446: for (i = 0; i < cmcf->variables.nelts; i++) {
447: if (name->len != v[i].name.len
448: || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
449: {
450: continue;
451: }
452:
453: return i;
454: }
455: }
456:
457: v = ngx_array_push(&cmcf->variables);
458: if (v == NULL) {
459: return NGX_ERROR;
460: }
461:
462: v->name.len = name->len;
463: v->name.data = ngx_pnalloc(cf->pool, name->len);
464: if (v->name.data == NULL) {
465: return NGX_ERROR;
466: }
467:
468: ngx_strlow(v->name.data, name->data, name->len);
469:
470: v->set_handler = NULL;
471: v->get_handler = NULL;
472: v->data = 0;
473: v->flags = 0;
474: v->index = cmcf->variables.nelts - 1;
475:
476: return v->index;
477: }
478:
479:
480: ngx_http_variable_value_t *
481: ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
482: {
483: ngx_http_variable_t *v;
484: ngx_http_core_main_conf_t *cmcf;
485:
486: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
487:
488: if (cmcf->variables.nelts <= index) {
489: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
490: "unknown variable index: %d", index);
491: return NULL;
492: }
493:
494: if (r->variables[index].not_found || r->variables[index].valid) {
495: return &r->variables[index];
496: }
497:
498: v = cmcf->variables.elts;
499:
500: if (v[index].get_handler(r, &r->variables[index], v[index].data)
501: == NGX_OK)
502: {
503: if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
504: r->variables[index].no_cacheable = 1;
505: }
506:
507: return &r->variables[index];
508: }
509:
510: r->variables[index].valid = 0;
511: r->variables[index].not_found = 1;
512:
513: return NULL;
514: }
515:
516:
517: ngx_http_variable_value_t *
518: ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
519: {
520: ngx_http_variable_value_t *v;
521:
522: v = &r->variables[index];
523:
524: if (v->valid || v->not_found) {
525: if (!v->no_cacheable) {
526: return v;
527: }
528:
529: v->valid = 0;
530: v->not_found = 0;
531: }
532:
533: return ngx_http_get_indexed_variable(r, index);
534: }
535:
536:
537: ngx_http_variable_value_t *
538: ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
539: {
540: ngx_http_variable_t *v;
541: ngx_http_variable_value_t *vv;
542: ngx_http_core_main_conf_t *cmcf;
543:
544: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
545:
546: v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
547:
548: if (v) {
549: if (v->flags & NGX_HTTP_VAR_INDEXED) {
550: return ngx_http_get_flushed_variable(r, v->index);
551:
552: } else {
553:
554: vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
555:
556: if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
557: return vv;
558: }
559:
560: return NULL;
561: }
562: }
563:
564: vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
565: if (vv == NULL) {
566: return NULL;
567: }
568:
569: if (ngx_strncmp(name->data, "http_", 5) == 0) {
570:
571: if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
572: == NGX_OK)
573: {
574: return vv;
575: }
576:
577: return NULL;
578: }
579:
580: if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
581:
582: if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
583: == NGX_OK)
584: {
585: return vv;
586: }
587:
588: return NULL;
589: }
590:
591: if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) {
592:
593: if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
594: == NGX_OK)
595: {
596: return vv;
597: }
598:
599: return NULL;
600: }
601:
602: if (ngx_strncmp(name->data, "cookie_", 7) == 0) {
603:
604: if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
605: return vv;
606: }
607:
608: return NULL;
609: }
610:
611: if (ngx_strncmp(name->data, "arg_", 4) == 0) {
612:
613: if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
614: return vv;
615: }
616:
617: return NULL;
618: }
619:
620: vv->not_found = 1;
621:
622: return vv;
623: }
624:
625:
626: static ngx_int_t
627: ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
628: uintptr_t data)
629: {
630: ngx_str_t *s;
631:
632: s = (ngx_str_t *) ((char *) r + data);
633:
634: if (s->data) {
635: v->len = s->len;
636: v->valid = 1;
637: v->no_cacheable = 0;
638: v->not_found = 0;
639: v->data = s->data;
640:
641: } else {
642: v->not_found = 1;
643: }
644:
645: return NGX_OK;
646: }
647:
648:
649: static void
650: ngx_http_variable_request_set(ngx_http_request_t *r,
651: ngx_http_variable_value_t *v, uintptr_t data)
652: {
653: ngx_str_t *s;
654:
655: s = (ngx_str_t *) ((char *) r + data);
656:
657: s->len = v->len;
658: s->data = v->data;
659: }
660:
661:
662: static ngx_int_t
663: ngx_http_variable_request_get_size(ngx_http_request_t *r,
664: ngx_http_variable_value_t *v, uintptr_t data)
665: {
666: size_t *sp;
667:
668: sp = (size_t *) ((char *) r + data);
669:
670: v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);
671: if (v->data == NULL) {
672: return NGX_ERROR;
673: }
674:
675: v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;
676: v->valid = 1;
677: v->no_cacheable = 0;
678: v->not_found = 0;
679:
680: return NGX_OK;
681: }
682:
683:
684: static void
685: ngx_http_variable_request_set_size(ngx_http_request_t *r,
686: ngx_http_variable_value_t *v, uintptr_t data)
687: {
688: ssize_t s, *sp;
689: ngx_str_t val;
690:
691: val.len = v->len;
692: val.data = v->data;
693:
694: s = ngx_parse_size(&val);
695:
696: if (s == NGX_ERROR) {
697: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
698: "invalid size \"%V\"", &val);
699: return;
700: }
701:
702: sp = (ssize_t *) ((char *) r + data);
703:
704: *sp = s;
705:
706: return;
707: }
708:
709:
710: static ngx_int_t
711: ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
712: uintptr_t data)
713: {
714: ngx_table_elt_t *h;
715:
716: h = *(ngx_table_elt_t **) ((char *) r + data);
717:
718: if (h) {
719: v->len = h->value.len;
720: v->valid = 1;
721: v->no_cacheable = 0;
722: v->not_found = 0;
723: v->data = h->value.data;
724:
725: } else {
726: v->not_found = 1;
727: }
728:
729: return NGX_OK;
730: }
731:
732:
733: static ngx_int_t
734: ngx_http_variable_cookies(ngx_http_request_t *r,
735: ngx_http_variable_value_t *v, uintptr_t data)
736: {
737: return ngx_http_variable_headers_internal(r, v, data, ';');
738: }
739:
740:
741: static ngx_int_t
742: ngx_http_variable_headers(ngx_http_request_t *r,
743: ngx_http_variable_value_t *v, uintptr_t data)
744: {
745: return ngx_http_variable_headers_internal(r, v, data, ',');
746: }
747:
748:
749: static ngx_int_t
750: ngx_http_variable_headers_internal(ngx_http_request_t *r,
751: ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
752: {
753: size_t len;
754: u_char *p, *end;
755: ngx_uint_t i, n;
756: ngx_array_t *a;
757: ngx_table_elt_t **h;
758:
759: a = (ngx_array_t *) ((char *) r + data);
760:
761: n = a->nelts;
762: h = a->elts;
763:
764: len = 0;
765:
766: for (i = 0; i < n; i++) {
767:
768: if (h[i]->hash == 0) {
769: continue;
770: }
771:
772: len += h[i]->value.len + 2;
773: }
774:
775: if (len == 0) {
776: v->not_found = 1;
777: return NGX_OK;
778: }
779:
780: len -= 2;
781:
782: v->valid = 1;
783: v->no_cacheable = 0;
784: v->not_found = 0;
785:
786: if (n == 1) {
787: v->len = (*h)->value.len;
788: v->data = (*h)->value.data;
789:
790: return NGX_OK;
791: }
792:
793: p = ngx_pnalloc(r->pool, len);
794: if (p == NULL) {
795: return NGX_ERROR;
796: }
797:
798: v->len = len;
799: v->data = p;
800:
801: end = p + len;
802:
803: for (i = 0; /* void */ ; i++) {
804:
805: if (h[i]->hash == 0) {
806: continue;
807: }
808:
809: p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
810:
811: if (p == end) {
812: break;
813: }
814:
815: *p++ = sep; *p++ = ' ';
816: }
817:
818: return NGX_OK;
819: }
820:
821:
822: static ngx_int_t
823: ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
824: ngx_http_variable_value_t *v, uintptr_t data)
825: {
826: return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
827: &r->headers_in.headers.part,
828: sizeof("http_") - 1);
829: }
830:
831:
832: static ngx_int_t
833: ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
834: ngx_http_variable_value_t *v, uintptr_t data)
835: {
836: return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
837: &r->headers_out.headers.part,
838: sizeof("sent_http_") - 1);
839: }
840:
841:
842: ngx_int_t
843: ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
844: ngx_list_part_t *part, size_t prefix)
845: {
846: u_char ch;
847: ngx_uint_t i, n;
848: ngx_table_elt_t *header;
849:
850: header = part->elts;
851:
852: for (i = 0; /* void */ ; i++) {
853:
854: if (i >= part->nelts) {
855: if (part->next == NULL) {
856: break;
857: }
858:
859: part = part->next;
860: header = part->elts;
861: i = 0;
862: }
863:
864: if (header[i].hash == 0) {
865: continue;
866: }
867:
868: for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
869: ch = header[i].key.data[n];
870:
871: if (ch >= 'A' && ch <= 'Z') {
872: ch |= 0x20;
873:
874: } else if (ch == '-') {
875: ch = '_';
876: }
877:
878: if (var->data[n + prefix] != ch) {
879: break;
880: }
881: }
882:
883: if (n + prefix == var->len && n == header[i].key.len) {
884: v->len = header[i].value.len;
885: v->valid = 1;
886: v->no_cacheable = 0;
887: v->not_found = 0;
888: v->data = header[i].value.data;
889:
890: return NGX_OK;
891: }
892: }
893:
894: v->not_found = 1;
895:
896: return NGX_OK;
897: }
898:
899:
900: static ngx_int_t
901: ngx_http_variable_request_line(ngx_http_request_t *r,
902: ngx_http_variable_value_t *v, uintptr_t data)
903: {
904: u_char *p, *s;
905:
906: s = r->request_line.data;
907:
908: if (s == NULL) {
909: s = r->request_start;
910:
911: if (s == NULL) {
912: v->not_found = 1;
913: return NGX_OK;
914: }
915:
916: for (p = s; p < r->header_in->last; p++) {
917: if (*p == CR || *p == LF) {
918: break;
919: }
920: }
921:
922: r->request_line.len = p - s;
923: r->request_line.data = s;
924: }
925:
926: v->len = r->request_line.len;
927: v->valid = 1;
928: v->no_cacheable = 0;
929: v->not_found = 0;
930: v->data = s;
931:
932: return NGX_OK;
933: }
934:
935:
936: static ngx_int_t
937: ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
938: uintptr_t data)
939: {
940: ngx_str_t *name = (ngx_str_t *) data;
941:
942: ngx_str_t cookie, s;
943:
944: s.len = name->len - (sizeof("cookie_") - 1);
945: s.data = name->data + sizeof("cookie_") - 1;
946:
947: if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
948: == NGX_DECLINED)
949: {
950: v->not_found = 1;
951: return NGX_OK;
952: }
953:
954: v->len = cookie.len;
955: v->valid = 1;
956: v->no_cacheable = 0;
957: v->not_found = 0;
958: v->data = cookie.data;
959:
960: return NGX_OK;
961: }
962:
963:
964: static ngx_int_t
965: ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
966: uintptr_t data)
967: {
968: ngx_str_t *name = (ngx_str_t *) data;
969:
970: u_char *arg;
971: size_t len;
972: ngx_str_t value;
973:
974: len = name->len - (sizeof("arg_") - 1);
975: arg = name->data + sizeof("arg_") - 1;
976:
977: if (ngx_http_arg(r, arg, len, &value) != NGX_OK) {
978: v->not_found = 1;
979: return NGX_OK;
980: }
981:
982: v->data = value.data;
983: v->len = value.len;
984: v->valid = 1;
985: v->no_cacheable = 0;
986: v->not_found = 0;
987:
988: return NGX_OK;
989: }
990:
991:
992: #if (NGX_HAVE_TCP_INFO)
993:
994: static ngx_int_t
995: ngx_http_variable_tcpinfo(ngx_http_request_t *r, ngx_http_variable_value_t *v,
996: uintptr_t data)
997: {
998: struct tcp_info ti;
999: socklen_t len;
1000: uint32_t value;
1001:
1002: len = sizeof(struct tcp_info);
1003: if (getsockopt(r->connection->fd, IPPROTO_TCP, TCP_INFO, &ti, &len) == -1) {
1004: v->not_found = 1;
1005: return NGX_OK;
1006: }
1007:
1008: v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN);
1009: if (v->data == NULL) {
1010: return NGX_ERROR;
1011: }
1012:
1013: switch (data) {
1014: case 0:
1015: value = ti.tcpi_rtt;
1016: break;
1017:
1018: case 1:
1019: value = ti.tcpi_rttvar;
1020: break;
1021:
1022: case 2:
1023: value = ti.tcpi_snd_cwnd;
1024: break;
1025:
1026: case 3:
1027: value = ti.tcpi_rcv_space;
1028: break;
1029:
1030: /* suppress warning */
1031: default:
1032: value = 0;
1033: break;
1034: }
1035:
1036: v->len = ngx_sprintf(v->data, "%uD", value) - v->data;
1037: v->valid = 1;
1038: v->no_cacheable = 0;
1039: v->not_found = 0;
1040:
1041: return NGX_OK;
1042: }
1043:
1044: #endif
1045:
1046:
1047: static ngx_int_t
1048: ngx_http_variable_content_length(ngx_http_request_t *r,
1049: ngx_http_variable_value_t *v, uintptr_t data)
1050: {
1051: u_char *p;
1052:
1053: if (r->headers_in.content_length) {
1054: v->len = r->headers_in.content_length->value.len;
1055: v->data = r->headers_in.content_length->value.data;
1056: v->valid = 1;
1057: v->no_cacheable = 0;
1058: v->not_found = 0;
1059:
1060: } else if (r->headers_in.content_length_n >= 0) {
1061: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1062: if (p == NULL) {
1063: return NGX_ERROR;
1064: }
1065:
1066: v->len = ngx_sprintf(p, "%O", r->headers_in.content_length_n) - p;
1067: v->data = p;
1068: v->valid = 1;
1069: v->no_cacheable = 0;
1070: v->not_found = 0;
1071:
1072: } else {
1073: v->not_found = 1;
1074: }
1075:
1076: return NGX_OK;
1077: }
1078:
1079:
1080: static ngx_int_t
1081: ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
1082: uintptr_t data)
1083: {
1084: ngx_http_core_srv_conf_t *cscf;
1085:
1086: if (r->headers_in.server.len) {
1087: v->len = r->headers_in.server.len;
1088: v->data = r->headers_in.server.data;
1089:
1090: } else {
1091: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1092:
1093: v->len = cscf->server_name.len;
1094: v->data = cscf->server_name.data;
1095: }
1096:
1097: v->valid = 1;
1098: v->no_cacheable = 0;
1099: v->not_found = 0;
1100:
1101: return NGX_OK;
1102: }
1103:
1104:
1105: static ngx_int_t
1106: ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
1107: ngx_http_variable_value_t *v, uintptr_t data)
1108: {
1109: struct sockaddr_in *sin;
1110: #if (NGX_HAVE_INET6)
1111: struct sockaddr_in6 *sin6;
1112: #endif
1113:
1114: switch (r->connection->sockaddr->sa_family) {
1115:
1116: #if (NGX_HAVE_INET6)
1117: case AF_INET6:
1118: sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
1119:
1120: v->len = sizeof(struct in6_addr);
1121: v->valid = 1;
1122: v->no_cacheable = 0;
1123: v->not_found = 0;
1124: v->data = sin6->sin6_addr.s6_addr;
1125:
1126: break;
1127: #endif
1128:
1129: default: /* AF_INET */
1130: sin = (struct sockaddr_in *) r->connection->sockaddr;
1131:
1132: v->len = sizeof(in_addr_t);
1133: v->valid = 1;
1134: v->no_cacheable = 0;
1135: v->not_found = 0;
1136: v->data = (u_char *) &sin->sin_addr;
1137:
1138: break;
1139: }
1140:
1141: return NGX_OK;
1142: }
1143:
1144:
1145: static ngx_int_t
1146: ngx_http_variable_remote_addr(ngx_http_request_t *r,
1147: ngx_http_variable_value_t *v, uintptr_t data)
1148: {
1149: v->len = r->connection->addr_text.len;
1150: v->valid = 1;
1151: v->no_cacheable = 0;
1152: v->not_found = 0;
1153: v->data = r->connection->addr_text.data;
1154:
1155: return NGX_OK;
1156: }
1157:
1158:
1159: static ngx_int_t
1160: ngx_http_variable_remote_port(ngx_http_request_t *r,
1161: ngx_http_variable_value_t *v, uintptr_t data)
1162: {
1163: ngx_uint_t port;
1164: struct sockaddr_in *sin;
1165: #if (NGX_HAVE_INET6)
1166: struct sockaddr_in6 *sin6;
1167: #endif
1168:
1169: v->len = 0;
1170: v->valid = 1;
1171: v->no_cacheable = 0;
1172: v->not_found = 0;
1173:
1174: v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
1175: if (v->data == NULL) {
1176: return NGX_ERROR;
1177: }
1178:
1179: switch (r->connection->sockaddr->sa_family) {
1180:
1181: #if (NGX_HAVE_INET6)
1182: case AF_INET6:
1183: sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
1184: port = ntohs(sin6->sin6_port);
1185: break;
1186: #endif
1187:
1188: default: /* AF_INET */
1189: sin = (struct sockaddr_in *) r->connection->sockaddr;
1190: port = ntohs(sin->sin_port);
1191: break;
1192: }
1193:
1194: if (port > 0 && port < 65536) {
1195: v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
1196: }
1197:
1198: return NGX_OK;
1199: }
1200:
1201:
1202: static ngx_int_t
1203: ngx_http_variable_server_addr(ngx_http_request_t *r,
1204: ngx_http_variable_value_t *v, uintptr_t data)
1205: {
1206: ngx_str_t s;
1207: u_char addr[NGX_SOCKADDR_STRLEN];
1208:
1209: s.len = NGX_SOCKADDR_STRLEN;
1210: s.data = addr;
1211:
1212: if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) {
1213: return NGX_ERROR;
1214: }
1215:
1216: s.data = ngx_pnalloc(r->pool, s.len);
1217: if (s.data == NULL) {
1218: return NGX_ERROR;
1219: }
1220:
1221: ngx_memcpy(s.data, addr, s.len);
1222:
1223: v->len = s.len;
1224: v->valid = 1;
1225: v->no_cacheable = 0;
1226: v->not_found = 0;
1227: v->data = s.data;
1228:
1229: return NGX_OK;
1230: }
1231:
1232:
1233: static ngx_int_t
1234: ngx_http_variable_server_port(ngx_http_request_t *r,
1235: ngx_http_variable_value_t *v, uintptr_t data)
1236: {
1237: ngx_uint_t port;
1238: struct sockaddr_in *sin;
1239: #if (NGX_HAVE_INET6)
1240: struct sockaddr_in6 *sin6;
1241: #endif
1242:
1243: v->len = 0;
1244: v->valid = 1;
1245: v->no_cacheable = 0;
1246: v->not_found = 0;
1247:
1248: if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) {
1249: return NGX_ERROR;
1250: }
1251:
1252: v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
1253: if (v->data == NULL) {
1254: return NGX_ERROR;
1255: }
1256:
1257: switch (r->connection->local_sockaddr->sa_family) {
1258:
1259: #if (NGX_HAVE_INET6)
1260: case AF_INET6:
1261: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr;
1262: port = ntohs(sin6->sin6_port);
1263: break;
1264: #endif
1265:
1266: default: /* AF_INET */
1267: sin = (struct sockaddr_in *) r->connection->local_sockaddr;
1268: port = ntohs(sin->sin_port);
1269: break;
1270: }
1271:
1272: if (port > 0 && port < 65536) {
1273: v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
1274: }
1275:
1276: return NGX_OK;
1277: }
1278:
1279:
1280: static ngx_int_t
1281: ngx_http_variable_scheme(ngx_http_request_t *r,
1282: ngx_http_variable_value_t *v, uintptr_t data)
1283: {
1284: #if (NGX_HTTP_SSL)
1285:
1286: if (r->connection->ssl) {
1287: v->len = sizeof("https") - 1;
1288: v->valid = 1;
1289: v->no_cacheable = 0;
1290: v->not_found = 0;
1291: v->data = (u_char *) "https";
1292:
1293: return NGX_OK;
1294: }
1295:
1296: #endif
1297:
1298: v->len = sizeof("http") - 1;
1299: v->valid = 1;
1300: v->no_cacheable = 0;
1301: v->not_found = 0;
1302: v->data = (u_char *) "http";
1303:
1304: return NGX_OK;
1305: }
1306:
1307:
1308: static ngx_int_t
1309: ngx_http_variable_https(ngx_http_request_t *r,
1310: ngx_http_variable_value_t *v, uintptr_t data)
1311: {
1312: #if (NGX_HTTP_SSL)
1313:
1314: if (r->connection->ssl) {
1315: v->len = sizeof("on") - 1;
1316: v->valid = 1;
1317: v->no_cacheable = 0;
1318: v->not_found = 0;
1319: v->data = (u_char *) "on";
1320:
1321: return NGX_OK;
1322: }
1323:
1324: #endif
1325:
1326: *v = ngx_http_variable_null_value;
1327:
1328: return NGX_OK;
1329: }
1330:
1331:
1332: static ngx_int_t
1333: ngx_http_variable_is_args(ngx_http_request_t *r,
1334: ngx_http_variable_value_t *v, uintptr_t data)
1335: {
1336: v->valid = 1;
1337: v->no_cacheable = 0;
1338: v->not_found = 0;
1339:
1340: if (r->args.len == 0) {
1341: v->len = 0;
1342: v->data = NULL;
1343: return NGX_OK;
1344: }
1345:
1346: v->len = 1;
1347: v->data = (u_char *) "?";
1348:
1349: return NGX_OK;
1350: }
1351:
1352:
1353: static ngx_int_t
1354: ngx_http_variable_document_root(ngx_http_request_t *r,
1355: ngx_http_variable_value_t *v, uintptr_t data)
1356: {
1357: ngx_str_t path;
1358: ngx_http_core_loc_conf_t *clcf;
1359:
1360: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1361:
1362: if (clcf->root_lengths == NULL) {
1363: v->len = clcf->root.len;
1364: v->valid = 1;
1365: v->no_cacheable = 0;
1366: v->not_found = 0;
1367: v->data = clcf->root.data;
1368:
1369: } else {
1370: if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 0,
1371: clcf->root_values->elts)
1372: == NULL)
1373: {
1374: return NGX_ERROR;
1375: }
1376:
1377: if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
1378: return NGX_ERROR;
1379: }
1380:
1381: v->len = path.len;
1382: v->valid = 1;
1383: v->no_cacheable = 0;
1384: v->not_found = 0;
1385: v->data = path.data;
1386: }
1387:
1388: return NGX_OK;
1389: }
1390:
1391:
1392: static ngx_int_t
1393: ngx_http_variable_realpath_root(ngx_http_request_t *r,
1394: ngx_http_variable_value_t *v, uintptr_t data)
1395: {
1396: u_char *real;
1397: size_t len;
1398: ngx_str_t path;
1399: ngx_http_core_loc_conf_t *clcf;
1400: #if (NGX_HAVE_MAX_PATH)
1401: u_char buffer[NGX_MAX_PATH];
1402: #endif
1403:
1404: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1405:
1406: if (clcf->root_lengths == NULL) {
1407: path = clcf->root;
1408:
1409: } else {
1410: if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 1,
1411: clcf->root_values->elts)
1412: == NULL)
1413: {
1414: return NGX_ERROR;
1415: }
1416:
1417: path.data[path.len - 1] = '\0';
1418:
1419: if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
1420: return NGX_ERROR;
1421: }
1422: }
1423:
1424: #if (NGX_HAVE_MAX_PATH)
1425: real = buffer;
1426: #else
1427: real = NULL;
1428: #endif
1429:
1430: real = ngx_realpath(path.data, real);
1431:
1432: if (real == NULL) {
1433: ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
1434: ngx_realpath_n " \"%s\" failed", path.data);
1435: return NGX_ERROR;
1436: }
1437:
1438: len = ngx_strlen(real);
1439:
1440: v->data = ngx_pnalloc(r->pool, len);
1441: if (v->data == NULL) {
1442: #if !(NGX_HAVE_MAX_PATH)
1443: ngx_free(real);
1444: #endif
1445: return NGX_ERROR;
1446: }
1447:
1448: v->len = len;
1449: v->valid = 1;
1450: v->no_cacheable = 0;
1451: v->not_found = 0;
1452:
1453: ngx_memcpy(v->data, real, len);
1454:
1455: #if !(NGX_HAVE_MAX_PATH)
1456: ngx_free(real);
1457: #endif
1458:
1459: return NGX_OK;
1460: }
1461:
1462:
1463: static ngx_int_t
1464: ngx_http_variable_request_filename(ngx_http_request_t *r,
1465: ngx_http_variable_value_t *v, uintptr_t data)
1466: {
1467: size_t root;
1468: ngx_str_t path;
1469:
1470: if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
1471: return NGX_ERROR;
1472: }
1473:
1474: /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */
1475:
1476: v->len = path.len - 1;
1477: v->valid = 1;
1478: v->no_cacheable = 0;
1479: v->not_found = 0;
1480: v->data = path.data;
1481:
1482: return NGX_OK;
1483: }
1484:
1485:
1486: static ngx_int_t
1487: ngx_http_variable_server_name(ngx_http_request_t *r,
1488: ngx_http_variable_value_t *v, uintptr_t data)
1489: {
1490: ngx_http_core_srv_conf_t *cscf;
1491:
1492: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1493:
1494: v->len = cscf->server_name.len;
1495: v->valid = 1;
1496: v->no_cacheable = 0;
1497: v->not_found = 0;
1498: v->data = cscf->server_name.data;
1499:
1500: return NGX_OK;
1501: }
1502:
1503:
1504: static ngx_int_t
1505: ngx_http_variable_request_method(ngx_http_request_t *r,
1506: ngx_http_variable_value_t *v, uintptr_t data)
1507: {
1508: if (r->main->method_name.data) {
1509: v->len = r->main->method_name.len;
1510: v->valid = 1;
1511: v->no_cacheable = 0;
1512: v->not_found = 0;
1513: v->data = r->main->method_name.data;
1514:
1515: } else {
1516: v->not_found = 1;
1517: }
1518:
1519: return NGX_OK;
1520: }
1521:
1522:
1523: static ngx_int_t
1524: ngx_http_variable_remote_user(ngx_http_request_t *r,
1525: ngx_http_variable_value_t *v, uintptr_t data)
1526: {
1527: ngx_int_t rc;
1528:
1529: rc = ngx_http_auth_basic_user(r);
1530:
1531: if (rc == NGX_DECLINED) {
1532: v->not_found = 1;
1533: return NGX_OK;
1534: }
1535:
1536: if (rc == NGX_ERROR) {
1537: return NGX_ERROR;
1538: }
1539:
1540: v->len = r->headers_in.user.len;
1541: v->valid = 1;
1542: v->no_cacheable = 0;
1543: v->not_found = 0;
1544: v->data = r->headers_in.user.data;
1545:
1546: return NGX_OK;
1547: }
1548:
1549:
1550: static ngx_int_t
1551: ngx_http_variable_bytes_sent(ngx_http_request_t *r,
1552: ngx_http_variable_value_t *v, uintptr_t data)
1553: {
1554: u_char *p;
1555:
1556: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1557: if (p == NULL) {
1558: return NGX_ERROR;
1559: }
1560:
1561: v->len = ngx_sprintf(p, "%O", r->connection->sent) - p;
1562: v->valid = 1;
1563: v->no_cacheable = 0;
1564: v->not_found = 0;
1565: v->data = p;
1566:
1567: return NGX_OK;
1568: }
1569:
1570:
1571: static ngx_int_t
1572: ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
1573: ngx_http_variable_value_t *v, uintptr_t data)
1574: {
1575: off_t sent;
1576: u_char *p;
1577:
1578: sent = r->connection->sent - r->header_size;
1579:
1580: if (sent < 0) {
1581: sent = 0;
1582: }
1583:
1584: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1585: if (p == NULL) {
1586: return NGX_ERROR;
1587: }
1588:
1589: v->len = ngx_sprintf(p, "%O", sent) - p;
1590: v->valid = 1;
1591: v->no_cacheable = 0;
1592: v->not_found = 0;
1593: v->data = p;
1594:
1595: return NGX_OK;
1596: }
1597:
1598:
1599: static ngx_int_t
1600: ngx_http_variable_pipe(ngx_http_request_t *r,
1601: ngx_http_variable_value_t *v, uintptr_t data)
1602: {
1603: v->data = (u_char *) (r->pipeline ? "p" : ".");
1604: v->len = 1;
1605: v->valid = 1;
1606: v->no_cacheable = 0;
1607: v->not_found = 0;
1608:
1609: return NGX_OK;
1610: }
1611:
1612:
1613: static ngx_int_t
1614: ngx_http_variable_status(ngx_http_request_t *r,
1615: ngx_http_variable_value_t *v, uintptr_t data)
1616: {
1617: ngx_uint_t status;
1618:
1619: v->data = ngx_pnalloc(r->pool, NGX_INT_T_LEN);
1620: if (v->data == NULL) {
1621: return NGX_ERROR;
1622: }
1623:
1624: if (r->err_status) {
1625: status = r->err_status;
1626:
1627: } else if (r->headers_out.status) {
1628: status = r->headers_out.status;
1629:
1630: } else if (r->http_version == NGX_HTTP_VERSION_9) {
1631: status = 9;
1632:
1633: } else {
1634: status = 0;
1635: }
1636:
1637: v->len = ngx_sprintf(v->data, "%03ui", status) - v->data;
1638: v->valid = 1;
1639: v->no_cacheable = 0;
1640: v->not_found = 0;
1641:
1642: return NGX_OK;
1643: }
1644:
1645:
1646: static ngx_int_t
1647: ngx_http_variable_sent_content_type(ngx_http_request_t *r,
1648: ngx_http_variable_value_t *v, uintptr_t data)
1649: {
1650: if (r->headers_out.content_type.len) {
1651: v->len = r->headers_out.content_type.len;
1652: v->valid = 1;
1653: v->no_cacheable = 0;
1654: v->not_found = 0;
1655: v->data = r->headers_out.content_type.data;
1656:
1657: } else {
1658: v->not_found = 1;
1659: }
1660:
1661: return NGX_OK;
1662: }
1663:
1664:
1665: static ngx_int_t
1666: ngx_http_variable_sent_content_length(ngx_http_request_t *r,
1667: ngx_http_variable_value_t *v, uintptr_t data)
1668: {
1669: u_char *p;
1670:
1671: if (r->headers_out.content_length) {
1672: v->len = r->headers_out.content_length->value.len;
1673: v->valid = 1;
1674: v->no_cacheable = 0;
1675: v->not_found = 0;
1676: v->data = r->headers_out.content_length->value.data;
1677:
1678: return NGX_OK;
1679: }
1680:
1681: if (r->headers_out.content_length_n >= 0) {
1682: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1683: if (p == NULL) {
1684: return NGX_ERROR;
1685: }
1686:
1687: v->len = ngx_sprintf(p, "%O", r->headers_out.content_length_n) - p;
1688: v->valid = 1;
1689: v->no_cacheable = 0;
1690: v->not_found = 0;
1691: v->data = p;
1692:
1693: return NGX_OK;
1694: }
1695:
1696: v->not_found = 1;
1697:
1698: return NGX_OK;
1699: }
1700:
1701:
1702: static ngx_int_t
1703: ngx_http_variable_sent_location(ngx_http_request_t *r,
1704: ngx_http_variable_value_t *v, uintptr_t data)
1705: {
1706: ngx_str_t name;
1707:
1708: if (r->headers_out.location) {
1709: v->len = r->headers_out.location->value.len;
1710: v->valid = 1;
1711: v->no_cacheable = 0;
1712: v->not_found = 0;
1713: v->data = r->headers_out.location->value.data;
1714:
1715: return NGX_OK;
1716: }
1717:
1718: ngx_str_set(&name, "sent_http_location");
1719:
1720: return ngx_http_variable_unknown_header(v, &name,
1721: &r->headers_out.headers.part,
1722: sizeof("sent_http_") - 1);
1723: }
1724:
1725:
1726: static ngx_int_t
1727: ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
1728: ngx_http_variable_value_t *v, uintptr_t data)
1729: {
1730: u_char *p;
1731:
1732: if (r->headers_out.last_modified) {
1733: v->len = r->headers_out.last_modified->value.len;
1734: v->valid = 1;
1735: v->no_cacheable = 0;
1736: v->not_found = 0;
1737: v->data = r->headers_out.last_modified->value.data;
1738:
1739: return NGX_OK;
1740: }
1741:
1742: if (r->headers_out.last_modified_time >= 0) {
1743: p = ngx_pnalloc(r->pool,
1744: sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1);
1745: if (p == NULL) {
1746: return NGX_ERROR;
1747: }
1748:
1749: v->len = ngx_http_time(p, r->headers_out.last_modified_time) - p;
1750: v->valid = 1;
1751: v->no_cacheable = 0;
1752: v->not_found = 0;
1753: v->data = p;
1754:
1755: return NGX_OK;
1756: }
1757:
1758: v->not_found = 1;
1759:
1760: return NGX_OK;
1761: }
1762:
1763:
1764: static ngx_int_t
1765: ngx_http_variable_sent_connection(ngx_http_request_t *r,
1766: ngx_http_variable_value_t *v, uintptr_t data)
1767: {
1768: size_t len;
1769: char *p;
1770:
1771: if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
1772: len = sizeof("upgrade") - 1;
1773: p = "upgrade";
1774:
1775: } else if (r->keepalive) {
1776: len = sizeof("keep-alive") - 1;
1777: p = "keep-alive";
1778:
1779: } else {
1780: len = sizeof("close") - 1;
1781: p = "close";
1782: }
1783:
1784: v->len = len;
1785: v->valid = 1;
1786: v->no_cacheable = 0;
1787: v->not_found = 0;
1788: v->data = (u_char *) p;
1789:
1790: return NGX_OK;
1791: }
1792:
1793:
1794: static ngx_int_t
1795: ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
1796: ngx_http_variable_value_t *v, uintptr_t data)
1797: {
1798: u_char *p;
1799: ngx_http_core_loc_conf_t *clcf;
1800:
1801: if (r->keepalive) {
1802: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1803:
1804: if (clcf->keepalive_header) {
1805:
1806: p = ngx_pnalloc(r->pool, sizeof("timeout=") - 1 + NGX_TIME_T_LEN);
1807: if (p == NULL) {
1808: return NGX_ERROR;
1809: }
1810:
1811: v->len = ngx_sprintf(p, "timeout=%T", clcf->keepalive_header) - p;
1812: v->valid = 1;
1813: v->no_cacheable = 0;
1814: v->not_found = 0;
1815: v->data = p;
1816:
1817: return NGX_OK;
1818: }
1819: }
1820:
1821: v->not_found = 1;
1822:
1823: return NGX_OK;
1824: }
1825:
1826:
1827: static ngx_int_t
1828: ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
1829: ngx_http_variable_value_t *v, uintptr_t data)
1830: {
1831: if (r->chunked) {
1832: v->len = sizeof("chunked") - 1;
1833: v->valid = 1;
1834: v->no_cacheable = 0;
1835: v->not_found = 0;
1836: v->data = (u_char *) "chunked";
1837:
1838: } else {
1839: v->not_found = 1;
1840: }
1841:
1842: return NGX_OK;
1843: }
1844:
1845:
1846: static ngx_int_t
1847: ngx_http_variable_request_completion(ngx_http_request_t *r,
1848: ngx_http_variable_value_t *v, uintptr_t data)
1849: {
1850: if (r->request_complete) {
1851: v->len = 2;
1852: v->valid = 1;
1853: v->no_cacheable = 0;
1854: v->not_found = 0;
1855: v->data = (u_char *) "OK";
1856:
1857: return NGX_OK;
1858: }
1859:
1860: v->len = 0;
1861: v->valid = 1;
1862: v->no_cacheable = 0;
1863: v->not_found = 0;
1864: v->data = (u_char *) "";
1865:
1866: return NGX_OK;
1867: }
1868:
1869:
1870: static ngx_int_t
1871: ngx_http_variable_request_body(ngx_http_request_t *r,
1872: ngx_http_variable_value_t *v, uintptr_t data)
1873: {
1874: u_char *p;
1875: size_t len;
1876: ngx_buf_t *buf;
1877: ngx_chain_t *cl;
1878:
1879: if (r->request_body == NULL
1880: || r->request_body->bufs == NULL
1881: || r->request_body->temp_file)
1882: {
1883: v->not_found = 1;
1884:
1885: return NGX_OK;
1886: }
1887:
1888: cl = r->request_body->bufs;
1889: buf = cl->buf;
1890:
1891: if (cl->next == NULL) {
1892: v->len = buf->last - buf->pos;
1893: v->valid = 1;
1894: v->no_cacheable = 0;
1895: v->not_found = 0;
1896: v->data = buf->pos;
1897:
1898: return NGX_OK;
1899: }
1900:
1901: len = buf->last - buf->pos;
1902: cl = cl->next;
1903:
1904: for ( /* void */ ; cl; cl = cl->next) {
1905: buf = cl->buf;
1906: len += buf->last - buf->pos;
1907: }
1908:
1909: p = ngx_pnalloc(r->pool, len);
1910: if (p == NULL) {
1911: return NGX_ERROR;
1912: }
1913:
1914: v->data = p;
1915: cl = r->request_body->bufs;
1916:
1917: for ( /* void */ ; cl; cl = cl->next) {
1918: buf = cl->buf;
1919: p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
1920: }
1921:
1922: v->len = len;
1923: v->valid = 1;
1924: v->no_cacheable = 0;
1925: v->not_found = 0;
1926:
1927: return NGX_OK;
1928: }
1929:
1930:
1931: static ngx_int_t
1932: ngx_http_variable_request_body_file(ngx_http_request_t *r,
1933: ngx_http_variable_value_t *v, uintptr_t data)
1934: {
1935: if (r->request_body == NULL || r->request_body->temp_file == NULL) {
1936: v->not_found = 1;
1937:
1938: return NGX_OK;
1939: }
1940:
1941: v->len = r->request_body->temp_file->file.name.len;
1942: v->valid = 1;
1943: v->no_cacheable = 0;
1944: v->not_found = 0;
1945: v->data = r->request_body->temp_file->file.name.data;
1946:
1947: return NGX_OK;
1948: }
1949:
1950:
1951: static ngx_int_t
1952: ngx_http_variable_request_length(ngx_http_request_t *r,
1953: ngx_http_variable_value_t *v, uintptr_t data)
1954: {
1955: u_char *p;
1956:
1957: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
1958: if (p == NULL) {
1959: return NGX_ERROR;
1960: }
1961:
1962: v->len = ngx_sprintf(p, "%O", r->request_length) - p;
1963: v->valid = 1;
1964: v->no_cacheable = 0;
1965: v->not_found = 0;
1966: v->data = p;
1967:
1968: return NGX_OK;
1969: }
1970:
1971:
1972: static ngx_int_t
1973: ngx_http_variable_request_time(ngx_http_request_t *r,
1974: ngx_http_variable_value_t *v, uintptr_t data)
1975: {
1976: u_char *p;
1977: ngx_time_t *tp;
1978: ngx_msec_int_t ms;
1979:
1980: p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN + 4);
1981: if (p == NULL) {
1982: return NGX_ERROR;
1983: }
1984:
1985: tp = ngx_timeofday();
1986:
1987: ms = (ngx_msec_int_t)
1988: ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
1989: ms = ngx_max(ms, 0);
1990:
1991: v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p;
1992: v->valid = 1;
1993: v->no_cacheable = 0;
1994: v->not_found = 0;
1995: v->data = p;
1996:
1997: return NGX_OK;
1998: }
1999:
2000:
2001: static ngx_int_t
2002: ngx_http_variable_connection(ngx_http_request_t *r,
2003: ngx_http_variable_value_t *v, uintptr_t data)
2004: {
2005: u_char *p;
2006:
2007: p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN);
2008: if (p == NULL) {
2009: return NGX_ERROR;
2010: }
2011:
2012: v->len = ngx_sprintf(p, "%uA", r->connection->number) - p;
2013: v->valid = 1;
2014: v->no_cacheable = 0;
2015: v->not_found = 0;
2016: v->data = p;
2017:
2018: return NGX_OK;
2019: }
2020:
2021:
2022: static ngx_int_t
2023: ngx_http_variable_connection_requests(ngx_http_request_t *r,
2024: ngx_http_variable_value_t *v, uintptr_t data)
2025: {
2026: u_char *p;
2027:
2028: p = ngx_pnalloc(r->pool, NGX_INT_T_LEN);
2029: if (p == NULL) {
2030: return NGX_ERROR;
2031: }
2032:
2033: v->len = ngx_sprintf(p, "%ui", r->connection->requests) - p;
2034: v->valid = 1;
2035: v->no_cacheable = 0;
2036: v->not_found = 0;
2037: v->data = p;
2038:
2039: return NGX_OK;
2040: }
2041:
2042:
2043: static ngx_int_t
2044: ngx_http_variable_nginx_version(ngx_http_request_t *r,
2045: ngx_http_variable_value_t *v, uintptr_t data)
2046: {
2047: v->len = sizeof(NGINX_VERSION) - 1;
2048: v->valid = 1;
2049: v->no_cacheable = 0;
2050: v->not_found = 0;
2051: v->data = (u_char *) NGINX_VERSION;
2052:
2053: return NGX_OK;
2054: }
2055:
2056:
2057: static ngx_int_t
2058: ngx_http_variable_hostname(ngx_http_request_t *r,
2059: ngx_http_variable_value_t *v, uintptr_t data)
2060: {
2061: v->len = ngx_cycle->hostname.len;
2062: v->valid = 1;
2063: v->no_cacheable = 0;
2064: v->not_found = 0;
2065: v->data = ngx_cycle->hostname.data;
2066:
2067: return NGX_OK;
2068: }
2069:
2070:
2071: static ngx_int_t
2072: ngx_http_variable_pid(ngx_http_request_t *r,
2073: ngx_http_variable_value_t *v, uintptr_t data)
2074: {
2075: u_char *p;
2076:
2077: p = ngx_pnalloc(r->pool, NGX_INT64_LEN);
2078: if (p == NULL) {
2079: return NGX_ERROR;
2080: }
2081:
2082: v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
2083: v->valid = 1;
2084: v->no_cacheable = 0;
2085: v->not_found = 0;
2086: v->data = p;
2087:
2088: return NGX_OK;
2089: }
2090:
2091:
2092: static ngx_int_t
2093: ngx_http_variable_msec(ngx_http_request_t *r,
2094: ngx_http_variable_value_t *v, uintptr_t data)
2095: {
2096: u_char *p;
2097: ngx_time_t *tp;
2098:
2099: p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN + 4);
2100: if (p == NULL) {
2101: return NGX_ERROR;
2102: }
2103:
2104: tp = ngx_timeofday();
2105:
2106: v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p;
2107: v->valid = 1;
2108: v->no_cacheable = 0;
2109: v->not_found = 0;
2110: v->data = p;
2111:
2112: return NGX_OK;
2113: }
2114:
2115:
2116: static ngx_int_t
2117: ngx_http_variable_time_iso8601(ngx_http_request_t *r,
2118: ngx_http_variable_value_t *v, uintptr_t data)
2119: {
2120: u_char *p;
2121:
2122: p = ngx_pnalloc(r->pool, ngx_cached_http_log_iso8601.len);
2123: if (p == NULL) {
2124: return NGX_ERROR;
2125: }
2126:
2127: ngx_memcpy(p, ngx_cached_http_log_iso8601.data,
2128: ngx_cached_http_log_iso8601.len);
2129:
2130: v->len = ngx_cached_http_log_iso8601.len;
2131: v->valid = 1;
2132: v->no_cacheable = 0;
2133: v->not_found = 0;
2134: v->data = p;
2135:
2136: return NGX_OK;
2137: }
2138:
2139:
2140: static ngx_int_t
2141: ngx_http_variable_time_local(ngx_http_request_t *r,
2142: ngx_http_variable_value_t *v, uintptr_t data)
2143: {
2144: u_char *p;
2145:
2146: p = ngx_pnalloc(r->pool, ngx_cached_http_log_time.len);
2147: if (p == NULL) {
2148: return NGX_ERROR;
2149: }
2150:
2151: ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len);
2152:
2153: v->len = ngx_cached_http_log_time.len;
2154: v->valid = 1;
2155: v->no_cacheable = 0;
2156: v->not_found = 0;
2157: v->data = p;
2158:
2159: return NGX_OK;
2160: }
2161:
2162:
2163: void *
2164: ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map, ngx_str_t *match)
2165: {
2166: void *value;
2167: u_char *low;
2168: size_t len;
2169: ngx_uint_t key;
2170:
2171: len = match->len;
2172:
2173: if (len) {
2174: low = ngx_pnalloc(r->pool, len);
2175: if (low == NULL) {
2176: return NULL;
2177: }
2178:
2179: } else {
2180: low = NULL;
2181: }
2182:
2183: key = ngx_hash_strlow(low, match->data, len);
2184:
2185: value = ngx_hash_find_combined(&map->hash, key, low, len);
2186: if (value) {
2187: return value;
2188: }
2189:
2190: #if (NGX_PCRE)
2191:
2192: if (len && map->nregex) {
2193: ngx_int_t n;
2194: ngx_uint_t i;
2195: ngx_http_map_regex_t *reg;
2196:
2197: reg = map->regex;
2198:
2199: for (i = 0; i < map->nregex; i++) {
2200:
2201: n = ngx_http_regex_exec(r, reg[i].regex, match);
2202:
2203: if (n == NGX_OK) {
2204: return reg[i].value;
2205: }
2206:
2207: if (n == NGX_DECLINED) {
2208: continue;
2209: }
2210:
2211: /* NGX_ERROR */
2212:
2213: return NULL;
2214: }
2215: }
2216:
2217: #endif
2218:
2219: return NULL;
2220: }
2221:
2222:
2223: #if (NGX_PCRE)
2224:
2225: static ngx_int_t
2226: ngx_http_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v,
2227: uintptr_t data)
2228: {
2229: v->not_found = 1;
2230: return NGX_OK;
2231: }
2232:
2233:
2234: ngx_http_regex_t *
2235: ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
2236: {
2237: u_char *p;
2238: size_t size;
2239: ngx_str_t name;
2240: ngx_uint_t i, n;
2241: ngx_http_variable_t *v;
2242: ngx_http_regex_t *re;
2243: ngx_http_regex_variable_t *rv;
2244: ngx_http_core_main_conf_t *cmcf;
2245:
2246: rc->pool = cf->pool;
2247:
2248: if (ngx_regex_compile(rc) != NGX_OK) {
2249: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
2250: return NULL;
2251: }
2252:
2253: re = ngx_pcalloc(cf->pool, sizeof(ngx_http_regex_t));
2254: if (re == NULL) {
2255: return NULL;
2256: }
2257:
2258: re->regex = rc->regex;
2259: re->ncaptures = rc->captures;
2260:
2261: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
2262: cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
2263:
2264: n = (ngx_uint_t) rc->named_captures;
2265:
2266: if (n == 0) {
2267: return re;
2268: }
2269:
2270: rv = ngx_palloc(rc->pool, n * sizeof(ngx_http_regex_variable_t));
2271: if (rv == NULL) {
2272: return NULL;
2273: }
2274:
2275: re->variables = rv;
2276: re->nvariables = n;
2277: re->name = rc->pattern;
2278:
2279: size = rc->name_size;
2280: p = rc->names;
2281:
2282: for (i = 0; i < n; i++) {
2283: rv[i].capture = 2 * ((p[0] << 8) + p[1]);
2284:
2285: name.data = &p[2];
2286: name.len = ngx_strlen(name.data);
2287:
2288: v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
2289: if (v == NULL) {
2290: return NULL;
2291: }
2292:
2293: rv[i].index = ngx_http_get_variable_index(cf, &name);
2294: if (rv[i].index == NGX_ERROR) {
2295: return NULL;
2296: }
2297:
2298: v->get_handler = ngx_http_variable_not_found;
2299:
2300: p += size;
2301: }
2302:
2303: return re;
2304: }
2305:
2306:
2307: ngx_int_t
2308: ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s)
2309: {
2310: ngx_int_t rc, index;
2311: ngx_uint_t i, n, len;
2312: ngx_http_variable_value_t *vv;
2313: ngx_http_core_main_conf_t *cmcf;
2314:
2315: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
2316:
2317: if (re->ncaptures) {
2318: len = cmcf->ncaptures;
2319:
2320: if (r->captures == NULL) {
2321: r->captures = ngx_palloc(r->pool, len * sizeof(int));
2322: if (r->captures == NULL) {
2323: return NGX_ERROR;
2324: }
2325: }
2326:
2327: } else {
2328: len = 0;
2329: }
2330:
2331: rc = ngx_regex_exec(re->regex, s, r->captures, len);
2332:
2333: if (rc == NGX_REGEX_NO_MATCHED) {
2334: return NGX_DECLINED;
2335: }
2336:
2337: if (rc < 0) {
2338: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
2339: ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
2340: rc, s, &re->name);
2341: return NGX_ERROR;
2342: }
2343:
2344: for (i = 0; i < re->nvariables; i++) {
2345:
2346: n = re->variables[i].capture;
2347: index = re->variables[i].index;
2348: vv = &r->variables[index];
2349:
2350: vv->len = r->captures[n + 1] - r->captures[n];
2351: vv->valid = 1;
2352: vv->no_cacheable = 0;
2353: vv->not_found = 0;
2354: vv->data = &s->data[r->captures[n]];
2355:
2356: #if (NGX_DEBUG)
2357: {
2358: ngx_http_variable_t *v;
2359:
2360: v = cmcf->variables.elts;
2361:
2362: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2363: "http regex set $%V to \"%*s\"",
2364: &v[index].name, vv->len, vv->data);
2365: }
2366: #endif
2367: }
2368:
2369: r->ncaptures = rc * 2;
2370: r->captures_data = s->data;
2371:
2372: return NGX_OK;
2373: }
2374:
2375: #endif
2376:
2377:
2378: ngx_int_t
2379: ngx_http_variables_add_core_vars(ngx_conf_t *cf)
2380: {
2381: ngx_int_t rc;
2382: ngx_http_variable_t *cv, *v;
2383: ngx_http_core_main_conf_t *cmcf;
2384:
2385: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
2386:
2387: cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
2388: sizeof(ngx_hash_keys_arrays_t));
2389: if (cmcf->variables_keys == NULL) {
2390: return NGX_ERROR;
2391: }
2392:
2393: cmcf->variables_keys->pool = cf->pool;
2394: cmcf->variables_keys->temp_pool = cf->pool;
2395:
2396: if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
2397: != NGX_OK)
2398: {
2399: return NGX_ERROR;
2400: }
2401:
2402: for (cv = ngx_http_core_variables; cv->name.len; cv++) {
2403: v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
2404: if (v == NULL) {
2405: return NGX_ERROR;
2406: }
2407:
2408: *v = *cv;
2409:
2410: rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
2411: NGX_HASH_READONLY_KEY);
2412:
2413: if (rc == NGX_OK) {
2414: continue;
2415: }
2416:
2417: if (rc == NGX_BUSY) {
2418: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2419: "conflicting variable name \"%V\"", &v->name);
2420: }
2421:
2422: return NGX_ERROR;
2423: }
2424:
2425: return NGX_OK;
2426: }
2427:
2428:
2429: ngx_int_t
2430: ngx_http_variables_init_vars(ngx_conf_t *cf)
2431: {
2432: ngx_uint_t i, n;
2433: ngx_hash_key_t *key;
2434: ngx_hash_init_t hash;
2435: ngx_http_variable_t *v, *av;
2436: ngx_http_core_main_conf_t *cmcf;
2437:
2438: /* set the handlers for the indexed http variables */
2439:
2440: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
2441:
2442: v = cmcf->variables.elts;
2443: key = cmcf->variables_keys->keys.elts;
2444:
2445: for (i = 0; i < cmcf->variables.nelts; i++) {
2446:
2447: for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
2448:
2449: av = key[n].value;
2450:
2451: if (av->get_handler
2452: && v[i].name.len == key[n].key.len
2453: && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
2454: == 0)
2455: {
2456: v[i].get_handler = av->get_handler;
2457: v[i].data = av->data;
2458:
2459: av->flags |= NGX_HTTP_VAR_INDEXED;
2460: v[i].flags = av->flags;
2461:
2462: av->index = i;
2463:
2464: goto next;
2465: }
2466: }
2467:
2468: if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
2469: v[i].get_handler = ngx_http_variable_unknown_header_in;
2470: v[i].data = (uintptr_t) &v[i].name;
2471:
2472: continue;
2473: }
2474:
2475: if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) {
2476: v[i].get_handler = ngx_http_variable_unknown_header_out;
2477: v[i].data = (uintptr_t) &v[i].name;
2478:
2479: continue;
2480: }
2481:
2482: if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) {
2483: v[i].get_handler = ngx_http_upstream_header_variable;
2484: v[i].data = (uintptr_t) &v[i].name;
2485: v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
2486:
2487: continue;
2488: }
2489:
2490: if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) {
2491: v[i].get_handler = ngx_http_variable_cookie;
2492: v[i].data = (uintptr_t) &v[i].name;
2493:
2494: continue;
2495: }
2496:
2497: if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
2498: v[i].get_handler = ngx_http_variable_argument;
2499: v[i].data = (uintptr_t) &v[i].name;
2500: v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
2501:
2502: continue;
2503: }
2504:
2505: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
2506: "unknown \"%V\" variable", &v[i].name);
2507:
2508: return NGX_ERROR;
2509:
2510: next:
2511: continue;
2512: }
2513:
2514:
2515: for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
2516: av = key[n].value;
2517:
2518: if (av->flags & NGX_HTTP_VAR_NOHASH) {
2519: key[n].key.data = NULL;
2520: }
2521: }
2522:
2523:
2524: hash.hash = &cmcf->variables_hash;
2525: hash.key = ngx_hash_key;
2526: hash.max_size = cmcf->variables_hash_max_size;
2527: hash.bucket_size = cmcf->variables_hash_bucket_size;
2528: hash.name = "variables_hash";
2529: hash.pool = cf->pool;
2530: hash.temp_pool = NULL;
2531:
2532: if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
2533: cmcf->variables_keys->keys.nelts)
2534: != NGX_OK)
2535: {
2536: return NGX_ERROR;
2537: }
2538:
2539: cmcf->variables_keys = NULL;
2540:
2541: return NGX_OK;
2542: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>