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, &regex[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