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