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_stream.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevtypedef struct {
14e18a033bSKonstantin Ananyev    ngx_uint_t                    hash_max_size;
15e18a033bSKonstantin Ananyev    ngx_uint_t                    hash_bucket_size;
16e18a033bSKonstantin Ananyev} ngx_stream_map_conf_t;
17e18a033bSKonstantin Ananyev
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyevtypedef struct {
20e18a033bSKonstantin Ananyev    ngx_hash_keys_arrays_t        keys;
21e18a033bSKonstantin Ananyev
22e18a033bSKonstantin Ananyev    ngx_array_t                  *values_hash;
23e18a033bSKonstantin Ananyev#if (NGX_PCRE)
24e18a033bSKonstantin Ananyev    ngx_array_t                   regexes;
25e18a033bSKonstantin Ananyev#endif
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t  *default_value;
28e18a033bSKonstantin Ananyev    ngx_conf_t                   *cf;
29e18a033bSKonstantin Ananyev    unsigned                      hostnames:1;
30e18a033bSKonstantin Ananyev    unsigned                      no_cacheable:1;
31e18a033bSKonstantin Ananyev} ngx_stream_map_conf_ctx_t;
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyevtypedef struct {
35e18a033bSKonstantin Ananyev    ngx_stream_map_t              map;
36e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t    value;
37e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t  *default_value;
38e18a033bSKonstantin Ananyev    ngx_uint_t                    hostnames;      /* unsigned  hostnames:1 */
39e18a033bSKonstantin Ananyev} ngx_stream_map_ctx_t;
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyevstatic int ngx_libc_cdecl ngx_stream_map_cmp_dns_wildcards(const void *one,
43e18a033bSKonstantin Ananyev    const void *two);
44e18a033bSKonstantin Ananyevstatic void *ngx_stream_map_create_conf(ngx_conf_t *cf);
45e18a033bSKonstantin Ananyevstatic char *ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd,
46e18a033bSKonstantin Ananyev    void *conf);
47e18a033bSKonstantin Ananyevstatic char *ngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyev
50e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_stream_map_commands[] = {
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev    { ngx_string("map"),
53e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
54e18a033bSKonstantin Ananyev      ngx_stream_map_block,
55e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
56e18a033bSKonstantin Ananyev      0,
57e18a033bSKonstantin Ananyev      NULL },
58e18a033bSKonstantin Ananyev
59e18a033bSKonstantin Ananyev    { ngx_string("map_hash_max_size"),
60e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
61e18a033bSKonstantin Ananyev      ngx_conf_set_num_slot,
62e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
63e18a033bSKonstantin Ananyev      offsetof(ngx_stream_map_conf_t, hash_max_size),
64e18a033bSKonstantin Ananyev      NULL },
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev    { ngx_string("map_hash_bucket_size"),
67e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
68e18a033bSKonstantin Ananyev      ngx_conf_set_num_slot,
69e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
70e18a033bSKonstantin Ananyev      offsetof(ngx_stream_map_conf_t, hash_bucket_size),
71e18a033bSKonstantin Ananyev      NULL },
72e18a033bSKonstantin Ananyev
73e18a033bSKonstantin Ananyev      ngx_null_command
74e18a033bSKonstantin Ananyev};
75e18a033bSKonstantin Ananyev
76e18a033bSKonstantin Ananyev
77e18a033bSKonstantin Ananyevstatic ngx_stream_module_t  ngx_stream_map_module_ctx = {
78e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
79e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyev    ngx_stream_map_create_conf,            /* create main configuration */
82e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
85e18a033bSKonstantin Ananyev    NULL                                   /* merge server configuration */
86e18a033bSKonstantin Ananyev};
87e18a033bSKonstantin Ananyev
88e18a033bSKonstantin Ananyev
89e18a033bSKonstantin Ananyevngx_module_t  ngx_stream_map_module = {
90e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
91e18a033bSKonstantin Ananyev    &ngx_stream_map_module_ctx,            /* module context */
92e18a033bSKonstantin Ananyev    ngx_stream_map_commands,               /* module directives */
93e18a033bSKonstantin Ananyev    NGX_STREAM_MODULE,                     /* module type */
94e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
95e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
96e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
97e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
98e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
99e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
100e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
101e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
102e18a033bSKonstantin Ananyev};
103e18a033bSKonstantin Ananyev
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyevstatic ngx_int_t
106e18a033bSKonstantin Ananyevngx_stream_map_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v,
107e18a033bSKonstantin Ananyev    uintptr_t data)
108e18a033bSKonstantin Ananyev{
109e18a033bSKonstantin Ananyev    ngx_stream_map_ctx_t  *map = (ngx_stream_map_ctx_t *) data;
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyev    ngx_str_t                     val, str;
112e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t   *cv;
113e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t  *value;
114e18a033bSKonstantin Ananyev
115e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
116e18a033bSKonstantin Ananyev                   "stream map started");
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev    if (ngx_stream_complex_value(s, &map->value, &val) != NGX_OK) {
119e18a033bSKonstantin Ananyev        return NGX_ERROR;
120e18a033bSKonstantin Ananyev    }
121e18a033bSKonstantin Ananyev
122e18a033bSKonstantin Ananyev    if (map->hostnames && val.len > 0 && val.data[val.len - 1] == '.') {
123e18a033bSKonstantin Ananyev        val.len--;
124e18a033bSKonstantin Ananyev    }
125e18a033bSKonstantin Ananyev
126e18a033bSKonstantin Ananyev    value = ngx_stream_map_find(s, &map->map, &val);
127e18a033bSKonstantin Ananyev
128e18a033bSKonstantin Ananyev    if (value == NULL) {
129e18a033bSKonstantin Ananyev        value = map->default_value;
130e18a033bSKonstantin Ananyev    }
131e18a033bSKonstantin Ananyev
132e18a033bSKonstantin Ananyev    if (!value->valid) {
133e18a033bSKonstantin Ananyev        cv = (ngx_stream_complex_value_t *) value->data;
134e18a033bSKonstantin Ananyev
135e18a033bSKonstantin Ananyev        if (ngx_stream_complex_value(s, cv, &str) != NGX_OK) {
136e18a033bSKonstantin Ananyev            return NGX_ERROR;
137e18a033bSKonstantin Ananyev        }
138e18a033bSKonstantin Ananyev
139e18a033bSKonstantin Ananyev        v->valid = 1;
140e18a033bSKonstantin Ananyev        v->no_cacheable = 0;
141e18a033bSKonstantin Ananyev        v->not_found = 0;
142e18a033bSKonstantin Ananyev        v->len = str.len;
143e18a033bSKonstantin Ananyev        v->data = str.data;
144e18a033bSKonstantin Ananyev
145e18a033bSKonstantin Ananyev    } else {
146e18a033bSKonstantin Ananyev        *v = *value;
147e18a033bSKonstantin Ananyev    }
148e18a033bSKonstantin Ananyev
149e18a033bSKonstantin Ananyev    ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
150e18a033bSKonstantin Ananyev                   "stream map: \"%V\" \"%v\"", &val, v);
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev    return NGX_OK;
153e18a033bSKonstantin Ananyev}
154e18a033bSKonstantin Ananyev
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyevstatic void *
157e18a033bSKonstantin Ananyevngx_stream_map_create_conf(ngx_conf_t *cf)
158e18a033bSKonstantin Ananyev{
159e18a033bSKonstantin Ananyev    ngx_stream_map_conf_t  *mcf;
160e18a033bSKonstantin Ananyev
161e18a033bSKonstantin Ananyev    mcf = ngx_palloc(cf->pool, sizeof(ngx_stream_map_conf_t));
162e18a033bSKonstantin Ananyev    if (mcf == NULL) {
163e18a033bSKonstantin Ananyev        return NULL;
164e18a033bSKonstantin Ananyev    }
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev    mcf->hash_max_size = NGX_CONF_UNSET_UINT;
167e18a033bSKonstantin Ananyev    mcf->hash_bucket_size = NGX_CONF_UNSET_UINT;
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    return mcf;
170e18a033bSKonstantin Ananyev}
171e18a033bSKonstantin Ananyev
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyevstatic char *
174e18a033bSKonstantin Ananyevngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
175e18a033bSKonstantin Ananyev{
176e18a033bSKonstantin Ananyev    ngx_stream_map_conf_t  *mcf = conf;
177e18a033bSKonstantin Ananyev
178e18a033bSKonstantin Ananyev    char                                *rv;
179e18a033bSKonstantin Ananyev    ngx_str_t                           *value, name;
180e18a033bSKonstantin Ananyev    ngx_conf_t                           save;
181e18a033bSKonstantin Ananyev    ngx_pool_t                          *pool;
182e18a033bSKonstantin Ananyev    ngx_hash_init_t                      hash;
183e18a033bSKonstantin Ananyev    ngx_stream_map_ctx_t                *map;
184e18a033bSKonstantin Ananyev    ngx_stream_variable_t               *var;
185e18a033bSKonstantin Ananyev    ngx_stream_map_conf_ctx_t            ctx;
186e18a033bSKonstantin Ananyev    ngx_stream_compile_complex_value_t   ccv;
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyev    if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) {
189e18a033bSKonstantin Ananyev        mcf->hash_max_size = 2048;
190e18a033bSKonstantin Ananyev    }
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev    if (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) {
193e18a033bSKonstantin Ananyev        mcf->hash_bucket_size = ngx_cacheline_size;
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev    } else {
196e18a033bSKonstantin Ananyev        mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size,
197e18a033bSKonstantin Ananyev                                          ngx_cacheline_size);
198e18a033bSKonstantin Ananyev    }
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev    map = ngx_pcalloc(cf->pool, sizeof(ngx_stream_map_ctx_t));
201e18a033bSKonstantin Ananyev    if (map == NULL) {
202e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
203e18a033bSKonstantin Ananyev    }
204e18a033bSKonstantin Ananyev
205e18a033bSKonstantin Ananyev    value = cf->args->elts;
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyev    ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
208e18a033bSKonstantin Ananyev
209e18a033bSKonstantin Ananyev    ccv.cf = cf;
210e18a033bSKonstantin Ananyev    ccv.value = &value[1];
211e18a033bSKonstantin Ananyev    ccv.complex_value = &map->value;
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
214e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
215e18a033bSKonstantin Ananyev    }
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev    name = value[2];
218e18a033bSKonstantin Ananyev
219e18a033bSKonstantin Ananyev    if (name.data[0] != '$') {
220e18a033bSKonstantin Ananyev        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
221e18a033bSKonstantin Ananyev                           "invalid variable name \"%V\"", &name);
222e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
223e18a033bSKonstantin Ananyev    }
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev    name.len--;
226e18a033bSKonstantin Ananyev    name.data++;
227e18a033bSKonstantin Ananyev
228e18a033bSKonstantin Ananyev    var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
229e18a033bSKonstantin Ananyev    if (var == NULL) {
230e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
231e18a033bSKonstantin Ananyev    }
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev    var->get_handler = ngx_stream_map_variable;
234e18a033bSKonstantin Ananyev    var->data = (uintptr_t) map;
235e18a033bSKonstantin Ananyev
236e18a033bSKonstantin Ananyev    pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
237e18a033bSKonstantin Ananyev    if (pool == NULL) {
238e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
239e18a033bSKonstantin Ananyev    }
240e18a033bSKonstantin Ananyev
241e18a033bSKonstantin Ananyev    ctx.keys.pool = cf->pool;
242e18a033bSKonstantin Ananyev    ctx.keys.temp_pool = pool;
243e18a033bSKonstantin Ananyev
244e18a033bSKonstantin Ananyev    if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) {
245e18a033bSKonstantin Ananyev        ngx_destroy_pool(pool);
246e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
247e18a033bSKonstantin Ananyev    }
248e18a033bSKonstantin Ananyev
249e18a033bSKonstantin Ananyev    ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize);
250e18a033bSKonstantin Ananyev    if (ctx.values_hash == NULL) {
251e18a033bSKonstantin Ananyev        ngx_destroy_pool(pool);
252e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
253e18a033bSKonstantin Ananyev    }
254e18a033bSKonstantin Ananyev
255e18a033bSKonstantin Ananyev#if (NGX_PCRE)
256e18a033bSKonstantin Ananyev    if (ngx_array_init(&ctx.regexes, cf->pool, 2,
257e18a033bSKonstantin Ananyev                       sizeof(ngx_stream_map_regex_t))
258e18a033bSKonstantin Ananyev        != NGX_OK)
259e18a033bSKonstantin Ananyev    {
260e18a033bSKonstantin Ananyev        ngx_destroy_pool(pool);
261e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
262e18a033bSKonstantin Ananyev    }
263e18a033bSKonstantin Ananyev#endif
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyev    ctx.default_value = NULL;
266e18a033bSKonstantin Ananyev    ctx.cf = &save;
267e18a033bSKonstantin Ananyev    ctx.hostnames = 0;
268e18a033bSKonstantin Ananyev    ctx.no_cacheable = 0;
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev    save = *cf;
271e18a033bSKonstantin Ananyev    cf->pool = pool;
272e18a033bSKonstantin Ananyev    cf->ctx = &ctx;
273e18a033bSKonstantin Ananyev    cf->handler = ngx_stream_map;
274e18a033bSKonstantin Ananyev    cf->handler_conf = conf;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    rv = ngx_conf_parse(cf, NULL);
277e18a033bSKonstantin Ananyev
278e18a033bSKonstantin Ananyev    *cf = save;
279e18a033bSKonstantin Ananyev
280e18a033bSKonstantin Ananyev    if (rv != NGX_CONF_OK) {
281e18a033bSKonstantin Ananyev        ngx_destroy_pool(pool);
282e18a033bSKonstantin Ananyev        return rv;
283e18a033bSKonstantin Ananyev    }
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev    if (ctx.no_cacheable) {
286e18a033bSKonstantin Ananyev        var->flags |= NGX_STREAM_VAR_NOCACHEABLE;
287e18a033bSKonstantin Ananyev    }
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev    map->default_value = ctx.default_value ? ctx.default_value:
290e18a033bSKonstantin Ananyev                                             &ngx_stream_variable_null_value;
291e18a033bSKonstantin Ananyev
292e18a033bSKonstantin Ananyev    map->hostnames = ctx.hostnames;
293e18a033bSKonstantin Ananyev
294e18a033bSKonstantin Ananyev    hash.key = ngx_hash_key_lc;
295e18a033bSKonstantin Ananyev    hash.max_size = mcf->hash_max_size;
296e18a033bSKonstantin Ananyev    hash.bucket_size = mcf->hash_bucket_size;
297e18a033bSKonstantin Ananyev    hash.name = "map_hash";
298e18a033bSKonstantin Ananyev    hash.pool = cf->pool;
299e18a033bSKonstantin Ananyev
300e18a033bSKonstantin Ananyev    if (ctx.keys.keys.nelts) {
301e18a033bSKonstantin Ananyev        hash.hash = &map->map.hash.hash;
302e18a033bSKonstantin Ananyev        hash.temp_pool = NULL;
303e18a033bSKonstantin Ananyev
304e18a033bSKonstantin Ananyev        if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts)
305e18a033bSKonstantin Ananyev            != NGX_OK)
306e18a033bSKonstantin Ananyev        {
307e18a033bSKonstantin Ananyev            ngx_destroy_pool(pool);
308e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
309e18a033bSKonstantin Ananyev        }
310e18a033bSKonstantin Ananyev    }
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev    if (ctx.keys.dns_wc_head.nelts) {
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyev        ngx_qsort(ctx.keys.dns_wc_head.elts,
315e18a033bSKonstantin Ananyev                  (size_t) ctx.keys.dns_wc_head.nelts,
316e18a033bSKonstantin Ananyev                  sizeof(ngx_hash_key_t), ngx_stream_map_cmp_dns_wildcards);
317e18a033bSKonstantin Ananyev
318e18a033bSKonstantin Ananyev        hash.hash = NULL;
319e18a033bSKonstantin Ananyev        hash.temp_pool = pool;
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev        if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts,
322e18a033bSKonstantin Ananyev                                   ctx.keys.dns_wc_head.nelts)
323e18a033bSKonstantin Ananyev            != NGX_OK)
324e18a033bSKonstantin Ananyev        {
325e18a033bSKonstantin Ananyev            ngx_destroy_pool(pool);
326e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
327e18a033bSKonstantin Ananyev        }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev        map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
330e18a033bSKonstantin Ananyev    }
331e18a033bSKonstantin Ananyev
332e18a033bSKonstantin Ananyev    if (ctx.keys.dns_wc_tail.nelts) {
333e18a033bSKonstantin Ananyev
334e18a033bSKonstantin Ananyev        ngx_qsort(ctx.keys.dns_wc_tail.elts,
335e18a033bSKonstantin Ananyev                  (size_t) ctx.keys.dns_wc_tail.nelts,
336e18a033bSKonstantin Ananyev                  sizeof(ngx_hash_key_t), ngx_stream_map_cmp_dns_wildcards);
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev        hash.hash = NULL;
339e18a033bSKonstantin Ananyev        hash.temp_pool = pool;
340e18a033bSKonstantin Ananyev
341e18a033bSKonstantin Ananyev        if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts,
342e18a033bSKonstantin Ananyev                                   ctx.keys.dns_wc_tail.nelts)
343e18a033bSKonstantin Ananyev            != NGX_OK)
344e18a033bSKonstantin Ananyev        {
345e18a033bSKonstantin Ananyev            ngx_destroy_pool(pool);
346e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
347e18a033bSKonstantin Ananyev        }
348e18a033bSKonstantin Ananyev
349e18a033bSKonstantin Ananyev        map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
350e18a033bSKonstantin Ananyev    }
351e18a033bSKonstantin Ananyev
352e18a033bSKonstantin Ananyev#if (NGX_PCRE)
353e18a033bSKonstantin Ananyev
354e18a033bSKonstantin Ananyev    if (ctx.regexes.nelts) {
355e18a033bSKonstantin Ananyev        map->map.regex = ctx.regexes.elts;
356e18a033bSKonstantin Ananyev        map->map.nregex = ctx.regexes.nelts;
357e18a033bSKonstantin Ananyev    }
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev#endif
360e18a033bSKonstantin Ananyev
361e18a033bSKonstantin Ananyev    ngx_destroy_pool(pool);
362e18a033bSKonstantin Ananyev
363e18a033bSKonstantin Ananyev    return rv;
364e18a033bSKonstantin Ananyev}
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyev
367e18a033bSKonstantin Ananyevstatic int ngx_libc_cdecl
368e18a033bSKonstantin Ananyevngx_stream_map_cmp_dns_wildcards(const void *one, const void *two)
369e18a033bSKonstantin Ananyev{
370e18a033bSKonstantin Ananyev    ngx_hash_key_t  *first, *second;
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    first = (ngx_hash_key_t *) one;
373e18a033bSKonstantin Ananyev    second = (ngx_hash_key_t *) two;
374e18a033bSKonstantin Ananyev
375e18a033bSKonstantin Ananyev    return ngx_dns_strcmp(first->key.data, second->key.data);
376e18a033bSKonstantin Ananyev}
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyevstatic char *
380e18a033bSKonstantin Ananyevngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
381e18a033bSKonstantin Ananyev{
382e18a033bSKonstantin Ananyev    u_char                              *data;
383e18a033bSKonstantin Ananyev    size_t                               len;
384e18a033bSKonstantin Ananyev    ngx_int_t                            rv;
385e18a033bSKonstantin Ananyev    ngx_str_t                           *value, v;
386e18a033bSKonstantin Ananyev    ngx_uint_t                           i, key;
387e18a033bSKonstantin Ananyev    ngx_stream_map_conf_ctx_t           *ctx;
388e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t           cv, *cvp;
389e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t         *var, **vp;
390e18a033bSKonstantin Ananyev    ngx_stream_compile_complex_value_t   ccv;
391e18a033bSKonstantin Ananyev
392e18a033bSKonstantin Ananyev    ctx = cf->ctx;
393e18a033bSKonstantin Ananyev
394e18a033bSKonstantin Ananyev    value = cf->args->elts;
395e18a033bSKonstantin Ananyev
396e18a033bSKonstantin Ananyev    if (cf->args->nelts == 1
397e18a033bSKonstantin Ananyev        && ngx_strcmp(value[0].data, "hostnames") == 0)
398e18a033bSKonstantin Ananyev    {
399e18a033bSKonstantin Ananyev        ctx->hostnames = 1;
400e18a033bSKonstantin Ananyev        return NGX_CONF_OK;
401e18a033bSKonstantin Ananyev    }
402e18a033bSKonstantin Ananyev
403e18a033bSKonstantin Ananyev    if (cf->args->nelts == 1
404e18a033bSKonstantin Ananyev        && ngx_strcmp(value[0].data, "volatile") == 0)
405e18a033bSKonstantin Ananyev    {
406e18a033bSKonstantin Ananyev        ctx->no_cacheable = 1;
407e18a033bSKonstantin Ananyev        return NGX_CONF_OK;
408e18a033bSKonstantin Ananyev    }
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev    if (cf->args->nelts != 2) {
411e18a033bSKonstantin Ananyev        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
412e18a033bSKonstantin Ananyev                           "invalid number of the map parameters");
413e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
414e18a033bSKonstantin Ananyev    }
415e18a033bSKonstantin Ananyev
416e18a033b