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