~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_map_module.c

Version: ~ [ nginx-1.4.1 ] ~ [ nginx-1.5.0 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  * Copyright (C) Nginx, Inc.
  5  */
  6 
  7 
  8 #include <ngx_config.h>
  9 #include <ngx_core.h>
 10 #include <ngx_http.h>
 11 
 12 
 13 typedef struct {
 14     ngx_uint_t                  hash_max_size;
 15     ngx_uint_t                  hash_bucket_size;
 16 } ngx_http_map_conf_t;
 17 
 18 
 19 typedef struct {
 20     ngx_hash_keys_arrays_t      keys;
 21 
 22     ngx_array_t                *values_hash;
 23     ngx_array_t                 var_values;
 24 #if (NGX_PCRE)
 25     ngx_array_t                 regexes;
 26 #endif
 27 
 28     ngx_http_variable_value_t  *default_value;
 29     ngx_conf_t                 *cf;
 30     ngx_uint_t                  hostnames;      /* unsigned  hostnames:1 */
 31 } ngx_http_map_conf_ctx_t;
 32 
 33 
 34 typedef struct {
 35     ngx_http_map_t              map;
 36     ngx_http_complex_value_t    value;
 37     ngx_http_variable_value_t  *default_value;
 38     ngx_uint_t                  hostnames;      /* unsigned  hostnames:1 */
 39 } ngx_http_map_ctx_t;
 40 
 41 
 42 static int ngx_libc_cdecl ngx_http_map_cmp_dns_wildcards(const void *one,
 43     const void *two);
 44 static void *ngx_http_map_create_conf(ngx_conf_t *cf);
 45 static char *ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 46 static char *ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
 47 
 48 
 49 static ngx_command_t  ngx_http_map_commands[] = {
 50 
 51     { ngx_string("map"),
 52       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
 53       ngx_http_map_block,
 54       NGX_HTTP_MAIN_CONF_OFFSET,
 55       0,
 56       NULL },
 57 
 58     { ngx_string("map_hash_max_size"),
 59       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
 60       ngx_conf_set_num_slot,
 61       NGX_HTTP_MAIN_CONF_OFFSET,
 62       offsetof(ngx_http_map_conf_t, hash_max_size),
 63       NULL },
 64 
 65     { ngx_string("map_hash_bucket_size"),
 66       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
 67       ngx_conf_set_num_slot,
 68       NGX_HTTP_MAIN_CONF_OFFSET,
 69       offsetof(ngx_http_map_conf_t, hash_bucket_size),
 70       NULL },
 71 
 72       ngx_null_command
 73 };
 74 
 75 
 76 static ngx_http_module_t  ngx_http_map_module_ctx = {
 77     NULL,                                  /* preconfiguration */
 78     NULL,                                  /* postconfiguration */
 79 
 80     ngx_http_map_create_conf,              /* create main configuration */
 81     NULL,                                  /* init main configuration */
 82 
 83     NULL,                                  /* create server configuration */
 84     NULL,                                  /* merge server configuration */
 85 
 86     NULL,                                  /* create location configuration */
 87     NULL                                   /* merge location configuration */
 88 };
 89 
 90 
 91 ngx_module_t  ngx_http_map_module = {
 92     NGX_MODULE_V1,
 93     &ngx_http_map_module_ctx,              /* module context */
 94     ngx_http_map_commands,                 /* module directives */
 95     NGX_HTTP_MODULE,                       /* module type */
 96     NULL,                                  /* init master */
 97     NULL,                                  /* init module */
 98     NULL,                                  /* init process */
 99     NULL,                                  /* init thread */
100     NULL,                                  /* exit thread */
101     NULL,                                  /* exit process */
102     NULL,                                  /* exit master */
103     NGX_MODULE_V1_PADDING
104 };
105 
106 
107 static ngx_int_t
108 ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
109     uintptr_t data)
110 {
111     ngx_http_map_ctx_t  *map = (ngx_http_map_ctx_t *) data;
112 
113     ngx_str_t                   val;
114     ngx_http_variable_value_t  *value;
115 
116     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
117                    "http map started");
118 
119     if (ngx_http_complex_value(r, &map->value, &val) != NGX_OK) {
120         return NGX_ERROR;
121     }
122 
123     if (map->hostnames && val.len > 0 && val.data[val.len - 1] == '.') {
124         val.len--;
125     }
126 
127     value = ngx_http_map_find(r, &map->map, &val);
128 
129     if (value == NULL) {
130         value = map->default_value;
131     }
132 
133     if (!value->valid) {
134         value = ngx_http_get_flushed_variable(r, (ngx_uint_t) value->data);
135 
136         if (value == NULL || value->not_found) {
137             value = &ngx_http_variable_null_value;
138         }
139     }
140 
141     *v = *value;
142 
143     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
144                    "http map: \"%v\" \"%v\"", &val, v);
145 
146     return NGX_OK;
147 }
148 
149 
150 static void *
151 ngx_http_map_create_conf(ngx_conf_t *cf)
152 {
153     ngx_http_map_conf_t  *mcf;
154 
155     mcf = ngx_palloc(cf->pool, sizeof(ngx_http_map_conf_t));
156     if (mcf == NULL) {
157         return NULL;
158     }
159 
160     mcf->hash_max_size = NGX_CONF_UNSET_UINT;
161     mcf->hash_bucket_size = NGX_CONF_UNSET_UINT;
162 
163     return mcf;
164 }
165 
166 
167 static char *
168 ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
169 {
170     ngx_http_map_conf_t  *mcf = conf;
171 
172     char                              *rv;
173     ngx_str_t                         *value, name;
174     ngx_conf_t                         save;
175     ngx_pool_t                        *pool;
176     ngx_hash_init_t                    hash;
177     ngx_http_map_ctx_t                *map;
178     ngx_http_variable_t               *var;
179     ngx_http_map_conf_ctx_t            ctx;
180     ngx_http_compile_complex_value_t   ccv;
181 
182     if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) {
183         mcf->hash_max_size = 2048;
184     }
185 
186     if (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) {
187         mcf->hash_bucket_size = ngx_cacheline_size;
188 
189     } else {
190         mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size,
191                                           ngx_cacheline_size);
192     }
193 
194     map = ngx_pcalloc(cf->pool, sizeof(ngx_http_map_ctx_t));
195     if (map == NULL) {
196         return NGX_CONF_ERROR;
197     }
198 
199     value = cf->args->elts;
200 
201     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
202 
203     ccv.cf = cf;
204     ccv.value = &value[1];
205     ccv.complex_value = &map->value;
206 
207     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
208         return NGX_CONF_ERROR;
209     }
210 
211     name = value[2];
212 
213     if (name.data[0] != '$') {
214         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
215                            "invalid variable name \"%V\"", &name);
216         return NGX_CONF_ERROR;
217     }
218 
219     name.len--;
220     name.data++;
221 
222     var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
223     if (var == NULL) {
224         return NGX_CONF_ERROR;
225     }
226 
227     var->get_handler = ngx_http_map_variable;
228     var->data = (uintptr_t) map;
229 
230     pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
231     if (pool == NULL) {
232         return NGX_CONF_ERROR;
233     }
234 
235     ctx.keys.pool = cf->pool;
236     ctx.keys.temp_pool = pool;
237 
238     if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) {
239         ngx_destroy_pool(pool);
240         return NGX_CONF_ERROR;
241     }
242 
243     ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize);
244     if (ctx.values_hash == NULL) {
245         ngx_destroy_pool(pool);
246         return NGX_CONF_ERROR;
247     }
248 
249     if (ngx_array_init(&ctx.var_values, cf->pool, 2,
250                        sizeof(ngx_http_variable_value_t))
251         != NGX_OK)
252     {
253         ngx_destroy_pool(pool);
254         return NGX_CONF_ERROR;
255     }
256 
257 #if (NGX_PCRE)
258     if (ngx_array_init(&ctx.regexes, cf->pool, 2, sizeof(ngx_http_map_regex_t))
259         != NGX_OK)
260     {
261         ngx_destroy_pool(pool);
262         return NGX_CONF_ERROR;
263     }
264 #endif
265 
266     ctx.default_value = NULL;
267     ctx.cf = &save;
268     ctx.hostnames = 0;
269 
270     save = *cf;
271     cf->pool = pool;
272     cf->ctx = &ctx;
273     cf->handler = ngx_http_map;
274     cf->handler_conf = conf;
275 
276     rv = ngx_conf_parse(cf, NULL);
277 
278     *cf = save;
279 
280     if (rv != NGX_CONF_OK) {
281         ngx_destroy_pool(pool);
282         return rv;
283     }
284 
285     map->default_value = ctx.default_value ? ctx.default_value:
286                                              &ngx_http_variable_null_value;
287 
288     map->hostnames = ctx.hostnames;
289 
290     hash.key = ngx_hash_key_lc;
291     hash.max_size = mcf->hash_max_size;
292     hash.bucket_size = mcf->hash_bucket_size;
293     hash.name = "map_hash";
294     hash.pool = cf->pool;
295 
296     if (ctx.keys.keys.nelts) {
297         hash.hash = &map->map.hash.hash;
298         hash.temp_pool = NULL;
299 
300         if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts)
301             != NGX_OK)
302         {
303             ngx_destroy_pool(pool);
304             return NGX_CONF_ERROR;
305         }
306     }
307 
308     if (ctx.keys.dns_wc_head.nelts) {
309 
310         ngx_qsort(ctx.keys.dns_wc_head.elts,
311                   (size_t) ctx.keys.dns_wc_head.nelts,
312                   sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards);
313 
314         hash.hash = NULL;
315         hash.temp_pool = pool;
316 
317         if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts,
318                                    ctx.keys.dns_wc_head.nelts)
319             != NGX_OK)
320         {
321             ngx_destroy_pool(pool);
322             return NGX_CONF_ERROR;
323         }
324 
325         map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
326     }
327 
328     if (ctx.keys.dns_wc_tail.nelts) {
329 
330         ngx_qsort(ctx.keys.dns_wc_tail.elts,
331                   (size_t) ctx.keys.dns_wc_tail.nelts,
332                   sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards);
333 
334         hash.hash = NULL;
335         hash.temp_pool = pool;
336 
337         if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts,
338                                    ctx.keys.dns_wc_tail.nelts)
339             != NGX_OK)
340         {
341             ngx_destroy_pool(pool);
342             return NGX_CONF_ERROR;
343         }
344 
345         map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
346     }
347 
348 #if (NGX_PCRE)
349 
350     if (ctx.regexes.nelts) {
351         map->map.regex = ctx.regexes.elts;
352         map->map.nregex = ctx.regexes.nelts;
353     }
354 
355 #endif
356 
357     ngx_destroy_pool(pool);
358 
359     return rv;
360 }
361 
362 
363 static int ngx_libc_cdecl
364 ngx_http_map_cmp_dns_wildcards(const void *one, const void *two)
365 {
366     ngx_hash_key_t  *first, *second;
367 
368     first = (ngx_hash_key_t *) one;
369     second = (ngx_hash_key_t *) two;
370 
371     return ngx_dns_strcmp(first->key.data, second->key.data);
372 }
373 
374 
375 static char *
376 ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
377 {
378     ngx_int_t                   rc, index;
379     ngx_str_t                  *value, name;
380     ngx_uint_t                  i, key;
381     ngx_http_map_conf_ctx_t    *ctx;
382     ngx_http_variable_value_t  *var, **vp;
383 
384     ctx = cf->ctx;
385 
386     value = cf->args->elts;
387 
388     if (cf->args->nelts == 1
389         && ngx_strcmp(value[0].data, "hostnames") == 0)
390     {
391         ctx->hostnames = 1;
392         return NGX_CONF_OK;
393 
394     } else if (cf->args->nelts != 2) {
395         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
396                            "invalid number of the map parameters");
397         return NGX_CONF_ERROR;
398     }
399 
400     if (ngx_strcmp(value[0].data, "include") == 0) {
401         return ngx_conf_include(cf, dummy, conf);
402     }
403 
404     if (value[1].data[0] == '$') {
405         name = value[1];
406         name.len--;
407         name.data++;
408 
409         index = ngx_http_get_variable_index(ctx->cf, &name);
410         if (index == NGX_ERROR) {
411             return NGX_CONF_ERROR;
412         }
413 
414         var = ctx->var_values.elts;
415 
416         for (i = 0; i < ctx->var_values.nelts; i++) {
417             if (index == (ngx_int_t) var[i].data) {
418                 var = &var[i];
419                 goto found;
420             }
421         }
422 
423         var = ngx_array_push(&ctx->var_values);
424         if (var == NULL) {
425             return NGX_CONF_ERROR;
426         }
427 
428         var->valid = 0;
429         var->no_cacheable = 0;
430         var->not_found = 0;
431         var->len = 0;
432         var->data = (u_char *) index;
433 
434         goto found;
435     }
436 
437     key = 0;
438 
439     for (i = 0; i < value[1].len; i++) {
440         key = ngx_hash(key, value[1].data[i]);
441     }
442 
443     key %= ctx->keys.hsize;
444 
445     vp = ctx->values_hash[key].elts;
446 
447     if (vp) {
448         for (i = 0; i < ctx->values_hash[key].nelts; i++) {
449             if (value[1].len != (size_t) vp[i]->len) {
450                 continue;
451             }
452 
453             if (ngx_strncmp(value[1].data, vp[i]->data, value[1].len) == 0) {
454                 var = vp[i];
455                 goto found;
456             }
457         }
458 
459     } else {
460         if (ngx_array_init(&ctx->values_hash[key], cf->pool, 4,
461                            sizeof(ngx_http_variable_value_t *))
462             != NGX_OK)
463         {
464             return NGX_CONF_ERROR;
465         }
466     }
467 
468     var = ngx_palloc(ctx->keys.pool, sizeof(ngx_http_variable_value_t));
469     if (var == NULL) {
470         return NGX_CONF_ERROR;
471     }
472 
473     var->len = value[1].len;
474     var->data = ngx_pstrdup(ctx->keys.pool, &value[1]);
475     if (var->data == NULL) {
476         return NGX_CONF_ERROR;
477     }
478 
479     var->valid = 1;
480     var->no_cacheable = 0;
481     var->not_found = 0;
482 
483     vp = ngx_array_push(&ctx->values_hash[key]);
484     if (vp == NULL) {
485         return NGX_CONF_ERROR;
486     }
487 
488     *vp = var;
489 
490 found:
491 
492     if (ngx_strcmp(value[0].data, "default") == 0) {
493 
494         if (ctx->default_value) {
495             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
496                                "duplicate default map parameter");
497             return NGX_CONF_ERROR;
498         }
499 
500         ctx->default_value = var;
501 
502         return NGX_CONF_OK;
503     }
504 
505 #if (NGX_PCRE)
506 
507     if (value[0].len && value[0].data[0] == '~') {
508         ngx_regex_compile_t    rc;
509         ngx_http_map_regex_t  *regex;
510         u_char                 errstr[NGX_MAX_CONF_ERRSTR];
511 
512         regex = ngx_array_push(&ctx->regexes);
513         if (regex == NULL) {
514             return NGX_CONF_ERROR;
515         }
516 
517         value[0].len--;
518         value[0].data++;
519 
520         ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
521 
522         if (value[0].data[0] == '*') {
523             value[0].len--;
524             value[0].data++;
525             rc.options = NGX_REGEX_CASELESS;
526         }
527 
528         rc.pattern = value[0];
529         rc.err.len = NGX_MAX_CONF_ERRSTR;
530         rc.err.data = errstr;
531 
532         regex->regex = ngx_http_regex_compile(ctx->cf, &rc);
533         if (regex->regex == NULL) {
534             return NGX_CONF_ERROR;
535         }
536 
537         regex->value = var;
538 
539         return NGX_CONF_OK;
540     }
541 
542 #endif
543 
544     if (value[0].len && value[0].data[0] == '\\') {
545         value[0].len--;
546         value[0].data++;
547     }
548 
549     rc = ngx_hash_add_key(&ctx->keys, &value[0], var,
550                           (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : 0);
551 
552     if (rc == NGX_OK) {
553         return NGX_CONF_OK;
554     }
555 
556     if (rc == NGX_DECLINED) {
557         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
558                            "invalid hostname or wildcard \"%V\"", &value[0]);
559     }
560 
561     if (rc == NGX_BUSY) {
562         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
563                            "conflicting parameter \"%V\"", &value[0]);
564     }
565 
566     return NGX_CONF_ERROR;
567 }
568 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.