Mercurial > hg > nginx
comparison src/http/modules/ngx_http_referer_module.c @ 593:425af804d968 release-0.3.18
nginx-0.3.18-RELEASE import
*) Feature: the "server_names" directive supports the ".domain.tld"
names.
*) Feature: the "server_names" directive uses the hash for the
"*.domain.tld" names and more effective hash for usual names.
*) Change: the "server_names_hash_max_size" and
"server_names_hash_bucket_size" directives.
*) Change: the "server_names_hash" and "server_names_hash_threshold"
directives were canceled.
*) Feature: the "valid_referers" directive uses the hash site names.
*) Change: now the "valid_referers" directive checks the site names
only without the URI part.
*) Bugfix: some ".domain.tld" names incorrectly processed by the
ngx_http_map_module.
*) Bugfix: segmentation fault was occurred if configuration file did
not exist; the bug had appeared in 0.3.12.
*) Bugfix: on 64-bit platforms segmentation fault may occurred on
start; the bug had appeared in 0.3.16.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 26 Dec 2005 17:07:48 +0000 |
parents | 4e296b7d25bf |
children | ebc68d8ca496 |
comparison
equal
deleted
inserted
replaced
592:8b2e7f727cd0 | 593:425af804d968 |
---|---|
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 | 11 |
12 typedef struct { | 12 typedef struct { |
13 ngx_str_t name; | 13 ngx_hash_t hash; |
14 ngx_uint_t wildcard; | 14 ngx_hash_wildcard_t *dns_wildcards; |
15 } ngx_http_referer_t; | 15 |
16 | 16 ngx_flag_t no_referer; |
17 typedef struct { | 17 ngx_flag_t blocked_referer; |
18 ngx_array_t *referers; /* ngx_http_referer_t */ | 18 |
19 | 19 ngx_hash_keys_arrays_t *keys; |
20 ngx_flag_t no_referer; | |
21 ngx_flag_t blocked_referer; | |
22 } ngx_http_referer_conf_t; | 20 } ngx_http_referer_conf_t; |
23 | 21 |
24 | 22 |
25 static void * ngx_http_referer_create_conf(ngx_conf_t *cf); | 23 static void * ngx_http_referer_create_conf(ngx_conf_t *cf); |
26 static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, | 24 static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, |
27 void *child); | 25 void *child); |
28 static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, | 26 static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, |
29 void *conf); | 27 void *conf); |
28 static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, | |
29 ngx_str_t *value); | |
30 static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, | |
31 const void *two); | |
30 | 32 |
31 | 33 |
32 static ngx_command_t ngx_http_referer_commands[] = { | 34 static ngx_command_t ngx_http_referer_commands[] = { |
33 | 35 |
34 { ngx_string("valid_referers"), | 36 { ngx_string("valid_referers"), |
75 | 77 |
76 static ngx_int_t | 78 static ngx_int_t |
77 ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | 79 ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, |
78 uintptr_t data) | 80 uintptr_t data) |
79 { | 81 { |
80 u_char *ref; | 82 u_char *p, *ref; |
81 size_t len; | 83 size_t len; |
82 ngx_uint_t i, n; | 84 ngx_http_referer_conf_t *rlcf; |
83 ngx_http_referer_t *refs; | 85 |
84 ngx_http_referer_conf_t *cf; | 86 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); |
85 | 87 |
86 cf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); | 88 if (rlcf->hash.buckets == NULL |
87 | 89 && rlcf->dns_wildcards == NULL |
88 if (cf->referers == NULL) { | 90 && rlcf->dns_wildcards->hash.buckets == NULL) |
91 { | |
89 *v = ngx_http_variable_null_value; | 92 *v = ngx_http_variable_null_value; |
90 return NGX_OK; | 93 return NGX_OK; |
91 } | 94 } |
92 | 95 |
93 if (r->headers_in.referer == NULL) { | 96 if (r->headers_in.referer == NULL) { |
94 if (cf->no_referer) { | 97 if (rlcf->no_referer) { |
95 *v = ngx_http_variable_null_value; | 98 *v = ngx_http_variable_null_value; |
96 return NGX_OK; | 99 return NGX_OK; |
97 | 100 |
98 } else { | 101 } else { |
99 *v = ngx_http_variable_true_value; | 102 *v = ngx_http_variable_true_value; |
105 ref = r->headers_in.referer->value.data; | 108 ref = r->headers_in.referer->value.data; |
106 | 109 |
107 if (len < sizeof("http://i.ru") - 1 | 110 if (len < sizeof("http://i.ru") - 1 |
108 || (ngx_strncasecmp(ref, "http://", 7) != 0)) | 111 || (ngx_strncasecmp(ref, "http://", 7) != 0)) |
109 { | 112 { |
110 if (cf->blocked_referer) { | 113 if (rlcf->blocked_referer) { |
111 *v = ngx_http_variable_null_value; | 114 *v = ngx_http_variable_null_value; |
112 return NGX_OK; | 115 return NGX_OK; |
113 | 116 |
114 } else { | 117 } else { |
115 *v = ngx_http_variable_true_value; | 118 *v = ngx_http_variable_true_value; |
118 } | 121 } |
119 | 122 |
120 len -= 7; | 123 len -= 7; |
121 ref += 7; | 124 ref += 7; |
122 | 125 |
123 refs = cf->referers->elts; | 126 for (p = ref; p < ref + len; p++) { |
124 for (i = 0; i < cf->referers->nelts; i++ ){ | 127 if (*p == '/' || *p == ':') { |
125 | 128 break; |
126 if (refs[i].name.len > len) { | 129 } |
127 continue; | 130 } |
128 } | 131 |
129 | 132 len = p - ref; |
130 if (refs[i].wildcard) { | 133 |
131 for (n = 0; n < len; n++) { | 134 if (rlcf->hash.buckets) { |
132 if (ref[n] == '/' || ref[n] == ':') { | 135 if (ngx_hash_find(&rlcf->hash, ngx_hash_key_lc(ref, len), ref, len)) { |
133 break; | 136 *v = ngx_http_variable_null_value; |
134 } | 137 return NGX_OK; |
135 | 138 } |
136 if (ref[n] != '.') { | 139 } |
137 continue; | 140 |
138 } | 141 if (rlcf->dns_wildcards && rlcf->dns_wildcards->hash.buckets) { |
139 | 142 if (ngx_hash_find_wildcard(rlcf->dns_wildcards, ref, len)) { |
140 if (ngx_strncmp(&ref[n], refs[i].name.data, | 143 *v = ngx_http_variable_null_value; |
141 refs[i].name.len) == 0) | 144 return NGX_OK; |
142 { | |
143 *v = ngx_http_variable_null_value; | |
144 return NGX_OK; | |
145 } | |
146 } | |
147 | |
148 } else { | |
149 if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0) | |
150 { | |
151 *v = ngx_http_variable_null_value; | |
152 return NGX_OK; | |
153 } | |
154 } | 145 } |
155 } | 146 } |
156 | 147 |
157 *v = ngx_http_variable_true_value; | 148 *v = ngx_http_variable_true_value; |
158 | 149 |
163 static void * | 154 static void * |
164 ngx_http_referer_create_conf(ngx_conf_t *cf) | 155 ngx_http_referer_create_conf(ngx_conf_t *cf) |
165 { | 156 { |
166 ngx_http_referer_conf_t *conf; | 157 ngx_http_referer_conf_t *conf; |
167 | 158 |
168 conf = ngx_palloc(cf->pool, sizeof(ngx_http_referer_conf_t)); | 159 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t)); |
169 if (conf == NULL) { | 160 if (conf == NULL) { |
170 return NGX_CONF_ERROR; | 161 return NGX_CONF_ERROR; |
171 } | 162 } |
172 | 163 |
173 conf->referers = NULL; | |
174 conf->no_referer = NGX_CONF_UNSET; | 164 conf->no_referer = NGX_CONF_UNSET; |
175 conf->blocked_referer = NGX_CONF_UNSET; | 165 conf->blocked_referer = NGX_CONF_UNSET; |
176 | 166 |
177 return conf; | 167 return conf; |
178 } | 168 } |
182 ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) | 172 ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
183 { | 173 { |
184 ngx_http_referer_conf_t *prev = parent; | 174 ngx_http_referer_conf_t *prev = parent; |
185 ngx_http_referer_conf_t *conf = child; | 175 ngx_http_referer_conf_t *conf = child; |
186 | 176 |
187 if (conf->referers == NULL) { | 177 ngx_hash_init_t hash; |
188 conf->referers = prev->referers; | 178 |
179 if (conf->keys == NULL) { | |
180 conf->hash = prev->hash; | |
181 conf->dns_wildcards = prev->dns_wildcards; | |
182 | |
189 ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); | 183 ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); |
190 ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); | 184 ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); |
185 | |
186 return NGX_CONF_OK; | |
187 } | |
188 | |
189 hash.key = ngx_hash_key_lc; | |
190 hash.max_size = 2048; /* TODO: referer_hash_max_size; */ | |
191 hash.bucket_size = 64; /* TODO: referer_hash_bucket_size; */ | |
192 hash.name = "referers_hash"; | |
193 hash.pool = cf->pool; | |
194 | |
195 if (conf->keys->keys.nelts) { | |
196 hash.hash = &conf->hash; | |
197 hash.temp_pool = NULL; | |
198 | |
199 if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) | |
200 != NGX_OK) | |
201 { | |
202 return NGX_CONF_ERROR; | |
203 } | |
204 } | |
205 | |
206 if (conf->keys->dns_wildcards.nelts) { | |
207 | |
208 ngx_qsort(conf->keys->dns_wildcards.elts, | |
209 (size_t) conf->keys->dns_wildcards.nelts, | |
210 sizeof(ngx_hash_key_t), | |
211 ngx_http_cmp_referer_wildcards); | |
212 | |
213 hash.hash = NULL; | |
214 hash.temp_pool = cf->temp_pool; | |
215 | |
216 if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wildcards.elts, | |
217 conf->keys->dns_wildcards.nelts) | |
218 != NGX_OK) | |
219 { | |
220 return NGX_CONF_ERROR; | |
221 } | |
222 | |
223 conf->dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; | |
191 } | 224 } |
192 | 225 |
193 if (conf->no_referer == NGX_CONF_UNSET) { | 226 if (conf->no_referer == NGX_CONF_UNSET) { |
194 conf->no_referer = 0; | 227 conf->no_referer = 0; |
195 } | 228 } |
203 | 236 |
204 | 237 |
205 static char * | 238 static char * |
206 ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 239 ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
207 { | 240 { |
208 ngx_http_referer_conf_t *lcf = conf; | 241 ngx_http_referer_conf_t *rlcf = conf; |
209 | 242 |
210 ngx_uint_t i, server_names; | 243 u_char *p; |
211 ngx_str_t *value, name; | 244 ngx_str_t *value, name; |
212 ngx_http_referer_t *ref; | 245 ngx_uint_t i, n; |
213 ngx_http_variable_t *var; | 246 ngx_http_variable_t *var; |
214 ngx_http_server_name_t *sn; | 247 ngx_http_server_name_t *sn; |
215 ngx_http_core_srv_conf_t *cscf; | 248 ngx_http_core_srv_conf_t *cscf; |
216 | 249 |
217 name.len = sizeof("invalid_referer") - 1; | 250 name.len = sizeof("invalid_referer") - 1; |
223 return NGX_CONF_ERROR; | 256 return NGX_CONF_ERROR; |
224 } | 257 } |
225 | 258 |
226 var->handler = ngx_http_referer_variable; | 259 var->handler = ngx_http_referer_variable; |
227 | 260 |
228 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); | 261 if (rlcf->keys == NULL) { |
229 | 262 rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); |
230 if (lcf->referers == NULL) { | 263 if (rlcf->keys == NULL) { |
231 lcf->referers = ngx_array_create(cf->pool, | 264 return NGX_CONF_ERROR; |
232 cf->args->nelts + cscf->server_names.nelts, | 265 } |
233 sizeof(ngx_http_referer_t)); | 266 |
234 if (lcf->referers == NULL) { | 267 rlcf->keys->pool = cf->pool; |
268 rlcf->keys->temp_pool = cf->pool; | |
269 | |
270 if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) { | |
235 return NGX_CONF_ERROR; | 271 return NGX_CONF_ERROR; |
236 } | 272 } |
237 } | 273 } |
238 | 274 |
239 value = cf->args->elts; | 275 value = cf->args->elts; |
240 server_names = 0; | |
241 | 276 |
242 for (i = 1; i < cf->args->nelts; i++) { | 277 for (i = 1; i < cf->args->nelts; i++) { |
243 if (value[i].len == 0) { | 278 if (value[i].len == 0) { |
244 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 279 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
245 "invalid referer \"%V\"", &value[i]); | 280 "invalid referer \"%V\"", &value[i]); |
246 return NGX_CONF_ERROR; | 281 return NGX_CONF_ERROR; |
247 } | 282 } |
248 | 283 |
249 if (ngx_strcmp(value[i].data, "none") == 0) { | 284 if (ngx_strcmp(value[i].data, "none") == 0) { |
250 lcf->no_referer = 1; | 285 rlcf->no_referer = 1; |
251 continue; | 286 continue; |
252 } | 287 } |
253 | 288 |
254 if (ngx_strcmp(value[i].data, "blocked") == 0) { | 289 if (ngx_strcmp(value[i].data, "blocked") == 0) { |
255 lcf->blocked_referer = 1; | 290 rlcf->blocked_referer = 1; |
256 continue; | 291 continue; |
257 } | 292 } |
258 | 293 |
259 if (ngx_strcmp(value[i].data, "server_names") == 0) { | 294 if (ngx_strcmp(value[i].data, "server_names") == 0) { |
260 server_names = 1; | 295 |
296 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); | |
297 | |
298 sn = cscf->server_names.elts; | |
299 for (n = 0; n < cscf->server_names.nelts; n++) { | |
300 if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name) != NGX_OK) { | |
301 return NGX_CONF_ERROR; | |
302 } | |
303 } | |
304 | |
261 continue; | 305 continue; |
262 } | 306 } |
263 | 307 |
264 ref = ngx_array_push(lcf->referers); | 308 p = (u_char *) ngx_strstr(value[i].data, "/"); |
265 if (ref == NULL) { | 309 |
266 return NGX_CONF_ERROR; | 310 if (p) { |
267 } | |
268 | |
269 if (value[i].data[0] != '*') { | |
270 ref->name = value[i]; | |
271 ref->wildcard = 0; | |
272 continue; | |
273 } | |
274 | |
275 | |
276 if (value[i].data[1] != '.') { | |
277 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 311 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
278 "invalid wildcard referer \"%V\"", &value[i]); | 312 "URI part \"%s\" is deprecated, ignored", p); |
279 return NGX_CONF_ERROR; | 313 |
280 } | 314 value[i].len = p - value[i].data; |
281 | 315 } |
282 ref->name.len = value[i].len - 1; | 316 |
283 ref->name.data = value[i].data + 1; | 317 if (ngx_http_add_referer(cf, rlcf->keys, &value[i]) != NGX_OK) { |
284 ref->wildcard = 1; | 318 return NGX_CONF_ERROR; |
285 } | 319 } |
286 | 320 } |
287 if (!server_names) { | 321 |
322 return NGX_CONF_OK; | |
323 } | |
324 | |
325 | |
326 static char * | |
327 ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, | |
328 ngx_str_t *value) | |
329 { | |
330 u_char ch; | |
331 ngx_int_t rc; | |
332 ngx_uint_t flags; | |
333 | |
334 ch = value->data[0]; | |
335 | |
336 if ((ch == '*' && (value->len < 3 || value->data[1] != '.')) | |
337 || (ch == '.' && value->len < 2)) | |
338 { | |
339 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
340 "invalid DNS wildcard \"%V\"", value); | |
341 | |
342 return NGX_CONF_ERROR; | |
343 } | |
344 | |
345 flags = (ch == '*' || ch == '.') ? NGX_HASH_WILDCARD_KEY : 0; | |
346 | |
347 rc = ngx_hash_add_key(keys, value, (void *) 4, flags); | |
348 | |
349 if (rc == NGX_OK) { | |
288 return NGX_CONF_OK; | 350 return NGX_CONF_OK; |
289 } | 351 } |
290 | 352 |
291 sn = cscf->server_names.elts; | 353 if (rc == NGX_BUSY) { |
292 for (i = 0; i < cscf->server_names.nelts; i++) { | 354 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
293 ref = ngx_array_push(lcf->referers); | 355 "conflicting parameter \"%V\"", value); |
294 if (ref == NULL) { | 356 } |
295 return NGX_CONF_ERROR; | 357 |
296 } | 358 return NGX_CONF_ERROR; |
297 | 359 } |
298 ref->name.len = sn[i].name.len + 1; | 360 |
299 ref->name.data = ngx_palloc(cf->pool, ref->name.len); | 361 |
300 if (ref->name.data == NULL) { | 362 static int ngx_libc_cdecl |
301 return NGX_CONF_ERROR; | 363 ngx_http_cmp_referer_wildcards(const void *one, const void *two) |
302 } | 364 { |
303 | 365 ngx_hash_key_t *first, *second; |
304 ngx_memcpy(ref->name.data, sn[i].name.data, sn[i].name.len); | 366 |
305 ref->name.data[sn[i].name.len] = '/'; | 367 first = (ngx_hash_key_t *) one; |
306 ref->wildcard = sn[i].wildcard; | 368 second = (ngx_hash_key_t *) two; |
307 } | 369 |
308 | 370 return ngx_strcmp(first->key.data, second->key.data); |
309 return NGX_CONF_OK; | 371 } |
310 } |