├── Changelog ├── README ├── config ├── LICENCE └── ngx_http_eval_module.c /Changelog: -------------------------------------------------------------------------------- 1 | 2 | Version 1.0.3 3 | * Change: compatibility with nginx API 0.8.42 and greater 4 | * Change: handle requests with bodies properly 5 | 6 | Version 1.0.2 7 | * Change: restore $uri variable in subrequests 8 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | Documentation for this module could be found under following URLs: 3 | 4 | * English: 5 | 6 | http://www.grid.net.ru/nginx/eval.en.html 7 | 8 | * Russian: 9 | 10 | http://www.grid.net.ru/nginx/eval.ru.html 11 | 12 | This work is commissioned by gadu-gadu.pl 13 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_eval_module 2 | 3 | if test -n "$ngx_module_link"; then 4 | ngx_module_type=HTTP 5 | ngx_module_name=ngx_http_eval_module 6 | ngx_module_srcs="$ngx_addon_dir/ngx_http_eval_module.c" 7 | 8 | . auto/module 9 | else 10 | HTTP_MODULES="$HTTP_MODULES ngx_http_eval_module" 11 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_eval_module.c" 12 | fi 13 | 14 | 15 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | * Copyright (c) 2009, Valery Kholodkov 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Valery Kholodkov nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY VALERY KHOLODKOV ''AS IS'' AND ANY 16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL VALERY KHOLODKOV BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /ngx_http_eval_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2009 Valery Kholodkov 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct { 13 | ngx_http_variable_t *variable; 14 | ngx_uint_t index; 15 | } ngx_http_eval_variable_t; 16 | 17 | typedef struct { 18 | ngx_array_t *variables; 19 | ngx_str_t eval_location; 20 | } ngx_http_eval_block_t; 21 | 22 | typedef struct { 23 | ngx_array_t *blocks; 24 | ngx_flag_t escalate; 25 | ngx_str_t override_content_type; 26 | } ngx_http_eval_loc_conf_t; 27 | 28 | typedef struct { 29 | ngx_http_eval_loc_conf_t *base_conf; 30 | ngx_http_variable_value_t **values; 31 | ngx_int_t status; 32 | ngx_http_eval_block_t *current_block; 33 | ngx_http_eval_block_t *last_block; 34 | 35 | unsigned int done:1; 36 | unsigned int in_progress:1; 37 | } ngx_http_eval_ctx_t; 38 | 39 | typedef ngx_int_t (*ngx_http_eval_format_handler_pt)(ngx_http_request_t *r, 40 | ngx_http_eval_ctx_t *ctx); 41 | 42 | typedef struct { 43 | ngx_str_t content_type; 44 | ngx_http_eval_format_handler_pt handler; 45 | } ngx_http_eval_format_t; 46 | 47 | static ngx_int_t 48 | ngx_http_eval_init_variables(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, 49 | ngx_http_eval_block_t *block); 50 | 51 | static ngx_int_t ngx_http_eval_post_subrequest_handler(ngx_http_request_t *r, void *data, ngx_int_t rc); 52 | 53 | static void *ngx_http_eval_create_loc_conf(ngx_conf_t *cf); 54 | static char *ngx_http_eval_merge_loc_conf(ngx_conf_t *cf, void *parent, 55 | void *child); 56 | 57 | static char *ngx_http_eval_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 58 | 59 | static ngx_int_t ngx_http_eval_init(ngx_conf_t *cf); 60 | 61 | static ngx_int_t ngx_http_eval_octet_stream(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx); 62 | static ngx_int_t ngx_http_eval_plain_text(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx); 63 | static ngx_int_t ngx_http_eval_urlencoded(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx); 64 | 65 | static ngx_http_eval_format_t ngx_http_eval_formats[] = { 66 | { ngx_string("application/octet-stream"), ngx_http_eval_octet_stream }, 67 | { ngx_string("text/plain"), ngx_http_eval_plain_text }, 68 | { ngx_string("application/x-www-form-urlencoded"), ngx_http_eval_urlencoded }, 69 | 70 | { ngx_null_string, ngx_http_eval_plain_text } 71 | }; 72 | 73 | static ngx_command_t ngx_http_eval_commands[] = { 74 | 75 | { ngx_string("eval"), 76 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE|NGX_CONF_BLOCK, 77 | ngx_http_eval_block, 78 | NGX_HTTP_LOC_CONF_OFFSET, 79 | 0, 80 | NULL }, 81 | 82 | { ngx_string("eval_escalate"), 83 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 84 | ngx_conf_set_flag_slot, 85 | NGX_HTTP_LOC_CONF_OFFSET, 86 | offsetof(ngx_http_eval_loc_conf_t, escalate), 87 | NULL }, 88 | 89 | { ngx_string("eval_override_content_type"), 90 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 91 | ngx_conf_set_str_slot, 92 | NGX_HTTP_LOC_CONF_OFFSET, 93 | offsetof(ngx_http_eval_loc_conf_t, override_content_type), 94 | NULL }, 95 | 96 | ngx_null_command 97 | }; 98 | 99 | static ngx_http_module_t ngx_http_eval_module_ctx = { 100 | NULL, /* preconfiguration */ 101 | ngx_http_eval_init, /* postconfiguration */ 102 | 103 | NULL, /* create main configuration */ 104 | NULL, /* init main configuration */ 105 | 106 | NULL, /* create server configuration */ 107 | NULL, /* merge server configuration */ 108 | 109 | ngx_http_eval_create_loc_conf, /* create location configuration */ 110 | ngx_http_eval_merge_loc_conf /* merge location configuration */ 111 | }; 112 | 113 | ngx_module_t ngx_http_eval_module = { 114 | NGX_MODULE_V1, 115 | &ngx_http_eval_module_ctx, /* module context */ 116 | ngx_http_eval_commands, /* module directives */ 117 | NGX_HTTP_MODULE, /* module type */ 118 | NULL, /* init master */ 119 | NULL, /* init module */ 120 | NULL, /* init process */ 121 | NULL, /* init thread */ 122 | NULL, /* exit thread */ 123 | NULL, /* exit process */ 124 | NULL, /* exit master */ 125 | NGX_MODULE_V1_PADDING 126 | }; 127 | 128 | static ngx_int_t 129 | ngx_http_eval_handler(ngx_http_request_t *r) 130 | { 131 | size_t loc_len; 132 | ngx_str_t args; 133 | ngx_str_t subrequest_uri; 134 | ngx_uint_t flags; 135 | ngx_http_core_loc_conf_t *clcf; 136 | ngx_http_eval_loc_conf_t *ecf; 137 | ngx_http_eval_ctx_t *ctx; 138 | ngx_http_request_t *sr; 139 | ngx_int_t rc; 140 | ngx_http_post_subrequest_t *psr; 141 | ngx_http_eval_block_t *block; 142 | u_char *p; 143 | 144 | if(r != r->main && r->uri.len > 6 && r->uri.data[0] == '/' && r->uri.data[1] == 'e' 145 | && r->uri.data[2] == 'v' && r->uri.data[3] == 'a' && r->uri.data[4] == 'l' 146 | && r->uri.data[5] == '_') 147 | { 148 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 149 | 150 | loc_len = r->valid_location ? clcf->name.len : 0; 151 | 152 | if(r->uri.len != loc_len) { 153 | r->uri.data += loc_len; 154 | r->uri.len -= loc_len; 155 | } 156 | else { 157 | r->uri.len = 1; 158 | } 159 | } 160 | 161 | ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); 162 | 163 | if(ecf->blocks == NULL || !ecf->blocks->nelts) { 164 | return NGX_DECLINED; 165 | } 166 | 167 | ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); 168 | 169 | if(ctx == NULL) { 170 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); 171 | if (ctx == NULL) { 172 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 173 | } 174 | 175 | ctx->base_conf = ecf; 176 | 177 | ctx->current_block = ecf->blocks->elts; 178 | ctx->last_block = ctx->current_block + ecf->blocks->nelts - 1; 179 | 180 | ngx_http_set_ctx(r, ctx, ngx_http_eval_module); 181 | } 182 | 183 | if(ctx->done) { 184 | ctx->in_progress = 0; 185 | 186 | if(ctx->current_block == ctx->last_block) { 187 | if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { 188 | return NGX_DECLINED; 189 | } 190 | 191 | return ctx->status; 192 | } 193 | 194 | ctx->current_block++; 195 | } 196 | 197 | if(ctx->in_progress) { 198 | #if defined nginx_version && nginx_version >= 8042 199 | return NGX_DONE; 200 | #else 201 | return NGX_AGAIN; 202 | #endif 203 | } 204 | 205 | /* 206 | * Advance to block which has at least one variable 207 | */ 208 | while(ctx->current_block->variables == NULL || ctx->current_block->variables->nelts == 0) { 209 | if(ctx->current_block == ctx->last_block) { 210 | return NGX_DECLINED; 211 | } 212 | 213 | ctx->current_block++; 214 | } 215 | 216 | block = ctx->current_block; 217 | 218 | psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); 219 | if (psr == NULL) { 220 | return NGX_ERROR; 221 | } 222 | 223 | if(ngx_http_eval_init_variables(r, ctx, block) != NGX_OK) { 224 | return NGX_ERROR; 225 | } 226 | 227 | args.len = r->args.len; 228 | args.data = r->args.data; 229 | flags = 0; 230 | 231 | subrequest_uri.len = block->eval_location.len + r->uri.len; 232 | 233 | p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); 234 | 235 | if(p == NULL) { 236 | return NGX_ERROR; 237 | } 238 | 239 | p = ngx_copy(p, block->eval_location.data, block->eval_location.len); 240 | p = ngx_copy(p, r->uri.data, r->uri.len); 241 | 242 | if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { 243 | return NGX_ERROR; 244 | } 245 | 246 | psr->handler = ngx_http_eval_post_subrequest_handler; 247 | psr->data = ctx; 248 | 249 | flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED; 250 | 251 | rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); 252 | 253 | if (rc == NGX_ERROR || rc == NGX_DONE) { 254 | return rc; 255 | } 256 | 257 | /* 258 | * create a fake request body instead of discarding the real one 259 | * in order to avoid attempts to read it 260 | */ 261 | sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); 262 | if (sr->request_body == NULL) { 263 | return NGX_ERROR; 264 | } 265 | 266 | ctx->in_progress = 1; 267 | ctx->done = 0; 268 | 269 | /* 270 | * Wait for subrequest to complete 271 | */ 272 | 273 | #if defined nginx_version && nginx_version >= 8042 274 | return NGX_DONE; 275 | #else 276 | return NGX_AGAIN; 277 | #endif 278 | } 279 | 280 | static ngx_int_t 281 | ngx_http_eval_init_variables(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, 282 | ngx_http_eval_block_t *block) 283 | { 284 | ngx_uint_t i; 285 | ngx_http_eval_variable_t *variable; 286 | 287 | ctx->values = ngx_pcalloc(r->pool, block->variables->nelts * sizeof(ngx_http_variable_value_t*)); 288 | 289 | if (ctx->values == NULL) { 290 | return NGX_ERROR; 291 | } 292 | 293 | variable = block->variables->elts; 294 | 295 | for(i = 0;ivariables->nelts;i++) { 296 | ctx->values[i] = r->variables + variable[i].index; 297 | 298 | ctx->values[i]->valid = 0; 299 | ctx->values[i]->not_found = 1; 300 | } 301 | 302 | return NGX_OK; 303 | } 304 | 305 | static ngx_int_t 306 | ngx_http_eval_post_subrequest_handler(ngx_http_request_t *r, void *data, ngx_int_t rc) 307 | { 308 | ngx_http_eval_ctx_t *ctx = data; 309 | ngx_http_eval_format_t *f = ngx_http_eval_formats; 310 | ngx_str_t content_type; 311 | 312 | if(ctx->base_conf->override_content_type.len) { 313 | content_type.data = ctx->base_conf->override_content_type.data; 314 | content_type.len = ctx->base_conf->override_content_type.len; 315 | } 316 | else if(r->headers_out.content_type.len) { 317 | content_type.data = r->headers_out.content_type.data; 318 | content_type.len = r->headers_out.content_type.len; 319 | } 320 | else { 321 | content_type.data = (u_char*)"application/octet-stream"; 322 | content_type.len = sizeof("application/octet-stream") - 1; 323 | } 324 | 325 | while(f->content_type.len) { 326 | 327 | if(!ngx_strncasecmp(f->content_type.data, content_type.data, 328 | f->content_type.len)) 329 | { 330 | f->handler(r, ctx); 331 | break; 332 | } 333 | 334 | f++; 335 | } 336 | 337 | ctx->done = 1; 338 | ctx->status = rc; 339 | 340 | return NGX_OK; 341 | } 342 | 343 | /* 344 | * The next two evaluation methods assume we have at least one varible. 345 | * 346 | * ngx_http_eval_handler must guarantee this. * 347 | */ 348 | static ngx_int_t 349 | ngx_http_eval_octet_stream(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx) 350 | { 351 | ngx_http_variable_value_t *value = ctx->values[0]; 352 | 353 | if (r->upstream) { 354 | value->len = r->upstream->buffer.last - r->upstream->buffer.pos; 355 | value->data = r->upstream->buffer.pos; 356 | value->valid = 1; 357 | value->not_found = 0; 358 | } 359 | 360 | return NGX_OK; 361 | } 362 | 363 | static ngx_int_t 364 | ngx_http_eval_plain_text(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx) 365 | { 366 | ngx_int_t rc; 367 | u_char *p; 368 | ngx_http_variable_value_t *value = ctx->values[0]; 369 | 370 | rc = ngx_http_eval_octet_stream(r, ctx); 371 | 372 | if(rc != NGX_OK) { 373 | return rc; 374 | } 375 | 376 | /* 377 | * Remove trailing spaces and control characters 378 | */ 379 | if(value->valid) { 380 | p = value->data + value->len; 381 | 382 | while(p != value->data) { 383 | p--; 384 | 385 | if(*p != CR && *p != LF && *p != '\t' && *p != ' ') 386 | break; 387 | 388 | value->len--; 389 | } 390 | } 391 | 392 | return NGX_OK; 393 | } 394 | 395 | static ngx_int_t 396 | ngx_http_eval_set_variable_value(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, 397 | ngx_str_t *name, ngx_str_t *value) 398 | { 399 | ngx_uint_t i; 400 | ngx_http_eval_variable_t *variable; 401 | 402 | variable = ctx->current_block->variables->elts; 403 | 404 | for(i = 0;icurrent_block->variables->nelts;i++) { 405 | if(variable[i].variable->name.len != name->len) { 406 | continue; 407 | } 408 | 409 | if(!ngx_strncasecmp(variable[i].variable->name.data, name->data, variable[i].variable->name.len)) { 410 | ctx->values[i]->len = value->len; 411 | ctx->values[i]->data = value->data; 412 | ctx->values[i]->valid = 1; 413 | ctx->values[i]->not_found = 0; 414 | 415 | return NGX_OK; 416 | } 417 | } 418 | 419 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 420 | "eval: ignored undefined variable \"%V\"", value); 421 | 422 | return NGX_OK; 423 | } 424 | 425 | static ngx_int_t 426 | ngx_http_eval_parse_param(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, ngx_str_t *param) { 427 | u_char *p, *src, *dst; 428 | 429 | ngx_str_t name; 430 | ngx_str_t value; 431 | 432 | p = (u_char *) ngx_strchr(param->data, '='); 433 | 434 | if(p == NULL) { 435 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 436 | "eval: invalid param \"%V\"", param); 437 | return NGX_ERROR; 438 | } 439 | 440 | name.data = param->data; 441 | name.len = p - param->data; 442 | 443 | value.data = p + 1; 444 | value.len = param->len - (p - param->data) - 1; 445 | 446 | src = dst = value.data; 447 | 448 | ngx_unescape_uri(&dst, &src, value.len, NGX_UNESCAPE_URI); 449 | 450 | value.len = dst - value.data; 451 | 452 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 453 | "eval param: \"%V\"=\"%V\"", &name, &value); 454 | 455 | return ngx_http_eval_set_variable_value(r, ctx, &name, &value); 456 | } 457 | 458 | static ngx_int_t 459 | ngx_http_eval_urlencoded(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx) 460 | { 461 | u_char *pos, *last; 462 | ngx_str_t param; 463 | ngx_int_t rc; 464 | 465 | if (!r->upstream || r->upstream->buffer.last == r->upstream->buffer.pos) { 466 | return NGX_OK; 467 | } 468 | 469 | pos = r->upstream->buffer.pos; 470 | last = r->upstream->buffer.last; 471 | 472 | do { 473 | param.data = pos; 474 | param.len = 0; 475 | 476 | while (pos != last) { 477 | if (*pos == '&') { 478 | pos++; 479 | break; 480 | } 481 | 482 | if (*pos == CR || *pos == LF) { 483 | pos = last; 484 | break; 485 | } 486 | 487 | param.len++; 488 | pos++; 489 | } 490 | 491 | if(param.len != 0) { 492 | rc = ngx_http_eval_parse_param(r, ctx, ¶m); 493 | 494 | if(rc != NGX_OK) { 495 | return rc; 496 | } 497 | } 498 | }while(pos != last); 499 | 500 | return NGX_OK; 501 | } 502 | 503 | static void * 504 | ngx_http_eval_create_loc_conf(ngx_conf_t *cf) 505 | { 506 | ngx_http_eval_loc_conf_t *conf; 507 | 508 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_eval_loc_conf_t)); 509 | 510 | if (conf == NULL) { 511 | return NGX_CONF_ERROR; 512 | } 513 | 514 | conf->escalate = NGX_CONF_UNSET; 515 | 516 | return conf; 517 | } 518 | 519 | static char * 520 | ngx_http_eval_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 521 | { 522 | ngx_http_eval_loc_conf_t *prev = parent; 523 | ngx_http_eval_loc_conf_t *conf = child; 524 | 525 | ngx_conf_merge_value(conf->escalate, prev->escalate, 0); 526 | ngx_conf_merge_str_value(conf->override_content_type, prev->override_content_type, ""); 527 | 528 | return NGX_CONF_OK; 529 | } 530 | 531 | static ngx_int_t 532 | ngx_http_eval_variable(ngx_http_request_t *r, 533 | ngx_http_variable_value_t *v, uintptr_t data) 534 | { 535 | v->valid = 1; 536 | v->no_cacheable = 0; 537 | v->not_found = 0; 538 | 539 | v->len = 0; 540 | v->data = (u_char*)""; 541 | 542 | return NGX_OK; 543 | } 544 | 545 | static char * 546 | ngx_http_eval_add_variables(ngx_conf_t *cf, ngx_http_eval_block_t *block) 547 | { 548 | ngx_uint_t i; 549 | ngx_int_t index; 550 | ngx_str_t *value; 551 | ngx_http_variable_t *v; 552 | ngx_http_eval_variable_t *variable; 553 | 554 | value = cf->args->elts; 555 | 556 | block->variables = ngx_array_create(cf->pool, 557 | cf->args->nelts, sizeof(ngx_http_eval_variable_t)); 558 | 559 | if(block->variables == NULL) { 560 | return NGX_CONF_ERROR; 561 | } 562 | 563 | for(i = 1;iargs->nelts;i++) { 564 | if (value[i].data[0] != '$') { 565 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 566 | "invalid variable name \"%V\"", &value[1]); 567 | return NGX_CONF_ERROR; 568 | } 569 | 570 | variable = ngx_array_push(block->variables); 571 | if(variable == NULL) { 572 | return NGX_CONF_ERROR; 573 | } 574 | 575 | value[i].len--; 576 | value[i].data++; 577 | 578 | v = ngx_http_add_variable(cf, &value[i], NGX_HTTP_VAR_CHANGEABLE); 579 | if (v == NULL) { 580 | return NGX_CONF_ERROR; 581 | } 582 | 583 | index = ngx_http_get_variable_index(cf, &value[i]); 584 | if (index == NGX_ERROR) { 585 | return NGX_CONF_ERROR; 586 | } 587 | 588 | if (v->get_handler == NULL) 589 | { 590 | v->get_handler = ngx_http_eval_variable; 591 | v->data = index; 592 | } 593 | 594 | variable->variable = v; 595 | variable->index = index; 596 | } 597 | 598 | return NGX_CONF_OK; 599 | } 600 | 601 | static ngx_int_t 602 | ngx_http_eval_add_block(ngx_conf_t *cf, ngx_http_eval_loc_conf_t *conf, ngx_str_t *name) { 603 | ngx_http_eval_block_t *block; 604 | 605 | if(conf->blocks == NULL) { 606 | conf->blocks = ngx_array_create(cf->pool, 1, sizeof(ngx_http_eval_block_t)); 607 | 608 | if(conf->blocks == NULL) { 609 | return NGX_ERROR; 610 | } 611 | } 612 | 613 | block = ngx_array_push(conf->blocks); 614 | 615 | if(block == NULL) { 616 | return NGX_ERROR; 617 | } 618 | 619 | block->eval_location = *name; 620 | 621 | if(ngx_http_eval_add_variables(cf, block) != NGX_CONF_OK) { 622 | return NGX_ERROR; 623 | } 624 | 625 | return NGX_OK; 626 | } 627 | 628 | static char * 629 | ngx_http_eval_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 630 | { 631 | ngx_http_eval_loc_conf_t *pecf = conf; 632 | 633 | char *rv; 634 | void *mconf; 635 | ngx_str_t name; 636 | ngx_uint_t i; 637 | ngx_conf_t save; 638 | ngx_http_module_t *module; 639 | ngx_http_conf_ctx_t *ctx, *pctx; 640 | ngx_http_core_loc_conf_t *clcf, *rclcf; 641 | ngx_http_core_srv_conf_t *cscf; 642 | 643 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); 644 | if (ctx == NULL) { 645 | return NGX_CONF_ERROR; 646 | } 647 | 648 | pctx = cf->ctx; 649 | ctx->main_conf = pctx->main_conf; 650 | ctx->srv_conf = pctx->srv_conf; 651 | 652 | ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); 653 | if (ctx->loc_conf == NULL) { 654 | return NGX_CONF_ERROR; 655 | } 656 | 657 | for (i = 0; ngx_modules[i]; i++) { 658 | if (ngx_modules[i]->type != NGX_HTTP_MODULE) { 659 | continue; 660 | } 661 | 662 | module = ngx_modules[i]->ctx; 663 | 664 | if (module->create_loc_conf) { 665 | 666 | mconf = module->create_loc_conf(cf); 667 | if (mconf == NULL) { 668 | return NGX_CONF_ERROR; 669 | } 670 | 671 | ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; 672 | } 673 | } 674 | 675 | clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; 676 | 677 | name.len = sizeof("/eval_") - 1 + NGX_OFF_T_LEN; 678 | 679 | name.data = ngx_palloc(cf->pool, name.len); 680 | 681 | if(name.data == NULL) { 682 | return NGX_CONF_ERROR; 683 | } 684 | 685 | name.len = ngx_sprintf(name.data, "/eval_%O", (off_t)(uintptr_t)clcf) - name.data; 686 | 687 | clcf->loc_conf = ctx->loc_conf; 688 | clcf->name = name; 689 | clcf->exact_match = 0; 690 | clcf->noname = 0; 691 | clcf->internal = 1; 692 | clcf->noregex = 1; 693 | 694 | cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); 695 | 696 | rclcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; 697 | 698 | if (ngx_http_add_location(cf, &rclcf->locations, clcf) != NGX_OK) { 699 | return NGX_CONF_ERROR; 700 | } 701 | 702 | if(ngx_http_eval_add_block(cf, pecf, &clcf->name) != NGX_OK) { 703 | return NGX_CONF_ERROR; 704 | } 705 | 706 | save = *cf; 707 | cf->ctx = ctx; 708 | cf->cmd_type = NGX_HTTP_LOC_CONF; 709 | 710 | rv = ngx_conf_parse(cf, NULL); 711 | 712 | *cf = save; 713 | 714 | return rv; 715 | } 716 | 717 | static ngx_int_t 718 | ngx_http_eval_init(ngx_conf_t *cf) 719 | { 720 | ngx_http_handler_pt *h; 721 | ngx_http_core_main_conf_t *cmcf; 722 | 723 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 724 | 725 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); 726 | if (h == NULL) { 727 | return NGX_ERROR; 728 | } 729 | 730 | *h = ngx_http_eval_handler; 731 | 732 | return NGX_OK; 733 | } 734 | --------------------------------------------------------------------------------