comparison src/http/ngx_http_variables.c @ 509:9b8c906f6e63 release-0.1.29

nginx-0.1.29-RELEASE import *) Feature: the ngx_http_ssi_module supports "include virtual" command. *) Feature: the ngx_http_ssi_module supports the condition command like 'if expr="$NAME"' and "else" and "endif" commands. Only one nested level is supported. *) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and DATE_GMT variables and "config timefmt" command. *) Feature: the "ssi_ignore_recycled_buffers" directive. *) Bugfix: the "echo" command did not show the default value for the empty QUERY_STRING variable. *) Change: the ngx_http_proxy_module was rewritten. *) Feature: the "proxy_redirect", "proxy_pass_request_headers", "proxy_pass_request_body", and "proxy_method" directives. *) Feature: the "proxy_set_header" directive. The "proxy_x_var" was canceled and must be replaced with the proxy_set_header directive. *) Change: the "proxy_preserve_host" is canceled and must be replaced with the "proxy_set_header Host $host" and the "proxy_redirect off" directives, the "proxy_set_header Host $host:$proxy_port" directive and the appropriate proxy_redirect directives. *) Change: the "proxy_set_x_real_ip" is canceled and must be replaced with the "proxy_set_header X-Real-IP $remote_addr" directive. *) Change: the "proxy_add_x_forwarded_for" is canceled and must be replaced with the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for" directive. *) Change: the "proxy_set_x_url" is canceled and must be replaced with the "proxy_set_header X-URL http://$host:$server_port$request_uri" directive. *) Feature: the "fastcgi_param" directive. *) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params" directive are canceled and must be replaced with the fastcgi_param directives. *) Feature: the "index" directive can use the variables. *) Feature: the "index" directive can be used at http and server levels. *) Change: the last index only in the "index" directive can be absolute. *) Feature: the "rewrite" directive can use the variables. *) Feature: the "internal" directive. *) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME, REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables. *) Change: nginx now passes the invalid lines in a client request headers or a backend response header. *) Bugfix: if the backend did not transfer response for a long time and the "send_timeout" was less than "proxy_read_timeout", then nginx returned the 408 response. *) Bugfix: the segmentation fault was occurred if the backend sent an invalid line in response header; the bug had appeared in 0.1.26. *) Bugfix: the segmentation fault may occurred in FastCGI fault tolerance configuration. *) Bugfix: the "expires" directive did not remove the previous "Expires" and "Cache-Control" headers. *) Bugfix: nginx did not take into account trailing dot in "Host" header line. *) Bugfix: the ngx_http_auth_module did not work under Linux. *) Bugfix: the rewrite directive worked incorrectly, if the arguments were in a request. *) Bugfix: nginx could not be built on MacOS X.
author Igor Sysoev <igor@sysoev.ru>
date Thu, 12 May 2005 14:58:06 +0000
parents d4ea69372b94
children 417a087c9c4d
comparison
equal deleted inserted replaced
508:ca1020ce99ba 509:9b8c906f6e63
8 #include <ngx_core.h> 8 #include <ngx_core.h>
9 #include <ngx_event.h> 9 #include <ngx_event.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 #define NGX_HTTP_VARS_HASH_PRIME 29 13 static ngx_http_variable_value_t *
14 14 ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data);
15 #define ngx_http_vars_hash_key(key, vn) \
16 { \
17 ngx_uint_t n; \
18 for (key = 0, n = 0; n < (vn)->len; n++) { \
19 key += (vn)->data[n]; \
20 } \
21 key %= NGX_HTTP_VARS_HASH_PRIME; \
22 }
23
24
25 static ngx_http_variable_value_t * 15 static ngx_http_variable_value_t *
26 ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data); 16 ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data);
27 static ngx_http_variable_value_t * 17 static ngx_http_variable_value_t *
28 ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data); 18 ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data);
29 static ngx_http_variable_value_t * 19 static ngx_http_variable_value_t *
20 ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data);
21 static ngx_http_variable_value_t *
30 ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data); 22 ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data);
31 static ngx_http_variable_value_t * 23 static ngx_http_variable_value_t *
32 ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data); 24 ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data);
33 static ngx_http_variable_value_t * 25 static ngx_http_variable_value_t *
34 ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data); 26 ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data);
35 27 static ngx_http_variable_value_t *
36 28 ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data);
37 static ngx_array_t *ngx_http_core_variables_hash; 29 static ngx_http_variable_value_t *
38 30 ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data);
39 31 static ngx_http_variable_value_t *
40 static ngx_http_core_variable_t ngx_http_core_variables[] = { 32 ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data);
41 33
42 { ngx_string("HTTP_HOST"), ngx_http_variable_header, 34
43 offsetof(ngx_http_headers_in_t, host) }, 35 /*
44 36 * TODO:
45 { ngx_string("HTTP_USER_AGENT"), ngx_http_variable_header, 37 * Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
46 offsetof(ngx_http_headers_in_t, user_agent) }, 38 * REMOTE_HOST (null), REMOTE_IDENT (null),
47 39 * SERVER_SOFTWARE
48 { ngx_string("HTTP_REFERER"), ngx_http_variable_header, 40 *
49 offsetof(ngx_http_headers_in_t, referer) }, 41 * Apache SSI: DATE_GMT, DOCUMENT_NAME, LAST_MODIFIED,
42 * USER_NAME (file owner)
43 */
44
45 static ngx_http_variable_t ngx_http_core_variables[] = {
46
47 { ngx_string("http_host"), ngx_http_variable_header,
48 offsetof(ngx_http_request_t, headers_in.host), 0 },
49
50 { ngx_string("http_user_agent"), ngx_http_variable_header,
51 offsetof(ngx_http_request_t, headers_in.user_agent), 0 },
52
53 { ngx_string("http_referer"), ngx_http_variable_header,
54 offsetof(ngx_http_request_t, headers_in.referer), 0 },
50 55
51 #if (NGX_HTTP_GZIP) 56 #if (NGX_HTTP_GZIP)
52 { ngx_string("HTTP_VIA"), ngx_http_variable_header, 57 { ngx_string("http_via"), ngx_http_variable_header,
53 offsetof(ngx_http_headers_in_t, via) }, 58 offsetof(ngx_http_request_t, headers_in.via), 0 },
54 #endif 59 #endif
55 60
56 #if (NGX_HTTP_PROXY) 61 #if (NGX_HTTP_PROXY)
57 { ngx_string("HTTP_X_FORWARDED_FOR"), ngx_http_variable_header, 62 { ngx_string("http_x_forwarded_for"), ngx_http_variable_header,
58 offsetof(ngx_http_headers_in_t, x_forwarded_for) }, 63 offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0 },
59 #endif 64 #endif
60 65
61 { ngx_string("REMOTE_ADDR"), ngx_http_variable_remote_addr, 0 }, 66 { ngx_string("content_length"), ngx_http_variable_header,
62 67 offsetof(ngx_http_request_t, headers_in.content_length), 0 },
63 { ngx_string("DOCUMENT_URI"), ngx_http_variable_uri, 0 }, 68
64 69 { ngx_string("content_type"), ngx_http_variable_header,
65 { ngx_string("QUERY_STRING"), ngx_http_variable_query_string, 0 }, 70 offsetof(ngx_http_request_t, headers_in.content_type), 0 },
66 71
67 { ngx_null_string, NULL, 0 } 72 { ngx_string("host"), ngx_http_variable_host, 0, 0 },
73
74 { ngx_string("remote_addr"), ngx_http_variable_remote_addr, 0, 0 },
75
76 { ngx_string("remote_port"), ngx_http_variable_remote_port, 0, 0 },
77
78 { ngx_string("server_addr"), ngx_http_variable_server_addr, 0, 0 },
79
80 { ngx_string("server_port"), ngx_http_variable_server_port, 0, 0 },
81
82 { ngx_string("server_protocol"), ngx_http_variable_request,
83 offsetof(ngx_http_request_t, http_protocol), 0 },
84
85 { ngx_string("request_uri"), ngx_http_variable_request,
86 offsetof(ngx_http_request_t, unparsed_uri), 0 },
87
88 { ngx_string("document_uri"), ngx_http_variable_request,
89 offsetof(ngx_http_request_t, uri), 0 },
90
91 { ngx_string("document_root"), ngx_http_variable_document_root, 0, 0 },
92
93 { ngx_string("query_string"), ngx_http_variable_request,
94 offsetof(ngx_http_request_t, args),
95 NGX_HTTP_VAR_NOCACHABLE },
96
97 { ngx_string("request_filename"), ngx_http_variable_request_filename, 0,
98 NGX_HTTP_VAR_NOCACHABLE },
99
100 { ngx_string("server_name"), ngx_http_variable_request,
101 offsetof(ngx_http_request_t, server_name), 0 },
102
103 { ngx_string("request_method"), ngx_http_variable_request,
104 offsetof(ngx_http_request_t, method_name), 0 },
105
106 { ngx_string("remote_user"), ngx_http_variable_request,
107 offsetof(ngx_http_request_t, headers_in.user), 0 },
108
109 { ngx_null_string, NULL, 0, 0 }
68 }; 110 };
69 111
70 112
71 ngx_http_variable_t * 113 ngx_http_variable_t *
72 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t set) 114 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
115 {
116 ngx_uint_t i;
117 ngx_http_variable_t *v;
118 ngx_http_core_main_conf_t *cmcf;
119
120 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
121
122 v = cmcf->all_variables.elts;
123 for (i = 0; i < cmcf->all_variables.nelts; i++) {
124 if (name->len != v[i].name.len
125 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
126 {
127 continue;
128 }
129
130 if (!(v[i].flags & NGX_HTTP_VAR_CHANGABLE)) {
131 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
132 "the duplicate \"%V\" variable", name);
133 return NULL;
134 }
135
136 return &v[i];
137 }
138
139 v = ngx_array_push(&cmcf->all_variables);
140 if (v == NULL) {
141 return NULL;
142 }
143
144 v->name.len = name->len;
145 v->name.data = ngx_palloc(cf->pool, name->len);
146 if (v->name.data == NULL) {
147 return NULL;
148 }
149
150 for (i = 0; i < name->len; i++) {
151 v->name.data[i] = ngx_tolower(name->data[i]);
152 }
153
154 v->handler = NULL;
155 v->data = 0;
156 v->flags = flags;
157
158 return v;
159 }
160
161
162 ngx_int_t
163 ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
73 { 164 {
74 ngx_uint_t i; 165 ngx_uint_t i;
75 ngx_http_variable_t *v; 166 ngx_http_variable_t *v;
76 ngx_http_core_main_conf_t *cmcf; 167 ngx_http_core_main_conf_t *cmcf;
77 168
81 172
82 if (v == NULL) { 173 if (v == NULL) {
83 if (ngx_array_init(&cmcf->variables, cf->pool, 4, 174 if (ngx_array_init(&cmcf->variables, cf->pool, 4,
84 sizeof(ngx_http_variable_t)) == NGX_ERROR) 175 sizeof(ngx_http_variable_t)) == NGX_ERROR)
85 { 176 {
86 return NULL; 177 return NGX_ERROR;
87 } 178 }
88 179
89 } else { 180 } else {
90 for (i = 0; i < cmcf->variables.nelts; i++) { 181 for (i = 0; i < cmcf->variables.nelts; i++) {
91 if (name->len != v[i].name.len 182 if (name->len != v[i].name.len
92 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0) 183 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
93 { 184 {
94 continue; 185 continue;
95 } 186 }
96 187
97 if (set && v[i].handler) { 188 return i;
98 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
99 "the duplicate \"%V\" variable", name);
100 return NULL;
101 }
102
103 return &v[i];
104 } 189 }
105 } 190 }
106 191
107 v = ngx_array_push(&cmcf->variables); 192 v = ngx_array_push(&cmcf->variables);
108 if (v == NULL) { 193 if (v == NULL) {
109 return NULL; 194 return NGX_ERROR;
110 } 195 }
111 196
112 v->name.len = name->len; 197 v->name.len = name->len;
113 v->name.data = ngx_palloc(cf->pool, name->len); 198 v->name.data = ngx_palloc(cf->pool, name->len);
114 if (v->name.data == NULL) { 199 if (v->name.data == NULL) {
115 return NULL; 200 return NGX_ERROR;
116 } 201 }
117 202
118 for (i = 0; i < name->len; i++) { 203 for (i = 0; i < name->len; i++) {
119 v->name.data[i] = ngx_toupper(name->data[i]); 204 v->name.data[i] = ngx_tolower(name->data[i]);
120 } 205 }
121 206
122 v->index = cmcf->variables.nelts - 1;
123 v->handler = NULL; 207 v->handler = NULL;
124 v->data = 0; 208 v->data = 0;
125 209 v->flags = 0;
126 return v; 210
211 return cmcf->variables.nelts - 1;
127 } 212 }
128 213
129 214
130 ngx_http_variable_value_t * 215 ngx_http_variable_value_t *
131 ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index) 216 ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
156 if (r->variables == NULL) { 241 if (r->variables == NULL) {
157 return NULL; 242 return NULL;
158 } 243 }
159 } 244 }
160 245
161 r->variables[index] = vv; 246 if (!(v[index].flags & NGX_HTTP_VAR_NOCACHABLE)) {
247 r->variables[index] = vv;
248 }
162 249
163 return vv; 250 return vv;
164 } 251 }
165 252
166 253
167 ngx_http_variable_value_t * 254 ngx_http_variable_value_t *
168 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name) 255 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name)
169 { 256 {
170 ngx_uint_t i, key; 257 ngx_uint_t i, key;
171 ngx_http_variable_t *v; 258 ngx_http_variable_t *v;
172 ngx_http_core_variable_t *cv;
173 ngx_http_core_main_conf_t *cmcf; 259 ngx_http_core_main_conf_t *cmcf;
174 260
175 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); 261 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
176 262
177 v = cmcf->variables.elts; 263 key = 0;
178 for (i = 0; i < cmcf->variables.nelts; i++) { 264 for (i = 0; i < name->len; i++) {
179 if (v[i].name.len != name->len) { 265 key += name->data[i];
180 continue; 266 }
181 } 267
182 268 key %= cmcf->variables_hash.hash_size;
183 if (ngx_strncmp(v[i].name.data, name->data, name->len) == 0) { 269 v = (ngx_http_variable_t *) cmcf->variables_hash.buckets;
184 return ngx_http_get_indexed_variable(r, v[i].index); 270
185 } 271 if (v[key].name.len == name->len
186 } 272 && ngx_strncmp(v[key].name.data, name->data, name->len) == 0)
187 273 {
188 ngx_http_vars_hash_key(key, name); 274 return v[key].handler(r, v[key].data);
189 275 }
190 cv = ngx_http_core_variables_hash[key].elts; 276
191 for (i = 0; i < ngx_http_core_variables_hash[key].nelts; i++) { 277 if (ngx_strncmp(name->data, "http_", 5) == 0) {
192 if (cv[i].name.len != name->len) {
193 continue;
194 }
195
196 if (ngx_strncmp(cv[i].name.data, name->data, name->len) == 0) {
197 return cv[i].handler(r, cv[i].data);
198 }
199 }
200
201 if (ngx_strncmp(name->data, "HTTP_", 5) == 0) {
202 return ngx_http_variable_unknown_header(r, (uintptr_t) name); 278 return ngx_http_variable_unknown_header(r, (uintptr_t) name);
203 } 279 }
204 280
205 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 281 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
206 "unknown \"%V\" variable", name); 282 "unknown \"%V\" variable", name);
207 283
208 return NGX_HTTP_VARIABLE_NOT_FOUND; 284 return NGX_HTTP_VAR_NOT_FOUND;
285 }
286
287
288 static ngx_http_variable_value_t *
289 ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data)
290 {
291 ngx_str_t *s;
292 ngx_http_variable_value_t *vv;
293
294 s = (ngx_str_t *) ((char *) r + data);
295
296 if (s->data == NULL) {
297 return NGX_HTTP_VAR_NOT_FOUND;
298 }
299
300 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
301 if (vv == NULL) {
302 return NULL;
303 }
304
305 vv->value = 0;
306 vv->text = *s;
307
308 return vv;
209 } 309 }
210 310
211 311
212 static ngx_http_variable_value_t * 312 static ngx_http_variable_value_t *
213 ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data) 313 ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data)
214 { 314 {
215 ngx_table_elt_t *h; 315 ngx_table_elt_t *h;
216 ngx_http_variable_value_t *vv; 316 ngx_http_variable_value_t *vv;
217 317
218 h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); 318 h = *(ngx_table_elt_t **) ((char *) r + data);
219 319
220 if (h == NULL) { 320 if (h == NULL) {
221 return NGX_HTTP_VARIABLE_NOT_FOUND; 321 return NGX_HTTP_VAR_NOT_FOUND;
222 } 322 }
223 323
224 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); 324 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
225 if (vv == NULL) { 325 if (vv == NULL) {
226 return NULL; 326 return NULL;
257 part = part->next; 357 part = part->next;
258 header = part->elts; 358 header = part->elts;
259 i = 0; 359 i = 0;
260 } 360 }
261 361
262 for (n = 0; n + 5 < var->len && n < header[i].key.len; n++) 362 for (n = 0; n + 5 < var->len && n < header[i].key.len; n++) {
263 {
264 ch = header[i].key.data[n]; 363 ch = header[i].key.data[n];
265 364
266 if (ch >= 'a' && ch <= 'z') { 365 if (ch >= 'A' && ch <= 'Z') {
267 ch &= ~0x20; 366 ch |= 0x20;
268 367
269 } else if (ch == '-') { 368 } else if (ch == '-') {
270 ch = '_'; 369 ch = '_';
271 } 370 }
272 371
285 vv->text = header[i].value; 384 vv->text = header[i].value;
286 return vv; 385 return vv;
287 } 386 }
288 } 387 }
289 388
290 return NGX_HTTP_VARIABLE_NOT_FOUND; 389 return NGX_HTTP_VAR_NOT_FOUND;
390 }
391
392
393 static ngx_http_variable_value_t *
394 ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data)
395 {
396 ngx_http_variable_value_t *vv;
397
398 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
399 if (vv == NULL) {
400 return NULL;
401 }
402
403 vv->value = 0;
404
405 if (r->headers_in.host) {
406 vv->text.len = r->headers_in.host_name_len;
407 vv->text.data = r->headers_in.host->value.data;
408
409 } else {
410 vv->text = r->server_name;
411 }
412
413 return vv;
291 } 414 }
292 415
293 416
294 static ngx_http_variable_value_t * 417 static ngx_http_variable_value_t *
295 ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data) 418 ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data)
307 return vv; 430 return vv;
308 } 431 }
309 432
310 433
311 static ngx_http_variable_value_t * 434 static ngx_http_variable_value_t *
312 ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data) 435 ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data)
313 { 436 {
314 ngx_http_variable_value_t *vv; 437 ngx_uint_t port;
315 438 struct sockaddr_in *sin;
316 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); 439 ngx_http_variable_value_t *vv;
317 if (vv == NULL) { 440
318 return NULL; 441 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
319 } 442 if (vv == NULL) {
320 443 return NULL;
321 vv->value = 0; 444 }
322 vv->text = r->uri; 445
323 446 vv->value = 0;
324 return vv; 447 vv->text.len = 0;
325 } 448
326 449 vv->text.data = ngx_palloc(r->pool, sizeof("65535") - 1);
327 450 if (vv->text.data == NULL) {
328 static ngx_http_variable_value_t * 451 return NULL;
329 ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data) 452 }
330 { 453
331 ngx_http_variable_value_t *vv; 454 /* AF_INET only */
332 455
333 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); 456 if (r->connection->sockaddr->sa_family == AF_INET) {
334 if (vv == NULL) { 457 sin = (struct sockaddr_in *) r->connection->sockaddr;
335 return NULL; 458
336 } 459 port = ntohs(sin->sin_port);
337 460
338 vv->value = 0; 461 if (port > 0 && port < 65536) {
339 vv->text = r->args; 462 vv->value = port;
463 vv->text.len = ngx_sprintf(vv->text.data, "%ui", port)
464 - vv->text.data;
465 }
466 }
467
468 return vv;
469 }
470
471
472 static ngx_http_variable_value_t *
473 ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data)
474 {
475 socklen_t len;
476 ngx_connection_t *c;
477 struct sockaddr_in sin;
478 ngx_http_variable_value_t *vv;
479
480 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
481 if (vv == NULL) {
482 return NULL;
483 }
484
485 vv->value = 0;
486
487 vv->text.data = ngx_palloc(r->pool, INET_ADDRSTRLEN);
488 if (vv->text.data == NULL) {
489 return NULL;
490 }
491
492 c = r->connection;
493
494 if (r->in_addr == 0) {
495 len = sizeof(struct sockaddr_in);
496 if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
497 ngx_log_error(NGX_LOG_CRIT, c->log,
498 ngx_socket_errno, "getsockname() failed");
499 return NULL;
500 }
501
502 r->in_addr = sin.sin_addr.s_addr;
503 }
504
505 vv->text.len = ngx_inet_ntop(c->listening->family, &r->in_addr,
506 vv->text.data, INET_ADDRSTRLEN);
507
508 return vv;
509 }
510
511
512 static ngx_http_variable_value_t *
513 ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data)
514 {
515 ngx_http_variable_value_t *vv;
516
517 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
518 if (vv == NULL) {
519 return NULL;
520 }
521
522 vv->value = r->port;
523 vv->text.len = r->port_text->len - 1;
524 vv->text.data = r->port_text->data + 1;
525
526 return vv;
527 }
528
529
530 static ngx_http_variable_value_t *
531 ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data)
532 {
533 ngx_http_core_loc_conf_t *clcf;
534 ngx_http_variable_value_t *vv;
535
536 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
537 if (vv == NULL) {
538 return NULL;
539 }
540
541 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
542
543 vv->value = 0;
544 vv->text = clcf->root;
545
546 return vv;
547 }
548
549
550 static ngx_http_variable_value_t *
551 ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data)
552 {
553 u_char *p;
554 ngx_http_core_loc_conf_t *clcf;
555 ngx_http_variable_value_t *vv;
556
557 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
558 if (vv == NULL) {
559 return NULL;
560 }
561
562 vv->value = 0;
563
564 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
565
566 if (!clcf->alias) {
567 vv->text.len = clcf->root.len + r->uri.len;
568 vv->text.data = ngx_palloc(r->pool, vv->text.len);
569 if (vv->text.data == NULL) {
570 return NULL;
571 }
572
573 p = ngx_cpymem(vv->text.data, clcf->root.data, clcf->root.len);
574 ngx_memcpy(p, r->uri.data, r->uri.len + 1);
575
576 } else {
577 vv->text.len = clcf->root.len + r->uri.len + 2 - clcf->name.len;
578 vv->text.data = ngx_palloc(r->pool, vv->text.len);
579 if (vv->text.data == NULL) {
580 return NULL;
581 }
582
583 p = ngx_cpymem(vv->text.data, clcf->root.data, clcf->root.len);
584 ngx_memcpy(p, r->uri.data + clcf->name.len,
585 r->uri.len + 1 - clcf->name.len);
586 }
340 587
341 return vv; 588 return vv;
342 } 589 }
343 590
344 591
345 ngx_int_t 592 ngx_int_t
346 ngx_http_variables_init(ngx_cycle_t *cycle) 593 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
347 { 594 {
348 ngx_uint_t i, j, key; 595 ngx_http_variable_t *v, *cv;
349 ngx_http_variable_t *v;
350 ngx_http_core_variable_t *cv, *vp;
351 ngx_http_core_main_conf_t *cmcf; 596 ngx_http_core_main_conf_t *cmcf;
352 597
353 ngx_http_core_variables_hash = ngx_palloc(cycle->pool, 598 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
354 NGX_HTTP_VARS_HASH_PRIME 599
355 * sizeof(ngx_array_t)); 600 if (ngx_array_init(&cmcf->all_variables, cf->pool, 32,
356 if (ngx_http_core_variables_hash == NULL) { 601 sizeof(ngx_http_variable_t)) == NGX_ERROR)
602 {
357 return NGX_ERROR; 603 return NGX_ERROR;
358 } 604 }
359 605
360 for (i = 0; i < NGX_HTTP_VARS_HASH_PRIME; i++) { 606 for (cv = ngx_http_core_variables; cv->name.len; cv++) {
361 if (ngx_array_init(&ngx_http_core_variables_hash[i], cycle->pool, 4, 607 v = ngx_array_push(&cmcf->all_variables);
362 sizeof(ngx_http_core_variable_t)) == NGX_ERROR) 608 if (v == NULL) {
363 {
364 return NGX_ERROR; 609 return NGX_ERROR;
365 } 610 }
366 } 611
367 612 *v = *cv;
368 for (cv = ngx_http_core_variables; cv->name.len; cv++) { 613 }
369 ngx_http_vars_hash_key(key, &cv->name); 614
370 615 return NGX_OK;
371 vp = ngx_array_push(&ngx_http_core_variables_hash[key]); 616 }
372 if (vp == NULL) { 617
373 return NGX_ERROR; 618
374 } 619 ngx_int_t
375 620 ngx_http_variables_init_vars(ngx_conf_t *cf)
376 *vp = *cv; 621 {
377 } 622 ngx_uint_t i, n;
378 623 ngx_http_variable_t *v, *av;
379 624 ngx_http_core_main_conf_t *cmcf;
380 cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); 625
626 /* set the handlers for the indexed http variables */
627
628 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
381 629
382 v = cmcf->variables.elts; 630 v = cmcf->variables.elts;
631 av = cmcf->all_variables.elts;
632
383 for (i = 0; i < cmcf->variables.nelts; i++) { 633 for (i = 0; i < cmcf->variables.nelts; i++) {
384 634
385 if (v[i].handler) { 635 for (n = 0; n < cmcf->all_variables.nelts; n++) {
386 continue; 636
387 } 637 if (v[i].name.len == av[n].name.len
388 638 && ngx_strncmp(v[i].name.data, av[n].name.data, v[i].name.len)
389 ngx_http_vars_hash_key(key, &v[i].name); 639 == 0)
390 640 {
391 cv = ngx_http_core_variables_hash[key].elts; 641 v[i].handler = av[n].handler;
392 for (j = 0; j < ngx_http_core_variables_hash[key].nelts; j++) { 642 v[i].data = av[n].data;
393 if (cv[j].name.len != v[i].name.len) { 643 v[i].flags = av[n].flags;
394 continue; 644
645 goto next;
395 } 646 }
396 647 }
397 if (ngx_strncmp(cv[j].name.data, v[i].name.data, v[i].name.len) 648
398 == 0) 649 if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
399 {
400 v[i].handler = cv[j].handler;
401 v[i].data = cv[j].data;
402 continue;
403 }
404 }
405
406 if (ngx_strncmp(v[i].name.data, "HTTP_", 5) == 0) {
407 v[i].handler = ngx_http_variable_unknown_header; 650 v[i].handler = ngx_http_variable_unknown_header;
408 v[i].data = (uintptr_t) &v[i].name; 651 v[i].data = (uintptr_t) &v[i].name;
652
409 continue; 653 continue;
410 } 654 }
411 655
412 ngx_log_error(NGX_LOG_ERR, cycle->log, 0, 656 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
413 "unknown \"%V\" variable", &v[i].name); 657 "unknown \"%V\" variable", &v[i].name);
414 658
415 return NGX_ERROR; 659 return NGX_ERROR;
416 } 660
661 next:
662 continue;
663 }
664
665 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
666 "http variables: %ui", cmcf->variables.nelts);
667
668
669 /* init the all http variables hash */
670
671 cmcf->variables_hash.max_size = 500;
672 cmcf->variables_hash.bucket_limit = 1;
673 cmcf->variables_hash.bucket_size = sizeof(ngx_http_variable_t);
674 cmcf->variables_hash.name = "http variables";
675
676 if (ngx_hash_init(&cmcf->variables_hash, cf->pool,
677 cmcf->all_variables.elts, cmcf->all_variables.nelts) != NGX_OK)
678 {
679 return NGX_ERROR;
680 }
681
682 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
683 "http variables hash size: %ui for %ui values, "
684 "max buckets per entry: %ui",
685 cmcf->variables_hash.hash_size, cmcf->all_variables.nelts,
686 cmcf->variables_hash.min_buckets);
417 687
418 return NGX_OK; 688 return NGX_OK;
419 } 689 }