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