1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyev#define NGX_HTTP_REFERER_NO_URI_PART  ((void *) 4)
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyevtypedef struct {
17e18a033bSKonstantin Ananyev    ngx_hash_combined_t      hash;
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyev#if (NGX_PCRE)
20e18a033bSKonstantin Ananyev    ngx_array_t             *regex;
21e18a033bSKonstantin Ananyev    ngx_array_t             *server_name_regex;
22e18a033bSKonstantin Ananyev#endif
23e18a033bSKonstantin Ananyev
24e18a033bSKonstantin Ananyev    ngx_flag_t               no_referer;
25e18a033bSKonstantin Ananyev    ngx_flag_t               blocked_referer;
26e18a033bSKonstantin Ananyev    ngx_flag_t               server_names;
27e18a033bSKonstantin Ananyev
28e18a033bSKonstantin Ananyev    ngx_hash_keys_arrays_t  *keys;
29e18a033bSKonstantin Ananyev
30e18a033bSKonstantin Ananyev    ngx_uint_t               referer_hash_max_size;
31e18a033bSKonstantin Ananyev    ngx_uint_t               referer_hash_bucket_size;
32e18a033bSKonstantin Ananyev} ngx_http_referer_conf_t;
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyevstatic void * ngx_http_referer_create_conf(ngx_conf_t *cf);
36e18a033bSKonstantin Ananyevstatic char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent,
37e18a033bSKonstantin Ananyev    void *child);
38e18a033bSKonstantin Ananyevstatic char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
39e18a033bSKonstantin Ananyev    void *conf);
40e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_add_referer(ngx_conf_t *cf,
41e18a033bSKonstantin Ananyev    ngx_hash_keys_arrays_t *keys, ngx_str_t *value, ngx_str_t *uri);
42e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_add_regex_referer(ngx_conf_t *cf,
43e18a033bSKonstantin Ananyev    ngx_http_referer_conf_t *rlcf, ngx_str_t *name);
44e18a033bSKonstantin Ananyev#if (NGX_PCRE)
45e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_add_regex_server_name(ngx_conf_t *cf,
46e18a033bSKonstantin Ananyev    ngx_http_referer_conf_t *rlcf, ngx_http_regex_t *regex);
47e18a033bSKonstantin Ananyev#endif
48e18a033bSKonstantin Ananyevstatic int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one,
49e18a033bSKonstantin Ananyev    const void *two);
50e18a033bSKonstantin Ananyev
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_referer_commands[] = {
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyev    { ngx_string("valid_referers"),
55e18a033bSKonstantin Ananyev      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
56e18a033bSKonstantin Ananyev      ngx_http_valid_referers,
57e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
58e18a033bSKonstantin Ananyev      0,
59e18a033bSKonstantin Ananyev      NULL },
60e18a033bSKonstantin Ananyev
61e18a033bSKonstantin Ananyev    { ngx_string("referer_hash_max_size"),
62e18a033bSKonstantin Ananyev      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
63e18a033bSKonstantin Ananyev      ngx_conf_set_num_slot,
64e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
65e18a033bSKonstantin Ananyev      offsetof(ngx_http_referer_conf_t, referer_hash_max_size),
66e18a033bSKonstantin Ananyev      NULL },
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyev    { ngx_string("referer_hash_bucket_size"),
69e18a033bSKonstantin Ananyev      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
70e18a033bSKonstantin Ananyev      ngx_conf_set_num_slot,
71e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
72e18a033bSKonstantin Ananyev      offsetof(ngx_http_referer_conf_t, referer_hash_bucket_size),
73e18a033bSKonstantin Ananyev      NULL },
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyev      ngx_null_command
76e18a033bSKonstantin Ananyev};
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_referer_module_ctx = {
80e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
81e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
82e18a033bSKonstantin Ananyev
83e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
84e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
85e18a033bSKonstantin Ananyev
86e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
87e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
88e18a033bSKonstantin Ananyev
89e18a033bSKonstantin Ananyev    ngx_http_referer_create_conf,          /* create location configuration */
90e18a033bSKonstantin Ananyev    ngx_http_referer_merge_conf            /* merge location configuration */
91e18a033bSKonstantin Ananyev};
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyevngx_module_t  ngx_http_referer_module = {
95e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
96e18a033bSKonstantin Ananyev    &ngx_http_referer_module_ctx,          /* module context */
97e18a033bSKonstantin Ananyev    ngx_http_referer_commands,             /* module directives */
98e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
99e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
100e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
101e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
102e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
103e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
104e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
105e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
106e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
107e18a033bSKonstantin Ananyev};
108e18a033bSKonstantin Ananyev
109e18a033bSKonstantin Ananyev
110e18a033bSKonstantin Ananyevstatic ngx_int_t
111e18a033bSKonstantin Ananyevngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
112e18a033bSKonstantin Ananyev    uintptr_t data)
113e18a033bSKonstantin Ananyev{
114e18a033bSKonstantin Ananyev    u_char                    *p, *ref, *last;
115e18a033bSKonstantin Ananyev    size_t                     len;
116e18a033bSKonstantin Ananyev    ngx_str_t                 *uri;
117e18a033bSKonstantin Ananyev    ngx_uint_t                 i, key;
118e18a033bSKonstantin Ananyev    ngx_http_referer_conf_t   *rlcf;
119e18a033bSKonstantin Ananyev    u_char                     buf[256];
120e18a033bSKonstantin Ananyev#if (NGX_PCRE)
121e18a033bSKonstantin Ananyev    ngx_int_t                  rc;
122e18a033bSKonstantin Ananyev    ngx_str_t                  referer;
123e18a033bSKonstantin Ananyev#endif
124e18a033bSKonstantin Ananyev
125e18a033bSKonstantin Ananyev    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module);
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev    if (rlcf->hash.hash.buckets == NULL
128e18a033bSKonstantin Ananyev        && rlcf->hash.wc_head == NULL
129e18a033bSKonstantin Ananyev        && rlcf->hash.wc_tail == NULL
130e18a033bSKonstantin Ananyev#if (NGX_PCRE)
131e18a033bSKonstantin Ananyev        && rlcf->regex == NULL
132e18a033bSKonstantin Ananyev        && rlcf->server_name_regex == NULL
133e18a033bSKonstantin Ananyev#endif
134e18a033bSKonstantin Ananyev       )
135e18a033bSKonstantin Ananyev    {
136e18a033bSKonstantin Ananyev        goto valid;
137e18a033bSKonstantin Ananyev    }
138e18a033bSKonstantin Ananyev
139e18a033bSKonstantin Ananyev    if (r->headers_in.referer == NULL) {
140e18a033bSKonstantin Ananyev        if (rlcf->no_referer) {
141e18a033bSKonstantin Ananyev            goto valid;
142e18a033bSKonstantin Ananyev        }
143e18a033bSKonstantin Ananyev
144e18a033bSKonstantin Ananyev        goto invalid;
145e18a033bSKonstantin Ananyev    }
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyev    len = r->headers_in.referer->value.len;
148e18a033bSKonstantin Ananyev    ref = r->headers_in.referer->value.data;
149e18a033bSKonstantin Ananyev
150e18a033bSKonstantin Ananyev    if (len >= sizeof("http://i.ru") - 1) {
151e18a033bSKonstantin Ananyev        last = ref + len;
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyev        if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) {
154e18a033bSKonstantin Ananyev            ref += 7;
155e18a033bSKonstantin Ananyev            len -= 7;
156e18a033bSKonstantin Ananyev            goto valid_scheme;
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev        } else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) {
159e18a033bSKonstantin Ananyev            ref += 8;
160e18a033bSKonstantin Ananyev            len -= 8;
161e18a033bSKonstantin Ananyev            goto valid_scheme;
162e18a033bSKonstantin Ananyev        }
163e18a033bSKonstantin Ananyev    }
164e18a033bSKonstantin Ananyev
165e18a033bSKonstantin Ananyev    if (rlcf->blocked_referer) {
166e18a033bSKonstantin Ananyev        goto valid;
167e18a033bSKonstantin Ananyev    }
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    goto invalid;
170e18a033bSKonstantin Ananyev
171e18a033bSKonstantin Ananyevvalid_scheme:
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev    i = 0;
174e18a033bSKonstantin Ananyev    key = 0;
175e18a033bSKonstantin Ananyev
176e18a033bSKonstantin Ananyev    for (p = ref; p < last; p++) {
177e18a033bSKonstantin Ananyev        if (*p == '/' || *p == ':') {
178e18a033bSKonstantin Ananyev            break;
179e18a033bSKonstantin Ananyev        }
180e18a033bSKonstantin Ananyev
181e18a033bSKonstantin Ananyev        if (i == 256) {
182e18a033bSKonstantin Ananyev            goto invalid;
183e18a033bSKonstantin Ananyev        }
184e18a033bSKonstantin Ananyev
185e18a033bSKonstantin Ananyev        buf[i] = ngx_tolower(*p);
186e18a033bSKonstantin Ananyev        key = ngx_hash(key, buf[i++]);
187e18a033bSKonstantin Ananyev    }
188e18a033bSKonstantin Ananyev
189e18a033bSKonstantin Ananyev    uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref);
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyev    if (uri) {
192e18a033bSKonstantin Ananyev        goto uri;
193e18a033bSKonstantin Ananyev    }
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev#if (NGX_PCRE)
196e18a033bSKonstantin Ananyev
197e18a033bSKonstantin Ananyev    if (rlcf->server_name_regex) {
198e18a033bSKonstantin Ananyev        referer.len = p - ref;
199e18a033bSKonstantin Ananyev        referer.data = buf;
200e18a033bSKonstantin Ananyev
201e18a033bSKonstantin Ananyev        rc = ngx_regex_exec_array(rlcf->server_name_regex, &referer,
202e18a033bSKonstantin Ananyev                                  r->connection->log);
203e18a033bSKonstantin Ananyev
204e18a033bSKonstantin Ananyev        if (rc == NGX_OK) {
205e18a033bSKonstantin Ananyev            goto valid;
206e18a033bSKonstantin Ananyev        }
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev        if (rc == NGX_ERROR) {
209e18a033bSKonstantin Ananyev            return rc;
210e18a033bSKonstantin Ananyev        }
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyev        /* NGX_DECLINED */
213e18a033bSKonstantin Ananyev    }
214e18a033bSKonstantin Ananyev
215e18a033bSKonstantin Ananyev    if (rlcf->regex) {
216e18a033bSKonstantin Ananyev        referer.len = len;
217e18a033bSKonstantin Ananyev        referer.data = ref;
218e18a033bSKonstantin Ananyev
219e18a033bSKonstantin Ananyev        rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log);
220e18a033bSKonstantin Ananyev
221e18a033bSKonstantin Ananyev        if (rc == NGX_OK) {
222e18a033bSKonstantin Ananyev            goto valid;
223e18a033bSKonstantin Ananyev        }
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev        if (rc == NGX_ERROR) {
226e18a033bSKonstantin Ananyev            return rc;
227e18a033bSKonstantin Ananyev        }
228e18a033bSKonstantin Ananyev
229e18a033bSKonstantin Ananyev        /* NGX_DECLINED */
230e18a033bSKonstantin Ananyev    }
231e18a033bSKonstantin Ananyev
232e18a033bSKonstantin Ananyev#endif
233e18a033bSKonstantin Ananyev
234e18a033bSKonstantin Ananyevinvalid:
235e18a033bSKonstantin Ananyev
236e18a033bSKonstantin Ananyev    *v = ngx_http_variable_true_value;
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev    return NGX_OK;
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyevuri:
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev    for ( /* void */ ; p < last; p++) {
243e18a033bSKonstantin Ananyev        if (*p == '/') {
244e18a033bSKonstantin Ananyev            break;
245e18a033bSKonstantin Ananyev        }
246e18a033bSKonstantin Ananyev    }
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev    len = last - p;
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev    if (uri == NGX_HTTP_REFERER_NO_URI_PART) {
251e18a033bSKonstantin Ananyev        goto valid;
252e18a033bSKonstantin Ananyev    }
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    if (len < uri->len || ngx_strncmp(uri->data, p, uri->len) != 0) {
255e18a033bSKonstantin Ananyev        goto invalid;
256e18a033bSKonstantin Ananyev    }
257e18a033bSKonstantin Ananyev
258e18a033bSKonstantin Ananyevvalid:
259e18a033bSKonstantin Ananyev
260e18a033bSKonstantin Ananyev    *v = ngx_http_variable_null_value;
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyev    return NGX_OK;
263e18a033bSKonstantin Ananyev}
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyevstatic void *
267e18a033bSKonstantin Ananyevngx_http_referer_create_conf(ngx_conf_t *cf)
268e18a033bSKonstantin Ananyev{
269e18a033bSKonstantin Ananyev    ngx_http_referer_conf_t  *conf;
270e18a033bSKonstantin Ananyev
271e18a033bSKonstantin Ananyev    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t));
272e18a033bSKonstantin Ananyev    if (conf == NULL) {
273e18a033bSKonstantin Ananyev        return NULL;
274e18a033bSKonstantin Ananyev    }
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    /*
277e18a033bSKonstantin Ananyev     * set by ngx_pcalloc():
278e18a033bSKonstantin Ananyev     *
279e18a033bSKonstantin Ananyev     *     conf->hash = { NULL };
280e18a033bSKonstantin Ananyev     *     conf->server_names = 0;
281e18a033bSKonstantin Ananyev     *     conf->keys = NULL;
282e18a033bSKonstantin Ananyev     */
283e18a033bSKonstantin Ananyev
284e18a033bSKonstantin Ananyev#if (NGX_PCRE)
285e18a033bSKonstantin Ananyev    conf->regex = NGX_CONF_UNSET_PTR;
286e18a033bSKonstantin Ananyev    conf->server_name_regex = NGX_CONF_UNSET_PTR;
287e18a033bSKonstantin Ananyev#endif
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev    conf->no_referer = NGX_CONF_UNSET;
290e18a033bSKonstantin Ananyev    conf->blocked_referer = NGX_CONF_UNSET;
291e18a033bSKonstantin Ananyev    conf->referer_hash_max_size = NGX_CONF_UNSET_UINT;
292e18a033bSKonstantin Ananyev    conf->referer_hash_bucket_size = NGX_CONF_UNSET_UINT;
293e18a033bSKonstantin Ananyev
294e18a033bSKonstantin Ananyev    return conf;
295e18a033bSKonstantin Ananyev}
296e18a033bSKonstantin Ananyev
297e18a033bSKonstantin Ananyev
298e18a033bSKonstantin Ananyevstatic char *
299e18a033bSKonstantin Ananyevngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child)
300e18a033bSKonstantin Ananyev{
301e18a033bSKonstantin Ananyev    ngx_http_referer_conf_t *prev = parent;
302e18a033bSKonstantin Ananyev    ngx_http_referer_conf_t *conf = child;
303e18a033bSKonstantin Ananyev
304e18a033bSKonstantin Ananyev    ngx_uint_t                 n;
305e18a033bSKonstantin Ananyev    ngx_hash_init_t            hash;
306e18a033bSKonstantin Ananyev    ngx_http_server_name_t    *sn;
307e18a033bSKonstantin Ananyev    ngx_http_core_srv_conf_t  *cscf;
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev    if (conf->keys == NULL) {
310e18a033bSKonstantin Ananyev        conf->hash = prev->hash;
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev#if (NGX_PCRE)
313e18a033bSKonstantin Ananyev        ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
314e18a033bSKonstantin Ananyev        ngx_conf_merge_ptr_value(conf->server_name_regex,
315e18a033bSKonstantin Ananyev                                 prev->server_name_regex, NULL);
316e18a033bSKonstantin Ananyev#endif
317e18a033bSKonstantin Ananyev        ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
318e18a033bSKonstantin Ananyev        ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0);
319e18a033bSKonstantin Ananyev        ngx_conf_merge_uint_value(conf->referer_hash_max_size,
320e18a033bSKonstantin Ananyev                                  prev->referer_hash_max_size, 2048);
321e18a033bSKonstantin Ananyev        ngx_conf_merge_uint_value(conf->referer_hash_bucket_size,
322e18a033bSKonstantin Ananyev                                  prev->referer_hash_bucket_size, 64);
323e18a033bSKonstantin Ananyev
324e18a033bSKonstantin Ananyev        return NGX_CONF_OK;
325e18a033bSKonstantin Ananyev    }
326e18a033bSKonstantin Ananyev
327e18a033bSKonstantin Ananyev    if (conf->server_names == 1) {
328e18a033bSKonstantin Ananyev        cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
329e18a033bSKonstantin Ananyev
330e18a033bSKonstantin Ananyev        sn = cscf->server_names.elts;
331e18a033bSKonstantin Ananyev        for (n = 0; n < cscf->server_names.nelts; n++) {
332e18a033bSKonstantin Ananyev
333e18a033bSKonstantin Ananyev#if (NGX_PCRE)
334e18a033bSKonstantin Ananyev            if (sn[n].regex) {
335e18a033bSKonstantin Ananyev
336e18a033bSKonstantin Ananyev                if (ngx_http_add_regex_server_name(cf, conf, sn[n].regex)
337e18a033bSKonstantin Ananyev                    != NGX_OK)
338e18a033bSKonstantin Ananyev                {
339e18a033bSKonstantin Ananyev                    return NGX_CONF_ERROR;
340e18a033bSKonstantin Ananyev                }
341e18a033bSKonstantin Ananyev
342e18a033bSKonstantin Ananyev                continue;
343e18a033bSKonstantin Ananyev            }
344e18a033bSKonstantin Ananyev#endif
345e18a033bSKonstantin Ananyev
346e18a033bSKonstantin Ananyev            if (ngx_http_add_referer(cf, conf->keys, &sn[n].name, NULL)
347e18a033bSKonstantin Ananyev                != NGX_OK)
348e18a033bSKonstantin Ananyev            {
349e18a033bSKonstantin Ananyev                return NGX_CONF_ERROR;
350e18a033bSKonstantin Ananyev            }
351e18a033bSKonstantin Ananyev        }
352e18a033bSKonstantin Ananyev    }
353e18a033bSKonstantin Ananyev
354e18a033bSKonstantin Ananyev    if ((conf->no_referer == 1 || conf->blocked_referer == 1)
355e18a033bSKonstantin Ananyev        && conf->keys->keys.nelts == 0
356e18a033bSKonstantin Ananyev        && conf->keys->dns_wc_head.nelts == 0
357e18a033bSKonstantin Ananyev        && conf->keys->dns_wc_tail.nelts == 0)
358e18a033bSKonstantin Ananyev    {
359e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
360e18a033bSKonstantin Ananyev                      "the \"none\" or \"blocked\" referers are specified "
361e18a033bSKonstantin Ananyev                      "in the \"valid_referers\" directive "
362e18a033bSKonstantin Ananyev                      "without any valid referer");
363e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
364e18a033bSKonstantin Ananyev    }
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyev    ngx_conf_merge_uint_value(conf->referer_hash_max_size,
367e18a033bSKonstantin Ananyev                              prev->referer_hash_max_size, 2048);
368e18a033bSKonstantin Ananyev    ngx_conf_merge_uint_value(conf->referer_hash_bucket_size,
369e18a033bSKonstantin Ananyev                              prev->referer_hash_bucket_size, 64);
370e18a033bSKonstantin Ananyev    conf->referer_hash_bucket_size = ngx_align(conf->referer_hash_bucket_size,
371e18a033bSKonstantin Ananyev                                               ngx_cacheline_size);
372e18a033bSKonstantin Ananyev
373e18a033bSKonstantin Ananyev    hash.key = ngx_hash_key_lc;
374e18a033bSKonstantin Ananyev    hash.max_size = conf->referer_hash_max_size;
375e18a033bSKonstantin Ananyev    hash.bucket_size = conf->referer_hash_bucket_size;
376e18a033bSKonstantin Ananyev    hash.name = "referer_hash";
377e18a033bSKonstantin Ananyev    hash.pool = cf->pool;
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyev    if (conf->keys->keys.nelts) {
380e18a033bSKonstantin Ananyev        hash.hash = &conf->hash.hash;
381e18a033bSKonstantin Ananyev        hash.temp_pool = NULL;
382e18a033bSKonstantin Ananyev
383e18a033bSKonstantin Ananyev        if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts)
384e18a033bSKonstantin Ananyev            != NGX_OK)
385e18a033bSKonstantin Ananyev        {
386e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
387e18a033bSKonstantin Ananyev        }
388e18a033bSKonstantin Ananyev    }
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev    if (conf->keys->dns_wc_head.nelts) {
391e18a033bSKonstantin Ananyev
392e18a033bSKonstantin Ananyev        ngx_qsort(conf->keys->dns_wc_head.elts,
393e18a033bSKonstantin Ananyev                  (size_t) conf->keys->dns_wc_head.nelts,
394e18a033bSKonstantin Ananyev                  sizeof(ngx_hash_key_t),
395e18a033bSKonstantin Ananyev                  ngx_http_cmp_referer_wildcards);
396e18a033bSKonstantin Ananyev
397e18a033bSKonstantin Ananyev        hash.hash = NULL;
398e18a033bSKonstantin Ananyev        hash.temp_pool = cf->temp_pool;
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev        if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts,
401e18a033bSKonstantin Ananyev                                   conf->keys->dns_wc_head.nelts)
402e18a033bSKonstantin Ananyev            != NGX_OK)
403e18a033bSKonstantin Ananyev        {
404e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
405e18a033bSKonstantin Ananyev        }
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev        conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
408e18a033bSKonstantin Ananyev    }
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev    if (conf->keys->dns_wc_tail.nelts) {
411e18a033bSKonstantin Ananyev
412e18a033bSKonstantin Ananyev        ngx_qsort(conf->keys->dns_wc_tail.elts,
413e18a033bSKonstantin Ananyev                  (size_t) conf->keys->dns_wc_tail.nelts,
414e18a033bSKonstantin Ananyev                  sizeof(ngx_hash_key_t),
415e18a033bSKonstantin Ananyev                  ngx_http_cmp_referer_wildcards);
416e18a033bSKonstantin Ananyev
417e18a033bSKonstantin Ananyev        hash.