Mercurial > hg > nginx-vendor-0-5
comparison src/http/modules/ngx_http_referer_module.c @ 326:f70f2f565fe0 NGINX_0_5_33
nginx 0.5.33
*) Change: now by default the "echo" SSI command uses entity encoding.
*) Feature: the "encoding" parameter in the "echo" SSI command.
*) Change: mail proxy was split on three modules: pop3, imap and smtp.
*) Feature: the --without-mail_pop3_module, --without-mail_imap_module,
and --without-mail_smtp_module configuration parameters.
*) Feature: the "smtp_greeting_delay" and "smtp_client_buffer"
directives of the ngx_mail_smtp_module.
*) Feature: the "server_name" and "valid_referers" directives support
regular expressions.
*) Feature: the "server_name", "map", and "valid_referers" directives
support the "www.example.*" wildcards.
*) Bugfix: sub_filter did not work with empty substitution.
*) Bugfix: in sub_filter parsing.
*) Bugfix: a worker process may got caught in an endless loop, if the
memcached was used.
*) Bugfix: nginx supported low case only "close" and "keep-alive"
values in the "Connection" request header line; bug appeared in
0.5.32.
*) Bugfix: nginx could not start on Solaris if the shared PCRE library
located in non-standard place was used.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Wed, 07 Nov 2007 00:00:00 +0300 |
parents | 95d92ec39071 |
children | 26ff8d6b618d |
comparison
equal
deleted
inserted
replaced
325:5bb1b28ddeaa | 326:f70f2f565fe0 |
---|---|
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 | 11 |
12 #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) | 12 #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) |
13 | 13 |
14 #if (NGX_PCRE) | |
15 | |
14 typedef struct { | 16 typedef struct { |
15 ngx_hash_t hash; | 17 ngx_regex_t *regex; |
16 ngx_hash_wildcard_t *dns_wildcards; | 18 ngx_str_t name; |
19 } ngx_http_referer_regex_t; | |
20 | |
21 #else | |
22 | |
23 #define ngx_regex_t void | |
24 | |
25 #endif | |
26 | |
27 | |
28 typedef struct { | |
29 ngx_hash_combined_t hash; | |
30 | |
31 #if (NGX_PCRE) | |
32 ngx_array_t *regex; | |
33 #endif | |
17 | 34 |
18 ngx_flag_t no_referer; | 35 ngx_flag_t no_referer; |
19 ngx_flag_t blocked_referer; | 36 ngx_flag_t blocked_referer; |
20 | 37 |
21 ngx_hash_keys_arrays_t *keys; | 38 ngx_hash_keys_arrays_t *keys; |
27 void *child); | 44 void *child); |
28 static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, | 45 static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, |
29 void *conf); | 46 void *conf); |
30 static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, | 47 static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, |
31 ngx_str_t *value, ngx_str_t *uri); | 48 ngx_str_t *value, ngx_str_t *uri); |
49 static char *ngx_http_add_regex_referer(ngx_conf_t *cf, | |
50 ngx_http_referer_conf_t *rlcf, ngx_str_t *name, ngx_regex_t *regex); | |
32 static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, | 51 static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, |
33 const void *two); | 52 const void *two); |
34 | 53 |
35 | 54 |
36 static ngx_command_t ngx_http_referer_commands[] = { | 55 static ngx_command_t ngx_http_referer_commands[] = { |
79 | 98 |
80 static ngx_int_t | 99 static ngx_int_t |
81 ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | 100 ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, |
82 uintptr_t data) | 101 uintptr_t data) |
83 { | 102 { |
84 u_char *p, *ref, *last; | 103 u_char *p, *ref, *last; |
85 size_t len; | 104 size_t len; |
86 ngx_str_t *uri; | 105 ngx_str_t *uri; |
87 ngx_uint_t i, key; | 106 ngx_uint_t i, key; |
88 ngx_http_referer_conf_t *rlcf; | 107 ngx_http_referer_conf_t *rlcf; |
89 u_char buf[256]; | 108 u_char buf[256]; |
109 #if (NGX_PCRE) | |
110 ngx_int_t n; | |
111 ngx_str_t referer; | |
112 ngx_http_referer_regex_t *regex; | |
113 #endif | |
90 | 114 |
91 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); | 115 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); |
92 | 116 |
93 if (rlcf->hash.buckets == NULL && rlcf->dns_wildcards == NULL) { | 117 if (rlcf->hash.hash.buckets == NULL |
118 && rlcf->hash.wc_head == NULL | |
119 && rlcf->hash.wc_tail == NULL | |
120 #if (NGX_PCRE) | |
121 && rlcf->regex == NULL | |
122 #endif | |
123 ) | |
124 { | |
94 goto valid; | 125 goto valid; |
95 } | 126 } |
96 | 127 |
97 if (r->headers_in.referer == NULL) { | 128 if (r->headers_in.referer == NULL) { |
98 if (rlcf->no_referer) { | 129 if (rlcf->no_referer) { |
131 if (i == 256) { | 162 if (i == 256) { |
132 goto invalid; | 163 goto invalid; |
133 } | 164 } |
134 } | 165 } |
135 | 166 |
136 len = p - ref; | 167 uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref); |
137 | 168 |
138 if (rlcf->hash.buckets) { | 169 if (uri) { |
139 uri = ngx_hash_find(&rlcf->hash, key, buf, len); | 170 goto uri; |
140 if (uri) { | 171 } |
141 goto uri; | 172 |
142 } | 173 #if (NGX_PCRE) |
143 } | 174 |
144 | 175 if (rlcf->regex) { |
145 if (rlcf->dns_wildcards) { | 176 |
146 uri = ngx_hash_find_wildcard(rlcf->dns_wildcards, buf, len); | 177 referer.len = len - 7; |
147 if (uri) { | 178 referer.data = ref; |
148 goto uri; | 179 |
149 } | 180 regex = rlcf->regex->elts; |
150 } | 181 |
182 for (i = 0; i < rlcf->regex->nelts; i++) { | |
183 n = ngx_regex_exec(regex[i].regex, &referer, NULL, 0); | |
184 | |
185 if (n == NGX_REGEX_NO_MATCHED) { | |
186 continue; | |
187 } | |
188 | |
189 if (n < 0) { | |
190 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
191 ngx_regex_exec_n | |
192 " failed: %d on \"%V\" using \"%V\"", | |
193 n, &referer, ®ex[i].name); | |
194 return NGX_ERROR; | |
195 } | |
196 | |
197 /* match */ | |
198 | |
199 goto valid; | |
200 } | |
201 } | |
202 | |
203 #endif | |
151 | 204 |
152 invalid: | 205 invalid: |
153 | 206 |
154 *v = ngx_http_variable_true_value; | 207 *v = ngx_http_variable_true_value; |
155 | 208 |
206 | 259 |
207 ngx_hash_init_t hash; | 260 ngx_hash_init_t hash; |
208 | 261 |
209 if (conf->keys == NULL) { | 262 if (conf->keys == NULL) { |
210 conf->hash = prev->hash; | 263 conf->hash = prev->hash; |
211 conf->dns_wildcards = prev->dns_wildcards; | |
212 | 264 |
213 ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); | 265 ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); |
214 ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); | 266 ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); |
215 | 267 |
216 return NGX_CONF_OK; | 268 return NGX_CONF_OK; |
217 } | 269 } |
218 | 270 |
219 if ((conf->no_referer == 1 || conf->blocked_referer == 1) | 271 if ((conf->no_referer == 1 || conf->blocked_referer == 1) |
220 && conf->keys->keys.nelts == 0 && conf->keys->dns_wildcards.nelts == 0) | 272 && conf->keys->keys.nelts == 0 |
273 && conf->keys->dns_wc_head.nelts == 0 | |
274 && conf->keys->dns_wc_tail.nelts == 0) | |
221 { | 275 { |
222 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | 276 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, |
223 "the \"none\" or \"blocked\" referers are specified " | 277 "the \"none\" or \"blocked\" referers are specified " |
224 "in the \"valid_referers\" directive " | 278 "in the \"valid_referers\" directive " |
225 "without any valid referer"); | 279 "without any valid referer"); |
231 hash.bucket_size = 64; /* TODO: referer_hash_bucket_size; */ | 285 hash.bucket_size = 64; /* TODO: referer_hash_bucket_size; */ |
232 hash.name = "referers_hash"; | 286 hash.name = "referers_hash"; |
233 hash.pool = cf->pool; | 287 hash.pool = cf->pool; |
234 | 288 |
235 if (conf->keys->keys.nelts) { | 289 if (conf->keys->keys.nelts) { |
236 hash.hash = &conf->hash; | 290 hash.hash = &conf->hash.hash; |
237 hash.temp_pool = NULL; | 291 hash.temp_pool = NULL; |
238 | 292 |
239 if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) | 293 if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) |
240 != NGX_OK) | 294 != NGX_OK) |
241 { | 295 { |
242 return NGX_CONF_ERROR; | 296 return NGX_CONF_ERROR; |
243 } | 297 } |
244 } | 298 } |
245 | 299 |
246 if (conf->keys->dns_wildcards.nelts) { | 300 if (conf->keys->dns_wc_head.nelts) { |
247 | 301 |
248 ngx_qsort(conf->keys->dns_wildcards.elts, | 302 ngx_qsort(conf->keys->dns_wc_head.elts, |
249 (size_t) conf->keys->dns_wildcards.nelts, | 303 (size_t) conf->keys->dns_wc_head.nelts, |
250 sizeof(ngx_hash_key_t), | 304 sizeof(ngx_hash_key_t), |
251 ngx_http_cmp_referer_wildcards); | 305 ngx_http_cmp_referer_wildcards); |
252 | 306 |
253 hash.hash = NULL; | 307 hash.hash = NULL; |
254 hash.temp_pool = cf->temp_pool; | 308 hash.temp_pool = cf->temp_pool; |
255 | 309 |
256 if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wildcards.elts, | 310 if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts, |
257 conf->keys->dns_wildcards.nelts) | 311 conf->keys->dns_wc_head.nelts) |
258 != NGX_OK) | 312 != NGX_OK) |
259 { | 313 { |
260 return NGX_CONF_ERROR; | 314 return NGX_CONF_ERROR; |
261 } | 315 } |
262 | 316 |
263 conf->dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; | 317 conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; |
318 } | |
319 | |
320 if (conf->keys->dns_wc_tail.nelts) { | |
321 | |
322 ngx_qsort(conf->keys->dns_wc_tail.elts, | |
323 (size_t) conf->keys->dns_wc_tail.nelts, | |
324 sizeof(ngx_hash_key_t), | |
325 ngx_http_cmp_referer_wildcards); | |
326 | |
327 hash.hash = NULL; | |
328 hash.temp_pool = cf->temp_pool; | |
329 | |
330 if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts, | |
331 conf->keys->dns_wc_tail.nelts) | |
332 != NGX_OK) | |
333 { | |
334 return NGX_CONF_ERROR; | |
335 } | |
336 | |
337 conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; | |
264 } | 338 } |
265 | 339 |
266 if (conf->no_referer == NGX_CONF_UNSET) { | 340 if (conf->no_referer == NGX_CONF_UNSET) { |
267 conf->no_referer = 0; | 341 conf->no_referer = 0; |
268 } | 342 } |
340 | 414 |
341 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); | 415 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); |
342 | 416 |
343 sn = cscf->server_names.elts; | 417 sn = cscf->server_names.elts; |
344 for (n = 0; n < cscf->server_names.nelts; n++) { | 418 for (n = 0; n < cscf->server_names.nelts; n++) { |
419 | |
420 #if (NGX_PCRE) | |
421 if (sn[n].regex) { | |
422 | |
423 if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name, | |
424 sn[n].regex) | |
425 != NGX_OK) | |
426 { | |
427 return NGX_CONF_ERROR; | |
428 } | |
429 | |
430 continue; | |
431 } | |
432 #endif | |
433 | |
345 if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri) | 434 if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri) |
346 != NGX_OK) | 435 != NGX_OK) |
347 { | 436 { |
348 return NGX_CONF_ERROR; | 437 return NGX_CONF_ERROR; |
349 } | 438 } |
350 } | 439 } |
351 | 440 |
352 continue; | 441 continue; |
353 } | 442 } |
354 | 443 |
444 if (value[i].data[0] == '~') { | |
445 if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK) | |
446 { | |
447 return NGX_CONF_ERROR; | |
448 } | |
449 | |
450 continue; | |
451 } | |
452 | |
355 p = (u_char *) ngx_strchr(value[i].data, '/'); | 453 p = (u_char *) ngx_strchr(value[i].data, '/'); |
356 | 454 |
357 if (p) { | 455 if (p) { |
358 uri.len = (value[i].data + value[i].len) - p; | 456 uri.len = (value[i].data + value[i].len) - p; |
359 uri.data = p; | 457 uri.data = p; |
371 | 469 |
372 static char * | 470 static char * |
373 ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, | 471 ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, |
374 ngx_str_t *value, ngx_str_t *uri) | 472 ngx_str_t *value, ngx_str_t *uri) |
375 { | 473 { |
376 u_char ch; | 474 ngx_int_t rc; |
377 ngx_int_t rc; | 475 ngx_str_t *u; |
378 ngx_str_t *u; | |
379 ngx_uint_t flags; | |
380 | |
381 ch = value->data[0]; | |
382 | |
383 if ((ch == '*' && (value->len < 3 || value->data[1] != '.')) | |
384 || (ch == '.' && value->len < 2)) | |
385 { | |
386 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
387 "invalid DNS wildcard \"%V\"", value); | |
388 | |
389 return NGX_CONF_ERROR; | |
390 } | |
391 | |
392 flags = (ch == '*' || ch == '.') ? NGX_HASH_WILDCARD_KEY : 0; | |
393 | 476 |
394 if (uri->len == 0) { | 477 if (uri->len == 0) { |
395 u = NGX_HTTP_REFERER_NO_URI_PART; | 478 u = NGX_HTTP_REFERER_NO_URI_PART; |
396 | 479 |
397 } else { | 480 } else { |
401 } | 484 } |
402 | 485 |
403 *u = *uri; | 486 *u = *uri; |
404 } | 487 } |
405 | 488 |
406 rc = ngx_hash_add_key(keys, value, u, flags); | 489 rc = ngx_hash_add_key(keys, value, u, NGX_HASH_WILDCARD_KEY); |
407 | 490 |
408 if (rc == NGX_OK) { | 491 if (rc == NGX_OK) { |
409 return NGX_CONF_OK; | 492 return NGX_CONF_OK; |
493 } | |
494 | |
495 if (rc == NGX_DECLINED) { | |
496 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
497 "invalid hostname or wildcard \"%V\"", value); | |
410 } | 498 } |
411 | 499 |
412 if (rc == NGX_BUSY) { | 500 if (rc == NGX_BUSY) { |
413 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 501 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
414 "conflicting parameter \"%V\"", value); | 502 "conflicting parameter \"%V\"", value); |
416 | 504 |
417 return NGX_CONF_ERROR; | 505 return NGX_CONF_ERROR; |
418 } | 506 } |
419 | 507 |
420 | 508 |
509 static char * | |
510 ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, | |
511 ngx_str_t *name, ngx_regex_t *regex) | |
512 { | |
513 #if (NGX_PCRE) | |
514 ngx_str_t err; | |
515 ngx_http_referer_regex_t *rr; | |
516 u_char errstr[NGX_MAX_CONF_ERRSTR]; | |
517 | |
518 if (rlcf->regex == NULL) { | |
519 rlcf->regex = ngx_array_create(cf->pool, 2, | |
520 sizeof(ngx_http_referer_regex_t)); | |
521 if (rlcf->regex == NULL) { | |
522 return NGX_CONF_ERROR; | |
523 } | |
524 } | |
525 | |
526 rr = ngx_array_push(rlcf->regex); | |
527 if (rr == NULL) { | |
528 return NGX_CONF_ERROR; | |
529 } | |
530 | |
531 if (regex) { | |
532 rr->regex = regex; | |
533 rr->name = *name; | |
534 | |
535 return NGX_CONF_OK; | |
536 } | |
537 | |
538 err.len = NGX_MAX_CONF_ERRSTR; | |
539 err.data = errstr; | |
540 | |
541 name->len--; | |
542 name->data++; | |
543 | |
544 rr->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); | |
545 | |
546 if (rr->regex == NULL) { | |
547 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); | |
548 return NGX_CONF_ERROR; | |
549 } | |
550 | |
551 rr->name = *name; | |
552 | |
553 return NGX_CONF_OK; | |
554 | |
555 #else | |
556 | |
557 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
558 "the using of the regex \"%V\" requires PCRE library", | |
559 name); | |
560 | |
561 return NGX_CONF_ERROR; | |
562 | |
563 #endif | |
564 } | |
565 | |
566 | |
421 static int ngx_libc_cdecl | 567 static int ngx_libc_cdecl |
422 ngx_http_cmp_referer_wildcards(const void *one, const void *two) | 568 ngx_http_cmp_referer_wildcards(const void *one, const void *two) |
423 { | 569 { |
424 ngx_hash_key_t *first, *second; | 570 ngx_hash_key_t *first, *second; |
425 | 571 |