Annotation of embedaddon/nginx/src/http/modules/ngx_http_rewrite_module.c, revision 1.1.1.1
1.1 misho 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_array_t *codes; /* uintptr_t */
15:
16: ngx_uint_t stack_size;
17:
18: ngx_flag_t log;
19: ngx_flag_t uninitialized_variable_warn;
20: } ngx_http_rewrite_loc_conf_t;
21:
22:
23: static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
24: static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
25: void *parent, void *child);
26: static ngx_int_t ngx_http_rewrite_init(ngx_conf_t *cf);
27: static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
28: static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
29: void *conf);
30: static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
31: void *conf);
32: static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
33: void *conf);
34: static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
35: ngx_http_rewrite_loc_conf_t *lcf);
36: static char *ngx_http_rewrite_variable(ngx_conf_t *cf,
37: ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
38: static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
39: void *conf);
40: static char * ngx_http_rewrite_value(ngx_conf_t *cf,
41: ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
42:
43:
44: static ngx_command_t ngx_http_rewrite_commands[] = {
45:
46: { ngx_string("rewrite"),
47: NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
48: |NGX_CONF_TAKE23,
49: ngx_http_rewrite,
50: NGX_HTTP_LOC_CONF_OFFSET,
51: 0,
52: NULL },
53:
54: { ngx_string("return"),
55: NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
56: |NGX_CONF_TAKE12,
57: ngx_http_rewrite_return,
58: NGX_HTTP_LOC_CONF_OFFSET,
59: 0,
60: NULL },
61:
62: { ngx_string("break"),
63: NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
64: |NGX_CONF_NOARGS,
65: ngx_http_rewrite_break,
66: NGX_HTTP_LOC_CONF_OFFSET,
67: 0,
68: NULL },
69:
70: { ngx_string("if"),
71: NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
72: ngx_http_rewrite_if,
73: NGX_HTTP_LOC_CONF_OFFSET,
74: 0,
75: NULL },
76:
77: { ngx_string("set"),
78: NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
79: |NGX_CONF_TAKE2,
80: ngx_http_rewrite_set,
81: NGX_HTTP_LOC_CONF_OFFSET,
82: 0,
83: NULL },
84:
85: { ngx_string("rewrite_log"),
86: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
87: |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
88: ngx_conf_set_flag_slot,
89: NGX_HTTP_LOC_CONF_OFFSET,
90: offsetof(ngx_http_rewrite_loc_conf_t, log),
91: NULL },
92:
93: { ngx_string("uninitialized_variable_warn"),
94: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
95: |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
96: ngx_conf_set_flag_slot,
97: NGX_HTTP_LOC_CONF_OFFSET,
98: offsetof(ngx_http_rewrite_loc_conf_t, uninitialized_variable_warn),
99: NULL },
100:
101: ngx_null_command
102: };
103:
104:
105: static ngx_http_module_t ngx_http_rewrite_module_ctx = {
106: NULL, /* preconfiguration */
107: ngx_http_rewrite_init, /* postconfiguration */
108:
109: NULL, /* create main configuration */
110: NULL, /* init main configuration */
111:
112: NULL, /* create server configuration */
113: NULL, /* merge server configuration */
114:
115: ngx_http_rewrite_create_loc_conf, /* create location configuration */
116: ngx_http_rewrite_merge_loc_conf /* merge location configuration */
117: };
118:
119:
120: ngx_module_t ngx_http_rewrite_module = {
121: NGX_MODULE_V1,
122: &ngx_http_rewrite_module_ctx, /* module context */
123: ngx_http_rewrite_commands, /* module directives */
124: NGX_HTTP_MODULE, /* module type */
125: NULL, /* init master */
126: NULL, /* init module */
127: NULL, /* init process */
128: NULL, /* init thread */
129: NULL, /* exit thread */
130: NULL, /* exit process */
131: NULL, /* exit master */
132: NGX_MODULE_V1_PADDING
133: };
134:
135:
136: static ngx_int_t
137: ngx_http_rewrite_handler(ngx_http_request_t *r)
138: {
139: ngx_int_t index;
140: ngx_http_script_code_pt code;
141: ngx_http_script_engine_t *e;
142: ngx_http_core_srv_conf_t *cscf;
143: ngx_http_core_main_conf_t *cmcf;
144: ngx_http_rewrite_loc_conf_t *rlcf;
145:
146: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
147: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
148: index = cmcf->phase_engine.location_rewrite_index;
149:
150: if (r->phase_handler == index && r->loc_conf == cscf->ctx->loc_conf) {
151: /* skipping location rewrite phase for server null location */
152: return NGX_DECLINED;
153: }
154:
155: rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
156:
157: if (rlcf->codes == NULL) {
158: return NGX_DECLINED;
159: }
160:
161: e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
162: if (e == NULL) {
163: return NGX_HTTP_INTERNAL_SERVER_ERROR;
164: }
165:
166: e->sp = ngx_pcalloc(r->pool,
167: rlcf->stack_size * sizeof(ngx_http_variable_value_t));
168: if (e->sp == NULL) {
169: return NGX_HTTP_INTERNAL_SERVER_ERROR;
170: }
171:
172: e->ip = rlcf->codes->elts;
173: e->request = r;
174: e->quote = 1;
175: e->log = rlcf->log;
176: e->status = NGX_DECLINED;
177:
178: while (*(uintptr_t *) e->ip) {
179: code = *(ngx_http_script_code_pt *) e->ip;
180: code(e);
181: }
182:
183: if (e->status < NGX_HTTP_BAD_REQUEST) {
184: return e->status;
185: }
186:
187: if (r->err_status == 0) {
188: return e->status;
189: }
190:
191: return r->err_status;
192: }
193:
194:
195: static ngx_int_t
196: ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
197: uintptr_t data)
198: {
199: ngx_http_variable_t *var;
200: ngx_http_core_main_conf_t *cmcf;
201: ngx_http_rewrite_loc_conf_t *rlcf;
202:
203: rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
204:
205: if (rlcf->uninitialized_variable_warn == 0) {
206: *v = ngx_http_variable_null_value;
207: return NGX_OK;
208: }
209:
210: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
211:
212: var = cmcf->variables.elts;
213:
214: /*
215: * the ngx_http_rewrite_module sets variables directly in r->variables,
216: * and they should be handled by ngx_http_get_indexed_variable(),
217: * so the handler is called only if the variable is not initialized
218: */
219:
220: ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
221: "using uninitialized \"%V\" variable", &var[data].name);
222:
223: *v = ngx_http_variable_null_value;
224:
225: return NGX_OK;
226: }
227:
228:
229: static void *
230: ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
231: {
232: ngx_http_rewrite_loc_conf_t *conf;
233:
234: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
235: if (conf == NULL) {
236: return NULL;
237: }
238:
239: conf->stack_size = NGX_CONF_UNSET_UINT;
240: conf->log = NGX_CONF_UNSET;
241: conf->uninitialized_variable_warn = NGX_CONF_UNSET;
242:
243: return conf;
244: }
245:
246:
247: static char *
248: ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
249: {
250: ngx_http_rewrite_loc_conf_t *prev = parent;
251: ngx_http_rewrite_loc_conf_t *conf = child;
252:
253: uintptr_t *code;
254:
255: ngx_conf_merge_value(conf->log, prev->log, 0);
256: ngx_conf_merge_value(conf->uninitialized_variable_warn,
257: prev->uninitialized_variable_warn, 1);
258: ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);
259:
260: if (conf->codes == NULL) {
261: return NGX_CONF_OK;
262: }
263:
264: if (conf->codes == prev->codes) {
265: return NGX_CONF_OK;
266: }
267:
268: code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
269: if (code == NULL) {
270: return NGX_CONF_ERROR;
271: }
272:
273: *code = (uintptr_t) NULL;
274:
275: return NGX_CONF_OK;
276: }
277:
278:
279: static ngx_int_t
280: ngx_http_rewrite_init(ngx_conf_t *cf)
281: {
282: ngx_http_handler_pt *h;
283: ngx_http_core_main_conf_t *cmcf;
284:
285: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
286:
287: h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
288: if (h == NULL) {
289: return NGX_ERROR;
290: }
291:
292: *h = ngx_http_rewrite_handler;
293:
294: h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
295: if (h == NULL) {
296: return NGX_ERROR;
297: }
298:
299: *h = ngx_http_rewrite_handler;
300:
301: return NGX_OK;
302: }
303:
304:
305: static char *
306: ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
307: {
308: ngx_http_rewrite_loc_conf_t *lcf = conf;
309:
310: ngx_str_t *value;
311: ngx_uint_t last;
312: ngx_regex_compile_t rc;
313: ngx_http_script_code_pt *code;
314: ngx_http_script_compile_t sc;
315: ngx_http_script_regex_code_t *regex;
316: ngx_http_script_regex_end_code_t *regex_end;
317: u_char errstr[NGX_MAX_CONF_ERRSTR];
318:
319: regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
320: sizeof(ngx_http_script_regex_code_t));
321: if (regex == NULL) {
322: return NGX_CONF_ERROR;
323: }
324:
325: ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
326:
327: value = cf->args->elts;
328:
329: ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
330:
331: rc.pattern = value[1];
332: rc.err.len = NGX_MAX_CONF_ERRSTR;
333: rc.err.data = errstr;
334:
335: /* TODO: NGX_REGEX_CASELESS */
336:
337: regex->regex = ngx_http_regex_compile(cf, &rc);
338: if (regex->regex == NULL) {
339: return NGX_CONF_ERROR;
340: }
341:
342: regex->code = ngx_http_script_regex_start_code;
343: regex->uri = 1;
344: regex->name = value[1];
345:
346: if (value[2].data[value[2].len - 1] == '?') {
347:
348: /* the last "?" drops the original arguments */
349: value[2].len--;
350:
351: } else {
352: regex->add_args = 1;
353: }
354:
355: last = 0;
356:
357: if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
358: || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
359: || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
360: {
361: regex->status = NGX_HTTP_MOVED_TEMPORARILY;
362: regex->redirect = 1;
363: last = 1;
364: }
365:
366: if (cf->args->nelts == 4) {
367: if (ngx_strcmp(value[3].data, "last") == 0) {
368: last = 1;
369:
370: } else if (ngx_strcmp(value[3].data, "break") == 0) {
371: regex->break_cycle = 1;
372: last = 1;
373:
374: } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
375: regex->status = NGX_HTTP_MOVED_TEMPORARILY;
376: regex->redirect = 1;
377: last = 1;
378:
379: } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
380: regex->status = NGX_HTTP_MOVED_PERMANENTLY;
381: regex->redirect = 1;
382: last = 1;
383:
384: } else {
385: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
386: "invalid parameter \"%V\"", &value[3]);
387: return NGX_CONF_ERROR;
388: }
389: }
390:
391: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
392:
393: sc.cf = cf;
394: sc.source = &value[2];
395: sc.lengths = ®ex->lengths;
396: sc.values = &lcf->codes;
397: sc.variables = ngx_http_script_variables_count(&value[2]);
398: sc.main = regex;
399: sc.complete_lengths = 1;
400: sc.compile_args = !regex->redirect;
401:
402: if (ngx_http_script_compile(&sc) != NGX_OK) {
403: return NGX_CONF_ERROR;
404: }
405:
406: regex = sc.main;
407:
408: regex->size = sc.size;
409: regex->args = sc.args;
410:
411: if (sc.variables == 0 && !sc.dup_capture) {
412: regex->lengths = NULL;
413: }
414:
415: regex_end = ngx_http_script_add_code(lcf->codes,
416: sizeof(ngx_http_script_regex_end_code_t),
417: ®ex);
418: if (regex_end == NULL) {
419: return NGX_CONF_ERROR;
420: }
421:
422: regex_end->code = ngx_http_script_regex_end_code;
423: regex_end->uri = regex->uri;
424: regex_end->args = regex->args;
425: regex_end->add_args = regex->add_args;
426: regex_end->redirect = regex->redirect;
427:
428: if (last) {
429: code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex);
430: if (code == NULL) {
431: return NGX_CONF_ERROR;
432: }
433:
434: *code = NULL;
435: }
436:
437: regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
438: - (u_char *) regex;
439:
440: return NGX_CONF_OK;
441: }
442:
443:
444: static char *
445: ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
446: {
447: ngx_http_rewrite_loc_conf_t *lcf = conf;
448:
449: u_char *p;
450: ngx_str_t *value, *v;
451: ngx_http_script_return_code_t *ret;
452: ngx_http_compile_complex_value_t ccv;
453:
454: ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
455: sizeof(ngx_http_script_return_code_t));
456: if (ret == NULL) {
457: return NGX_CONF_ERROR;
458: }
459:
460: value = cf->args->elts;
461:
462: ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));
463:
464: ret->code = ngx_http_script_return_code;
465:
466: p = value[1].data;
467:
468: ret->status = ngx_atoi(p, value[1].len);
469:
470: if (ret->status == (uintptr_t) NGX_ERROR) {
471:
472: if (cf->args->nelts == 2
473: && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
474: || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
475: || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
476: {
477: ret->status = NGX_HTTP_MOVED_TEMPORARILY;
478: v = &value[1];
479:
480: } else {
481: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
482: "invalid return code \"%V\"", &value[1]);
483: return NGX_CONF_ERROR;
484: }
485:
486: } else {
487:
488: if (ret->status > 999) {
489: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
490: "invalid return code \"%V\"", &value[1]);
491: return NGX_CONF_ERROR;
492: }
493:
494: if (cf->args->nelts == 2) {
495: return NGX_CONF_OK;
496: }
497:
498: v = &value[2];
499: }
500:
501: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
502:
503: ccv.cf = cf;
504: ccv.value = v;
505: ccv.complex_value = &ret->text;
506:
507: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
508: return NGX_CONF_ERROR;
509: }
510:
511: return NGX_CONF_OK;
512: }
513:
514:
515: static char *
516: ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
517: {
518: ngx_http_rewrite_loc_conf_t *lcf = conf;
519:
520: ngx_http_script_code_pt *code;
521:
522: code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
523: if (code == NULL) {
524: return NGX_CONF_ERROR;
525: }
526:
527: *code = ngx_http_script_break_code;
528:
529: return NGX_CONF_OK;
530: }
531:
532:
533: static char *
534: ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
535: {
536: ngx_http_rewrite_loc_conf_t *lcf = conf;
537:
538: void *mconf;
539: char *rv;
540: u_char *elts;
541: ngx_uint_t i;
542: ngx_conf_t save;
543: ngx_http_module_t *module;
544: ngx_http_conf_ctx_t *ctx, *pctx;
545: ngx_http_core_loc_conf_t *clcf, *pclcf;
546: ngx_http_script_if_code_t *if_code;
547: ngx_http_rewrite_loc_conf_t *nlcf;
548:
549: ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
550: if (ctx == NULL) {
551: return NGX_CONF_ERROR;
552: }
553:
554: pctx = cf->ctx;
555: ctx->main_conf = pctx->main_conf;
556: ctx->srv_conf = pctx->srv_conf;
557:
558: ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
559: if (ctx->loc_conf == NULL) {
560: return NGX_CONF_ERROR;
561: }
562:
563: for (i = 0; ngx_modules[i]; i++) {
564: if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
565: continue;
566: }
567:
568: module = ngx_modules[i]->ctx;
569:
570: if (module->create_loc_conf) {
571:
572: mconf = module->create_loc_conf(cf);
573: if (mconf == NULL) {
574: return NGX_CONF_ERROR;
575: }
576:
577: ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
578: }
579: }
580:
581: pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
582:
583: clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
584: clcf->loc_conf = ctx->loc_conf;
585: clcf->name = pclcf->name;
586: clcf->noname = 1;
587:
588: if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
589: return NGX_CONF_ERROR;
590: }
591:
592: if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
593: return NGX_CONF_ERROR;
594: }
595:
596: if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
597: if (if_code == NULL) {
598: return NGX_CONF_ERROR;
599: }
600:
601: if_code->code = ngx_http_script_if_code;
602:
603: elts = lcf->codes->elts;
604:
605:
606: /* the inner directives must be compiled to the same code array */
607:
608: nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
609: nlcf->codes = lcf->codes;
610:
611:
612: save = *cf;
613: cf->ctx = ctx;
614:
615: if (pclcf->name.len == 0) {
616: if_code->loc_conf = NULL;
617: cf->cmd_type = NGX_HTTP_SIF_CONF;
618:
619: } else {
620: if_code->loc_conf = ctx->loc_conf;
621: cf->cmd_type = NGX_HTTP_LIF_CONF;
622: }
623:
624: rv = ngx_conf_parse(cf, NULL);
625:
626: *cf = save;
627:
628: if (rv != NGX_CONF_OK) {
629: return rv;
630: }
631:
632:
633: if (elts != lcf->codes->elts) {
634: if_code = (ngx_http_script_if_code_t *)
635: ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
636: }
637:
638: if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
639: - (u_char *) if_code;
640:
641: /* the code array belong to parent block */
642:
643: nlcf->codes = NULL;
644:
645: return NGX_CONF_OK;
646: }
647:
648:
649: static char *
650: ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
651: {
652: u_char *p;
653: size_t len;
654: ngx_str_t *value;
655: ngx_uint_t cur, last;
656: ngx_regex_compile_t rc;
657: ngx_http_script_code_pt *code;
658: ngx_http_script_file_code_t *fop;
659: ngx_http_script_regex_code_t *regex;
660: u_char errstr[NGX_MAX_CONF_ERRSTR];
661:
662: value = cf->args->elts;
663: last = cf->args->nelts - 1;
664:
665: if (value[1].len < 1 || value[1].data[0] != '(') {
666: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
667: "invalid condition \"%V\"", &value[1]);
668: return NGX_CONF_ERROR;
669: }
670:
671: if (value[1].len == 1) {
672: cur = 2;
673:
674: } else {
675: cur = 1;
676: value[1].len--;
677: value[1].data++;
678: }
679:
680: if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') {
681: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
682: "invalid condition \"%V\"", &value[last]);
683: return NGX_CONF_ERROR;
684: }
685:
686: if (value[last].len == 1) {
687: last--;
688:
689: } else {
690: value[last].len--;
691: value[last].data[value[last].len] = '\0';
692: }
693:
694: len = value[cur].len;
695: p = value[cur].data;
696:
697: if (len > 1 && p[0] == '$') {
698:
699: if (cur != last && cur + 2 != last) {
700: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
701: "invalid condition \"%V\"", &value[cur]);
702: return NGX_CONF_ERROR;
703: }
704:
705: if (ngx_http_rewrite_variable(cf, lcf, &value[cur]) != NGX_CONF_OK) {
706: return NGX_CONF_ERROR;
707: }
708:
709: if (cur == last) {
710: return NGX_CONF_OK;
711: }
712:
713: cur++;
714:
715: len = value[cur].len;
716: p = value[cur].data;
717:
718: if (len == 1 && p[0] == '=') {
719:
720: if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
721: return NGX_CONF_ERROR;
722: }
723:
724: code = ngx_http_script_start_code(cf->pool, &lcf->codes,
725: sizeof(uintptr_t));
726: if (code == NULL) {
727: return NGX_CONF_ERROR;
728: }
729:
730: *code = ngx_http_script_equal_code;
731:
732: return NGX_CONF_OK;
733: }
734:
735: if (len == 2 && p[0] == '!' && p[1] == '=') {
736:
737: if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
738: return NGX_CONF_ERROR;
739: }
740:
741: code = ngx_http_script_start_code(cf->pool, &lcf->codes,
742: sizeof(uintptr_t));
743: if (code == NULL) {
744: return NGX_CONF_ERROR;
745: }
746:
747: *code = ngx_http_script_not_equal_code;
748: return NGX_CONF_OK;
749: }
750:
751: if ((len == 1 && p[0] == '~')
752: || (len == 2 && p[0] == '~' && p[1] == '*')
753: || (len == 2 && p[0] == '!' && p[1] == '~')
754: || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
755: {
756: regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
757: sizeof(ngx_http_script_regex_code_t));
758: if (regex == NULL) {
759: return NGX_CONF_ERROR;
760: }
761:
762: ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
763:
764: ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
765:
766: rc.pattern = value[last];
767: rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
768: rc.err.len = NGX_MAX_CONF_ERRSTR;
769: rc.err.data = errstr;
770:
771: regex->regex = ngx_http_regex_compile(cf, &rc);
772: if (regex->regex == NULL) {
773: return NGX_CONF_ERROR;
774: }
775:
776: regex->code = ngx_http_script_regex_start_code;
777: regex->next = sizeof(ngx_http_script_regex_code_t);
778: regex->test = 1;
779: if (p[0] == '!') {
780: regex->negative_test = 1;
781: }
782: regex->name = value[last];
783:
784: return NGX_CONF_OK;
785: }
786:
787: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
788: "unexpected \"%V\" in condition", &value[cur]);
789: return NGX_CONF_ERROR;
790:
791: } else if ((len == 2 && p[0] == '-')
792: || (len == 3 && p[0] == '!' && p[1] == '-'))
793: {
794: if (cur + 1 != last) {
795: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
796: "invalid condition \"%V\"", &value[cur]);
797: return NGX_CONF_ERROR;
798: }
799:
800: value[last].data[value[last].len] = '\0';
801: value[last].len++;
802:
803: if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
804: return NGX_CONF_ERROR;
805: }
806:
807: fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
808: sizeof(ngx_http_script_file_code_t));
809: if (fop == NULL) {
810: return NGX_CONF_ERROR;
811: }
812:
813: fop->code = ngx_http_script_file_code;
814:
815: if (p[1] == 'f') {
816: fop->op = ngx_http_script_file_plain;
817: return NGX_CONF_OK;
818: }
819:
820: if (p[1] == 'd') {
821: fop->op = ngx_http_script_file_dir;
822: return NGX_CONF_OK;
823: }
824:
825: if (p[1] == 'e') {
826: fop->op = ngx_http_script_file_exists;
827: return NGX_CONF_OK;
828: }
829:
830: if (p[1] == 'x') {
831: fop->op = ngx_http_script_file_exec;
832: return NGX_CONF_OK;
833: }
834:
835: if (p[0] == '!') {
836: if (p[2] == 'f') {
837: fop->op = ngx_http_script_file_not_plain;
838: return NGX_CONF_OK;
839: }
840:
841: if (p[2] == 'd') {
842: fop->op = ngx_http_script_file_not_dir;
843: return NGX_CONF_OK;
844: }
845:
846: if (p[2] == 'e') {
847: fop->op = ngx_http_script_file_not_exists;
848: return NGX_CONF_OK;
849: }
850:
851: if (p[2] == 'x') {
852: fop->op = ngx_http_script_file_not_exec;
853: return NGX_CONF_OK;
854: }
855: }
856:
857: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
858: "invalid condition \"%V\"", &value[cur]);
859: return NGX_CONF_ERROR;
860: }
861:
862: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
863: "invalid condition \"%V\"", &value[cur]);
864:
865: return NGX_CONF_ERROR;
866: }
867:
868:
869: static char *
870: ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
871: ngx_str_t *value)
872: {
873: ngx_int_t index;
874: ngx_http_script_var_code_t *var_code;
875:
876: value->len--;
877: value->data++;
878:
879: index = ngx_http_get_variable_index(cf, value);
880:
881: if (index == NGX_ERROR) {
882: return NGX_CONF_ERROR;
883: }
884:
885: var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
886: sizeof(ngx_http_script_var_code_t));
887: if (var_code == NULL) {
888: return NGX_CONF_ERROR;
889: }
890:
891: var_code->code = ngx_http_script_var_code;
892: var_code->index = index;
893:
894: return NGX_CONF_OK;
895: }
896:
897:
898: static char *
899: ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
900: {
901: ngx_http_rewrite_loc_conf_t *lcf = conf;
902:
903: ngx_int_t index;
904: ngx_str_t *value;
905: ngx_http_variable_t *v;
906: ngx_http_script_var_code_t *vcode;
907: ngx_http_script_var_handler_code_t *vhcode;
908:
909: value = cf->args->elts;
910:
911: if (value[1].data[0] != '$') {
912: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
913: "invalid variable name \"%V\"", &value[1]);
914: return NGX_CONF_ERROR;
915: }
916:
917: value[1].len--;
918: value[1].data++;
919:
920: v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
921: if (v == NULL) {
922: return NGX_CONF_ERROR;
923: }
924:
925: index = ngx_http_get_variable_index(cf, &value[1]);
926: if (index == NGX_ERROR) {
927: return NGX_CONF_ERROR;
928: }
929:
930: if (v->get_handler == NULL
931: && ngx_strncasecmp(value[1].data, (u_char *) "http_", 5) != 0
932: && ngx_strncasecmp(value[1].data, (u_char *) "sent_http_", 10) != 0
933: && ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0)
934: {
935: v->get_handler = ngx_http_rewrite_var;
936: v->data = index;
937: }
938:
939: if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
940: return NGX_CONF_ERROR;
941: }
942:
943: if (v->set_handler) {
944: vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
945: sizeof(ngx_http_script_var_handler_code_t));
946: if (vhcode == NULL) {
947: return NGX_CONF_ERROR;
948: }
949:
950: vhcode->code = ngx_http_script_var_set_handler_code;
951: vhcode->handler = v->set_handler;
952: vhcode->data = v->data;
953:
954: return NGX_CONF_OK;
955: }
956:
957: vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
958: sizeof(ngx_http_script_var_code_t));
959: if (vcode == NULL) {
960: return NGX_CONF_ERROR;
961: }
962:
963: vcode->code = ngx_http_script_set_var_code;
964: vcode->index = (uintptr_t) index;
965:
966: return NGX_CONF_OK;
967: }
968:
969:
970: static char *
971: ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
972: ngx_str_t *value)
973: {
974: ngx_int_t n;
975: ngx_http_script_compile_t sc;
976: ngx_http_script_value_code_t *val;
977: ngx_http_script_complex_value_code_t *complex;
978:
979: n = ngx_http_script_variables_count(value);
980:
981: if (n == 0) {
982: val = ngx_http_script_start_code(cf->pool, &lcf->codes,
983: sizeof(ngx_http_script_value_code_t));
984: if (val == NULL) {
985: return NGX_CONF_ERROR;
986: }
987:
988: n = ngx_atoi(value->data, value->len);
989:
990: if (n == NGX_ERROR) {
991: n = 0;
992: }
993:
994: val->code = ngx_http_script_value_code;
995: val->value = (uintptr_t) n;
996: val->text_len = (uintptr_t) value->len;
997: val->text_data = (uintptr_t) value->data;
998:
999: return NGX_CONF_OK;
1000: }
1001:
1002: complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
1003: sizeof(ngx_http_script_complex_value_code_t));
1004: if (complex == NULL) {
1005: return NGX_CONF_ERROR;
1006: }
1007:
1008: complex->code = ngx_http_script_complex_value_code;
1009: complex->lengths = NULL;
1010:
1011: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1012:
1013: sc.cf = cf;
1014: sc.source = value;
1015: sc.lengths = &complex->lengths;
1016: sc.values = &lcf->codes;
1017: sc.variables = n;
1018: sc.complete_lengths = 1;
1019:
1020: if (ngx_http_script_compile(&sc) != NGX_OK) {
1021: return NGX_CONF_ERROR;
1022: }
1023:
1024: return NGX_CONF_OK;
1025: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>