Mercurial > hg > nginx-vendor-current
comparison src/http/ngx_http_variables.c @ 48:6cfc63e68377 NGINX_0_1_24
nginx 0.1.24
*) Feature: the ngx_http_ssi_filter_module supports the QUERY_STRING
and DOCUMENT_URI variables.
*) Bugfix: the ngx_http_autoindex_module may some times return the 404
response for existent directory, if this directory was used in
"alias" directive.
*) Bugfix: the ngx_http_ssi_filter_module ran incorrectly for large
responses.
*) Bugfix: the lack of the "Referer" header line was always accounted
as valid referrer.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Fri, 04 Mar 2005 00:00:00 +0300 |
parents | |
children | 72eb30262aac |
comparison
equal
deleted
inserted
replaced
47:4ae32548452c | 48:6cfc63e68377 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 #define NGX_HTTP_VARS_HASH_PRIME 29 | |
14 | |
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 * | |
26 ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data); | |
27 static ngx_http_variable_value_t * | |
28 ngx_http_variable_unknown_header(ngx_http_request_t *r, ngx_str_t *var); | |
29 static ngx_http_variable_value_t * | |
30 ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data); | |
31 static ngx_http_variable_value_t * | |
32 ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data); | |
33 static ngx_http_variable_value_t * | |
34 ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data); | |
35 | |
36 | |
37 static ngx_array_t *ngx_http_core_variables_hash; | |
38 | |
39 | |
40 static ngx_http_core_variable_t ngx_http_core_variables[] = { | |
41 | |
42 { ngx_string("HTTP_HOST"), ngx_http_variable_header, | |
43 offsetof(ngx_http_headers_in_t, host) }, | |
44 | |
45 { ngx_string("HTTP_USER_AGENT"), ngx_http_variable_header, | |
46 offsetof(ngx_http_headers_in_t, user_agent) }, | |
47 | |
48 { ngx_string("HTTP_REFERER"), ngx_http_variable_header, | |
49 offsetof(ngx_http_headers_in_t, referer) }, | |
50 | |
51 #if (NGX_HTTP_GZIP) | |
52 { ngx_string("HTTP_VIA"), ngx_http_variable_header, | |
53 offsetof(ngx_http_headers_in_t, via) }, | |
54 #endif | |
55 | |
56 #if (NGX_HTTP_PROXY) | |
57 { ngx_string("HTTP_X_FORWARDED_FOR"), ngx_http_variable_header, | |
58 offsetof(ngx_http_headers_in_t, x_forwarded_for) }, | |
59 #endif | |
60 | |
61 { ngx_string("REMOTE_ADDR"), ngx_http_variable_remote_addr, 0 }, | |
62 | |
63 { ngx_string("DOCUMENT_URI"), ngx_http_variable_uri, 0 }, | |
64 | |
65 { ngx_string("QUERY_STRING"), ngx_http_variable_query_string, 0 }, | |
66 | |
67 { ngx_null_string, NULL, 0 } | |
68 }; | |
69 | |
70 | |
71 ngx_http_variable_t * | |
72 ngx_http_add_variable(ngx_conf_t *cf) | |
73 { | |
74 ngx_http_variable_t *var; | |
75 ngx_http_core_main_conf_t *cmcf; | |
76 | |
77 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
78 | |
79 if (cmcf->variables.elts == NULL) { | |
80 if (ngx_array_init(&cmcf->variables, cf->pool, 4, | |
81 sizeof(ngx_http_variable_t)) == NGX_ERROR) | |
82 { | |
83 return NULL; | |
84 } | |
85 } | |
86 | |
87 if (!(var = ngx_array_push(&cmcf->variables))) { | |
88 return NULL; | |
89 } | |
90 | |
91 var->index = cmcf->variables.nelts - 1; | |
92 | |
93 return var; | |
94 } | |
95 | |
96 | |
97 ngx_http_variable_value_t * | |
98 ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index) | |
99 { | |
100 ngx_http_variable_t *var; | |
101 ngx_http_core_main_conf_t *cmcf; | |
102 | |
103 /* TODO: cached variables */ | |
104 | |
105 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
106 | |
107 if (cmcf->variables.elts == NULL || cmcf->variables.nelts <= index) { | |
108 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
109 "unknown variable index: %d", index); | |
110 return NULL; | |
111 } | |
112 | |
113 var = cmcf->variables.elts; | |
114 | |
115 return var[index].handler(r, var[index].data); | |
116 } | |
117 | |
118 | |
119 ngx_int_t | |
120 ngx_http_get_variable_index(ngx_http_core_main_conf_t *cmcf, ngx_str_t *name) | |
121 { | |
122 ngx_uint_t i; | |
123 ngx_http_variable_t *var; | |
124 | |
125 var = cmcf->variables.elts; | |
126 for (i = 0; i < cmcf->variables.nelts; i++) { | |
127 if (var[i].name.len != name->len) { | |
128 continue; | |
129 } | |
130 | |
131 if (ngx_strncasecmp(var[i].name.data, name->data, name->len) == 0) { | |
132 return var[i].index; | |
133 } | |
134 } | |
135 | |
136 return -1; | |
137 } | |
138 | |
139 | |
140 ngx_http_variable_value_t * | |
141 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name) | |
142 { | |
143 ngx_int_t index; | |
144 ngx_uint_t i, key; | |
145 ngx_http_core_variable_t *var; | |
146 ngx_http_core_main_conf_t *cmcf; | |
147 | |
148 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
149 | |
150 index = ngx_http_get_variable_index(cmcf, name); | |
151 | |
152 if (index != -1) { | |
153 return ngx_http_get_indexed_variable(r, index); | |
154 } | |
155 | |
156 ngx_http_vars_hash_key(key, name); | |
157 | |
158 var = ngx_http_core_variables_hash[key].elts; | |
159 for (i = 0; i < ngx_http_core_variables_hash[key].nelts; i++) { | |
160 | |
161 if (var[i].name.len != name->len | |
162 || ngx_strncasecmp(var[i].name.data, name->data, name->len) != 0) | |
163 { | |
164 continue; | |
165 } | |
166 | |
167 return var[i].handler(r, var[i].data); | |
168 } | |
169 | |
170 if (ngx_strncasecmp(name->data, "HTTP_", 5) != 0) { | |
171 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
172 "unknown \"%V\" variable", name); | |
173 return NGX_HTTP_VARIABLE_NOT_FOUND; | |
174 } | |
175 | |
176 return ngx_http_variable_unknown_header(r, name); | |
177 } | |
178 | |
179 | |
180 static ngx_http_variable_value_t * | |
181 ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data) | |
182 { | |
183 ngx_table_elt_t *h; | |
184 ngx_http_variable_value_t *v; | |
185 | |
186 h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); | |
187 | |
188 if (h == NULL) { | |
189 return NGX_HTTP_VARIABLE_NOT_FOUND; | |
190 } | |
191 | |
192 if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { | |
193 return NULL; | |
194 } | |
195 | |
196 v->value = 0; | |
197 v->text = h->value; | |
198 | |
199 return v; | |
200 } | |
201 | |
202 | |
203 static ngx_http_variable_value_t * | |
204 ngx_http_variable_unknown_header(ngx_http_request_t *r, ngx_str_t *var) | |
205 { | |
206 u_char ch; | |
207 ngx_uint_t i, n; | |
208 ngx_list_part_t *part; | |
209 ngx_table_elt_t *header; | |
210 ngx_http_variable_value_t *v; | |
211 | |
212 part = &r->headers_in.headers.part; | |
213 header = part->elts; | |
214 | |
215 for (i = 0; /* void */ ; i++) { | |
216 | |
217 if (i >= part->nelts) { | |
218 if (part->next == NULL) { | |
219 break; | |
220 } | |
221 | |
222 part = part->next; | |
223 header = part->elts; | |
224 i = 0; | |
225 } | |
226 | |
227 for (n = 0; n + 5 < var->len && n < header[i].key.len; n++) | |
228 { | |
229 ch = header[i].key.data[n]; | |
230 | |
231 if (ch >= 'a' && ch <= 'z') { | |
232 ch &= ~0x20; | |
233 | |
234 } else if (ch == '-') { | |
235 ch = '_'; | |
236 } | |
237 | |
238 if (var->data[n + 5] != ch) { | |
239 break; | |
240 } | |
241 } | |
242 | |
243 if (n + 5 == var->len) { | |
244 if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { | |
245 return NULL; | |
246 } | |
247 | |
248 v->value = 0; | |
249 v->text = header[i].value; | |
250 return v; | |
251 } | |
252 } | |
253 | |
254 return NGX_HTTP_VARIABLE_NOT_FOUND; | |
255 } | |
256 | |
257 | |
258 static ngx_http_variable_value_t * | |
259 ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data) | |
260 { | |
261 ngx_http_variable_value_t *v; | |
262 | |
263 if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { | |
264 return NULL; | |
265 } | |
266 | |
267 v->value = 0; | |
268 v->text = r->connection->addr_text; | |
269 | |
270 return v; | |
271 } | |
272 | |
273 | |
274 static ngx_http_variable_value_t * | |
275 ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data) | |
276 { | |
277 ngx_http_variable_value_t *v; | |
278 | |
279 if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { | |
280 return NULL; | |
281 } | |
282 | |
283 v->value = 0; | |
284 v->text = r->uri; | |
285 | |
286 return v; | |
287 } | |
288 | |
289 | |
290 static ngx_http_variable_value_t * | |
291 ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data) | |
292 { | |
293 ngx_http_variable_value_t *v; | |
294 | |
295 if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { | |
296 return NULL; | |
297 } | |
298 | |
299 v->value = 0; | |
300 v->text = r->args; | |
301 | |
302 return v; | |
303 } | |
304 | |
305 | |
306 ngx_int_t | |
307 ngx_http_core_variables_init(ngx_cycle_t *cycle) | |
308 { | |
309 ngx_uint_t i, key; | |
310 ngx_http_core_variable_t *var, *v; | |
311 | |
312 ngx_http_core_variables_hash = ngx_palloc(cycle->pool, | |
313 NGX_HTTP_VARS_HASH_PRIME | |
314 * sizeof(ngx_array_t)); | |
315 if (ngx_http_core_variables_hash == NULL) { | |
316 return NGX_ERROR; | |
317 } | |
318 | |
319 for (i = 0; i < NGX_HTTP_VARS_HASH_PRIME; i++) { | |
320 if (ngx_array_init(&ngx_http_core_variables_hash[i], cycle->pool, 4, | |
321 sizeof(ngx_http_core_variable_t)) == NGX_ERROR) | |
322 { | |
323 return NGX_ERROR; | |
324 } | |
325 } | |
326 | |
327 for (var = ngx_http_core_variables; var->name.len; var++) { | |
328 ngx_http_vars_hash_key(key, &var->name); | |
329 | |
330 if (!(v = ngx_array_push(&ngx_http_core_variables_hash[key]))) { | |
331 return NGX_ERROR; | |
332 } | |
333 | |
334 *v = *var; | |
335 } | |
336 | |
337 return NGX_OK; | |
338 } |