Mercurial > hg > nginx-mail
comparison src/http/modules/ngx_http_map_module.c @ 665:0b460e61bdcd default tip
Merge with nginx 1.0.0.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 25 Apr 2011 04:22:17 +0400 |
parents | 8214eaef3530 |
children |
comparison
equal
deleted
inserted
replaced
572:06419a2298a9 | 665:0b460e61bdcd |
---|---|
17 | 17 |
18 typedef struct { | 18 typedef struct { |
19 ngx_hash_keys_arrays_t keys; | 19 ngx_hash_keys_arrays_t keys; |
20 | 20 |
21 ngx_array_t *values_hash; | 21 ngx_array_t *values_hash; |
22 ngx_array_t var_values; | |
23 #if (NGX_PCRE) | |
24 ngx_array_t regexes; | |
25 #endif | |
22 | 26 |
23 ngx_http_variable_value_t *default_value; | 27 ngx_http_variable_value_t *default_value; |
28 ngx_conf_t *cf; | |
24 ngx_uint_t hostnames; /* unsigned hostnames:1 */ | 29 ngx_uint_t hostnames; /* unsigned hostnames:1 */ |
25 } ngx_http_map_conf_ctx_t; | 30 } ngx_http_map_conf_ctx_t; |
26 | 31 |
27 | 32 |
28 typedef struct { | 33 typedef struct { |
29 ngx_hash_combined_t hash; | 34 ngx_http_map_t map; |
30 ngx_int_t index; | 35 ngx_http_complex_value_t value; |
31 ngx_http_variable_value_t *default_value; | 36 ngx_http_variable_value_t *default_value; |
32 ngx_uint_t hostnames; /* unsigned hostnames:1 */ | 37 ngx_uint_t hostnames; /* unsigned hostnames:1 */ |
33 } ngx_http_map_ctx_t; | 38 } ngx_http_map_ctx_t; |
34 | 39 |
35 | 40 |
103 uintptr_t data) | 108 uintptr_t data) |
104 { | 109 { |
105 ngx_http_map_ctx_t *map = (ngx_http_map_ctx_t *) data; | 110 ngx_http_map_ctx_t *map = (ngx_http_map_ctx_t *) data; |
106 | 111 |
107 size_t len; | 112 size_t len; |
108 u_char *name; | 113 ngx_str_t val; |
109 ngx_uint_t key; | 114 ngx_uint_t key; |
110 ngx_http_variable_value_t *vv, *value; | 115 ngx_http_variable_value_t *value; |
111 | 116 |
112 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 117 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
113 "http map started"); | 118 "http map started"); |
114 | 119 |
115 vv = ngx_http_get_flushed_variable(r, map->index); | 120 if (ngx_http_complex_value(r, &map->value, &val) != NGX_OK) { |
116 | 121 return NGX_ERROR; |
117 if (vv == NULL || vv->not_found) { | 122 } |
118 *v = *map->default_value; | 123 |
119 return NGX_OK; | 124 len = val.len; |
120 } | 125 |
121 | 126 if (len && map->hostnames && val.data[len - 1] == '.') { |
122 len = vv->len; | |
123 | |
124 if (len && map->hostnames && vv->data[len - 1] == '.') { | |
125 len--; | 127 len--; |
126 } | 128 } |
127 | 129 |
128 if (len == 0) { | 130 key = ngx_hash_strlow(val.data, val.data, len); |
129 *v = *map->default_value; | 131 |
130 return NGX_OK; | 132 value = ngx_http_map_find(r, &map->map, key, val.data, len, &val); |
131 } | 133 |
132 | 134 if (value == NULL) { |
133 name = ngx_pnalloc(r->pool, len); | 135 value = map->default_value; |
134 if (name == NULL) { | 136 } |
135 return NGX_ERROR; | 137 |
136 } | 138 if (!value->valid) { |
137 | 139 value = ngx_http_get_flushed_variable(r, (ngx_uint_t) value->data); |
138 key = ngx_hash_strlow(name, vv->data, len); | 140 |
139 | 141 if (value == NULL || value->not_found) { |
140 value = ngx_hash_find_combined(&map->hash, key, name, len); | 142 value = &ngx_http_variable_null_value; |
141 | 143 } |
142 if (value) { | 144 } |
143 *v = *value; | 145 |
144 | 146 *v = *value; |
145 } else { | |
146 *v = *map->default_value; | |
147 } | |
148 | 147 |
149 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 148 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
150 "http map: \"%v\" \"%v\"", vv, v); | 149 "http map: \"%v\" \"%v\"", &val, v); |
151 | 150 |
152 return NGX_OK; | 151 return NGX_OK; |
153 } | 152 } |
154 | 153 |
155 | 154 |
173 static char * | 172 static char * |
174 ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 173 ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
175 { | 174 { |
176 ngx_http_map_conf_t *mcf = conf; | 175 ngx_http_map_conf_t *mcf = conf; |
177 | 176 |
178 char *rv; | 177 char *rv; |
179 ngx_str_t *value, name; | 178 ngx_str_t *value, name; |
180 ngx_conf_t save; | 179 ngx_conf_t save; |
181 ngx_pool_t *pool; | 180 ngx_pool_t *pool; |
182 ngx_hash_init_t hash; | 181 ngx_hash_init_t hash; |
183 ngx_http_map_ctx_t *map; | 182 ngx_http_map_ctx_t *map; |
184 ngx_http_variable_t *var; | 183 ngx_http_variable_t *var; |
185 ngx_http_map_conf_ctx_t ctx; | 184 ngx_http_map_conf_ctx_t ctx; |
185 ngx_http_compile_complex_value_t ccv; | |
186 | 186 |
187 if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) { | 187 if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) { |
188 mcf->hash_max_size = 2048; | 188 mcf->hash_max_size = 2048; |
189 } | 189 } |
190 | 190 |
201 return NGX_CONF_ERROR; | 201 return NGX_CONF_ERROR; |
202 } | 202 } |
203 | 203 |
204 value = cf->args->elts; | 204 value = cf->args->elts; |
205 | 205 |
206 name = value[1]; | 206 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); |
207 name.len--; | 207 |
208 name.data++; | 208 ccv.cf = cf; |
209 | 209 ccv.value = &value[1]; |
210 map->index = ngx_http_get_variable_index(cf, &name); | 210 ccv.complex_value = &map->value; |
211 | 211 |
212 if (map->index == NGX_ERROR) { | 212 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { |
213 return NGX_CONF_ERROR; | 213 return NGX_CONF_ERROR; |
214 } | 214 } |
215 | 215 |
216 name = value[2]; | 216 name = value[2]; |
217 name.len--; | 217 name.len--; |
242 if (ctx.values_hash == NULL) { | 242 if (ctx.values_hash == NULL) { |
243 ngx_destroy_pool(pool); | 243 ngx_destroy_pool(pool); |
244 return NGX_CONF_ERROR; | 244 return NGX_CONF_ERROR; |
245 } | 245 } |
246 | 246 |
247 if (ngx_array_init(&ctx.var_values, cf->pool, 2, | |
248 sizeof(ngx_http_variable_value_t)) | |
249 != NGX_OK) | |
250 { | |
251 ngx_destroy_pool(pool); | |
252 return NGX_CONF_ERROR; | |
253 } | |
254 | |
255 #if (NGX_PCRE) | |
256 if (ngx_array_init(&ctx.regexes, cf->pool, 2, sizeof(ngx_http_map_regex_t)) | |
257 != NGX_OK) | |
258 { | |
259 ngx_destroy_pool(pool); | |
260 return NGX_CONF_ERROR; | |
261 } | |
262 #endif | |
263 | |
247 ctx.default_value = NULL; | 264 ctx.default_value = NULL; |
265 ctx.cf = &save; | |
248 ctx.hostnames = 0; | 266 ctx.hostnames = 0; |
249 | 267 |
250 save = *cf; | 268 save = *cf; |
251 cf->pool = pool; | 269 cf->pool = pool; |
252 cf->ctx = &ctx; | 270 cf->ctx = &ctx; |
270 hash.bucket_size = mcf->hash_bucket_size; | 288 hash.bucket_size = mcf->hash_bucket_size; |
271 hash.name = "map_hash"; | 289 hash.name = "map_hash"; |
272 hash.pool = cf->pool; | 290 hash.pool = cf->pool; |
273 | 291 |
274 if (ctx.keys.keys.nelts) { | 292 if (ctx.keys.keys.nelts) { |
275 hash.hash = &map->hash.hash; | 293 hash.hash = &map->map.hash.hash; |
276 hash.temp_pool = NULL; | 294 hash.temp_pool = NULL; |
277 | 295 |
278 if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) | 296 if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) |
279 != NGX_OK) | 297 != NGX_OK) |
280 { | 298 { |
298 { | 316 { |
299 ngx_destroy_pool(pool); | 317 ngx_destroy_pool(pool); |
300 return NGX_CONF_ERROR; | 318 return NGX_CONF_ERROR; |
301 } | 319 } |
302 | 320 |
303 map->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; | 321 map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; |
304 } | 322 } |
305 | 323 |
306 if (ctx.keys.dns_wc_tail.nelts) { | 324 if (ctx.keys.dns_wc_tail.nelts) { |
307 | 325 |
308 ngx_qsort(ctx.keys.dns_wc_tail.elts, | 326 ngx_qsort(ctx.keys.dns_wc_tail.elts, |
318 { | 336 { |
319 ngx_destroy_pool(pool); | 337 ngx_destroy_pool(pool); |
320 return NGX_CONF_ERROR; | 338 return NGX_CONF_ERROR; |
321 } | 339 } |
322 | 340 |
323 map->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; | 341 map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; |
324 } | 342 } |
343 | |
344 #if (NGX_PCRE) | |
345 | |
346 if (ctx.regexes.nelts) { | |
347 map->map.regex = ctx.regexes.elts; | |
348 map->map.nregex = ctx.regexes.nelts; | |
349 } | |
350 | |
351 #endif | |
325 | 352 |
326 ngx_destroy_pool(pool); | 353 ngx_destroy_pool(pool); |
327 | 354 |
328 return rv; | 355 return rv; |
329 } | 356 } |
342 | 369 |
343 | 370 |
344 static char * | 371 static char * |
345 ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) | 372 ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) |
346 { | 373 { |
347 ngx_int_t rc; | 374 ngx_int_t rc, index; |
348 ngx_str_t *value, file; | 375 ngx_str_t *value, file, name; |
349 ngx_uint_t i, key; | 376 ngx_uint_t i, key; |
350 ngx_http_map_conf_ctx_t *ctx; | 377 ngx_http_map_conf_ctx_t *ctx; |
351 ngx_http_variable_value_t *var, **vp; | 378 ngx_http_variable_value_t *var, **vp; |
352 | 379 |
353 ctx = cf->ctx; | 380 ctx = cf->ctx; |
362 | 389 |
363 } else if (cf->args->nelts != 2) { | 390 } else if (cf->args->nelts != 2) { |
364 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 391 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
365 "invalid number of the map parameters"); | 392 "invalid number of the map parameters"); |
366 return NGX_CONF_ERROR; | 393 return NGX_CONF_ERROR; |
367 | |
368 } else if (value[0].len == 0) { | |
369 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
370 "invalid first parameter"); | |
371 return NGX_CONF_ERROR; | |
372 } | 394 } |
373 | 395 |
374 if (ngx_strcmp(value[0].data, "include") == 0) { | 396 if (ngx_strcmp(value[0].data, "include") == 0) { |
375 file = value[1]; | 397 file = value[1]; |
376 | 398 |
377 if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){ | 399 if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { |
378 return NGX_CONF_ERROR; | 400 return NGX_CONF_ERROR; |
379 } | 401 } |
380 | 402 |
381 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); | 403 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); |
382 | 404 |
383 return ngx_conf_parse(cf, &file); | 405 return ngx_conf_parse(cf, &file); |
406 } | |
407 | |
408 if (value[1].data[0] == '$') { | |
409 name = value[1]; | |
410 name.len--; | |
411 name.data++; | |
412 | |
413 index = ngx_http_get_variable_index(ctx->cf, &name); | |
414 if (index == NGX_ERROR) { | |
415 return NGX_CONF_ERROR; | |
416 } | |
417 | |
418 var = ctx->var_values.elts; | |
419 | |
420 for (i = 0; i < ctx->var_values.nelts; i++) { | |
421 if (index == (ngx_int_t) var[i].data) { | |
422 goto found; | |
423 } | |
424 } | |
425 | |
426 var = ngx_palloc(ctx->keys.pool, sizeof(ngx_http_variable_value_t)); | |
427 if (var == NULL) { | |
428 return NGX_CONF_ERROR; | |
429 } | |
430 | |
431 var->valid = 0; | |
432 var->no_cacheable = 0; | |
433 var->not_found = 0; | |
434 var->len = 0; | |
435 var->data = (u_char *) index; | |
436 | |
437 vp = ngx_array_push(&ctx->var_values); | |
438 if (vp == NULL) { | |
439 return NGX_CONF_ERROR; | |
440 } | |
441 | |
442 *vp = var; | |
443 | |
444 goto found; | |
384 } | 445 } |
385 | 446 |
386 key = 0; | 447 key = 0; |
387 | 448 |
388 for (i = 0; i < value[1].len; i++) { | 449 for (i = 0; i < value[1].len; i++) { |
449 ctx->default_value = var; | 510 ctx->default_value = var; |
450 | 511 |
451 return NGX_CONF_OK; | 512 return NGX_CONF_OK; |
452 } | 513 } |
453 | 514 |
454 if (value[0].len && value[0].data[0] == '!') { | 515 #if (NGX_PCRE) |
516 | |
517 if (value[0].len && value[0].data[0] == '~') { | |
518 ngx_regex_compile_t rc; | |
519 ngx_http_map_regex_t *regex; | |
520 u_char errstr[NGX_MAX_CONF_ERRSTR]; | |
521 | |
522 regex = ngx_array_push(&ctx->regexes); | |
523 if (regex == NULL) { | |
524 return NGX_CONF_ERROR; | |
525 } | |
526 | |
527 value[0].len--; | |
528 value[0].data++; | |
529 | |
530 ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); | |
531 | |
532 rc.pattern = value[0]; | |
533 rc.err.len = NGX_MAX_CONF_ERRSTR; | |
534 rc.err.data = errstr; | |
535 | |
536 regex->regex = ngx_http_regex_compile(ctx->cf, &rc); | |
537 if (regex->regex == NULL) { | |
538 return NGX_CONF_ERROR; | |
539 } | |
540 | |
541 regex->value = var; | |
542 | |
543 return NGX_CONF_OK; | |
544 } | |
545 | |
546 #endif | |
547 | |
548 if (value[0].len && value[0].data[0] == '\\') { | |
455 value[0].len--; | 549 value[0].len--; |
456 value[0].data++; | 550 value[0].data++; |
457 } | 551 } |
458 | 552 |
459 rc = ngx_hash_add_key(&ctx->keys, &value[0], var, | 553 rc = ngx_hash_add_key(&ctx->keys, &value[0], var, |