Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_map_module.c
Go to the documentation of this file.
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 {
17 
18 
19 typedef struct {
21 
24 #if (NGX_PCRE)
25  ngx_array_t regexes;
26 #endif
27 
30  ngx_uint_t hostnames; /* unsigned hostnames:1 */
32 
33 
34 typedef struct {
38  ngx_uint_t hostnames; /* unsigned hostnames:1 */
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"),
53  ngx_http_map_block,
55  0,
56  NULL },
57 
58  { ngx_string("map_hash_max_size"),
62  offsetof(ngx_http_map_conf_t, hash_max_size),
63  NULL },
64 
65  { ngx_string("map_hash_bucket_size"),
69  offsetof(ngx_http_map_conf_t, hash_bucket_size),
70  NULL },
71 
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 
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 */
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;
115 
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) {
138  }
139  }
140 
141  *v = *value;
142 
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 
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;
181 
182  if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) {
183  mcf->hash_max_size = 2048;
184  }
185 
188 
189  } else {
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 
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] != '$') {
215  "invalid variable name \"%V\"", &name);
216  return NGX_CONF_ERROR;
217  }
218 
219  name.len--;
220  name.data++;
221 
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 
231  if (pool == NULL) {
232  return NGX_CONF_ERROR;
233  }
234 
235  ctx.keys.pool = cf->pool;
236  ctx.keys.temp_pool = pool;
237 
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,
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:
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 
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 
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 
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 
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;
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) {
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) {
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] == '~') {
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++;
526  }
527 
528  rc.pattern = value[0];
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) {
558  "invalid hostname or wildcard \"%V\"", &value[0]);
559  }
560 
561  if (rc == NGX_BUSY) {
563  "conflicting parameter \"%V\"", &value[0]);
564  }
565 
566  return NGX_CONF_ERROR;
567 }