# HG changeset patch # User Igor Sysoev # Date 1237714611 0 # Node ID 8afc4df77ee802a178ea0f5541a33decad106760 # Parent 41a965fba14137525f8683bb0111e99d1b95f74f ngx_http_script_flush_complex_value() ngx_http_complex_value() ngx_http_compile_complex_value() diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -12,7 +12,7 @@ static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc); static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc); static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, - ngx_str_t *value); + ngx_str_t *value, ngx_uint_t last); static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name); static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc); @@ -20,6 +20,10 @@ static ngx_int_t ngx_http_script_add_arg static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n); #endif +static ngx_int_t + ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc); +static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e); +static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e); #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code @@ -27,6 +31,186 @@ static ngx_int_t ngx_http_script_add_cap static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL; +void +ngx_http_scrip_flush_complex_value(ngx_http_request_t *r, + ngx_http_complex_value_t *val) +{ + ngx_uint_t *index; + + index = val->flushes; + + if (index) { + while (*index != (ngx_uint_t) -1) { + + if (r->variables[*index].no_cacheable) { + r->variables[*index].valid = 0; + r->variables[*index].not_found = 0; + } + + index++; + } + } +} + + +ngx_int_t +ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, + ngx_str_t *value) +{ + size_t len; + ngx_http_script_code_pt code; + ngx_http_script_len_code_pt lcode; + ngx_http_script_engine_t e; + + if (val->lengths == NULL) { + *value = val->value; + return NGX_OK; + } + + ngx_http_scrip_flush_complex_value(r, val); + + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + e.ip = val->lengths; + e.request = r; + e.flushed = 1; + + len = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + value->len = len; + value->data = ngx_pnalloc(r->pool, len); + if (value->data == NULL) { + return NGX_ERROR; + } + + e.ip = val->values; + e.pos = value->data; + e.buf = *value; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + + *value = e.buf; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) +{ + ngx_str_t *v; + ngx_uint_t i, n, nv, nc; + ngx_array_t flushes, lengths, values, *pf, *pl, *pv; + ngx_http_script_compile_t sc; + + v = ccv->value; + + if (v->len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter"); + return NGX_ERROR; + } + + ccv->complex_value->value = *v; + ccv->complex_value->flushes = NULL; + ccv->complex_value->lengths = NULL; + ccv->complex_value->values = NULL; + + nv = 0; + nc = 0; + + for (i = 0; i < v->len; i++) { + if (v->data[i] == '$') { + if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { + nc++; + + } else { + nv++; + } + } + } + + if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) { + + if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { + return NGX_ERROR; + } + + ccv->conf_prefix = 0; + ccv->root_prefix = 0; + } + + if (nv == 0 && nc == 0) { + return NGX_OK; + } + + n = nv + 1; + + if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + n = nv * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t); + + if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + n = (nv * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t) + + v->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + pf = &flushes; + pl = &lengths; + pv = &values; + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = ccv->cf; + sc.source = v; + sc.flushes = &pf; + sc.lengths = &pl; + sc.values = &pv; + sc.complete_lengths = 1; + sc.complete_values = 1; + sc.zero = ccv->zero; + sc.conf_prefix = ccv->conf_prefix; + sc.root_prefix = ccv->root_prefix; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; + } + + if (flushes.nelts) { + ccv->complex_value->flushes = flushes.elts; + ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1; + } + + ccv->complex_value->lengths = lengths.elts; + ccv->complex_value->values = values.elts; + + return NGX_OK; +} + + ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value) { @@ -180,7 +364,9 @@ ngx_http_script_compile(ngx_http_script_ sc->size += name.len; - if (ngx_http_script_add_copy_code(sc, &name) != NGX_OK) { + if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len)) + != NGX_OK) + { return NGX_ERROR; } } @@ -309,8 +495,25 @@ ngx_http_script_init_arrays(ngx_http_scr static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc) { + ngx_str_t zero; uintptr_t *code; + if (sc->zero) { + + zero.len = 1; + zero.data = (u_char *) "\0"; + + if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->conf_prefix || sc->root_prefix) { + if (ngx_http_script_add_full_name_code(sc) != NGX_OK) { + return NGX_ERROR; + } + } + if (sc->complete_lengths) { code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); if (code == NULL) { @@ -373,11 +576,16 @@ ngx_http_script_add_code(ngx_array_t *co static ngx_int_t -ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value) +ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value, + ngx_uint_t last) { - size_t size; + u_char *p; + size_t size, len, zero; ngx_http_script_copy_code_t *code; + zero = (sc->zero && last); + len = value->len + zero; + code = ngx_http_script_add_code(*sc->lengths, sizeof(ngx_http_script_copy_code_t), NULL); if (code == NULL) { @@ -385,10 +593,9 @@ ngx_http_script_add_copy_code(ngx_http_s } code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; - code->len = value->len; + code->len = len; - size = (sizeof(ngx_http_script_copy_code_t) + value->len - + sizeof(uintptr_t) - 1) + size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); code = ngx_http_script_add_code(*sc->values, size, &sc->main); @@ -397,10 +604,15 @@ ngx_http_script_add_copy_code(ngx_http_s } code->code = ngx_http_script_copy_code; - code->len = value->len; + code->len = len; + + p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t), + value->data, value->len); - ngx_memcpy((u_char *) code + sizeof(ngx_http_script_copy_code_t), - value->data, value->len); + if (zero) { + *p = '\0'; + sc->zero = 0; + } return NGX_OK; } @@ -988,6 +1200,77 @@ ngx_http_script_copy_capture_code(ngx_ht #endif +static ngx_int_t +ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc) +{ + ngx_http_script_full_name_code_t *code; + + code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_full_name_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code; + code->prefix = sc->conf_prefix; + + code = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_full_name_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_http_script_full_name_code; + code->prefix = sc->conf_prefix; + + return NGX_OK; +} + + +static size_t +ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_full_name_code_t *code; + + code = (ngx_http_script_full_name_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_full_name_code_t); + + return code->prefix ? sizeof(NGX_CONF_PREFIX) : ngx_cycle->root.len; +} + + +static void +ngx_http_script_full_name_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_full_name_code_t *code; + + ngx_str_t value; + + code = (ngx_http_script_full_name_code_t *) e->ip; + + value.data = e->buf.data; + value.len = e->pos - e->buf.data; + + if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->prefix) + != NGX_OK) + { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + e->buf = value; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script fullname: \"%V\"", &value); + + e->ip += sizeof(ngx_http_script_full_name_code_t); +} + + void ngx_http_script_return_code(ngx_http_script_engine_t *e) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -53,86 +53,114 @@ typedef struct { unsigned compile_args:1; unsigned complete_lengths:1; unsigned complete_values:1; + unsigned zero:1; + unsigned conf_prefix:1; + unsigned root_prefix:1; + unsigned dup_capture:1; - unsigned args:1; } ngx_http_script_compile_t; +typedef struct { + ngx_str_t value; + ngx_uint_t *flushes; + void *lengths; + void *values; +} ngx_http_complex_value_t; + + +typedef struct { + ngx_conf_t *cf; + ngx_str_t *value; + ngx_http_complex_value_t *complex_value; + + unsigned zero:1; + unsigned conf_prefix:1; + unsigned root_prefix:1; +} ngx_http_compile_complex_value_t; + + typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e); typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e); typedef struct { - ngx_http_script_code_pt code; - uintptr_t len; + ngx_http_script_code_pt code; + uintptr_t len; } ngx_http_script_copy_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t index; + ngx_http_script_code_pt code; + uintptr_t index; } ngx_http_script_var_code_t; typedef struct { - ngx_http_script_code_pt code; - ngx_http_set_variable_pt handler; - uintptr_t data; + ngx_http_script_code_pt code; + ngx_http_set_variable_pt handler; + uintptr_t data; } ngx_http_script_var_handler_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t n; + ngx_http_script_code_pt code; + uintptr_t n; } ngx_http_script_copy_capture_code_t; #if (NGX_PCRE) typedef struct { - ngx_http_script_code_pt code; - ngx_regex_t *regex; - ngx_array_t *lengths; - uintptr_t size; - uintptr_t ncaptures; - uintptr_t status; - uintptr_t next; + ngx_http_script_code_pt code; + ngx_regex_t *regex; + ngx_array_t *lengths; + uintptr_t size; + uintptr_t ncaptures; + uintptr_t status; + uintptr_t next; - uintptr_t test:1; - uintptr_t negative_test:1; - uintptr_t uri:1; - uintptr_t args:1; + uintptr_t test:1; + uintptr_t negative_test:1; + uintptr_t uri:1; + uintptr_t args:1; /* add the r->args to the new arguments */ - uintptr_t add_args:1; + uintptr_t add_args:1; - uintptr_t redirect:1; - uintptr_t break_cycle:1; + uintptr_t redirect:1; + uintptr_t break_cycle:1; - ngx_str_t name; + ngx_str_t name; } ngx_http_script_regex_code_t; typedef struct { - ngx_http_script_code_pt code; + ngx_http_script_code_pt code; - uintptr_t uri:1; - uintptr_t args:1; + uintptr_t uri:1; + uintptr_t args:1; /* add the r->args to the new arguments */ - uintptr_t add_args:1; + uintptr_t add_args:1; - uintptr_t redirect:1; + uintptr_t redirect:1; } ngx_http_script_regex_end_code_t; #endif typedef struct { - ngx_http_script_code_pt code; - uintptr_t status; - uintptr_t null; + ngx_http_script_code_pt code; + uintptr_t prefix; +} ngx_http_script_full_name_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + uintptr_t status; + uintptr_t null; } ngx_http_script_return_code_t; @@ -149,32 +177,38 @@ typedef enum { typedef struct { - ngx_http_script_code_pt code; - uintptr_t op; + ngx_http_script_code_pt code; + uintptr_t op; } ngx_http_script_file_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t next; - void **loc_conf; + ngx_http_script_code_pt code; + uintptr_t next; + void **loc_conf; } ngx_http_script_if_code_t; typedef struct { - ngx_http_script_code_pt code; - ngx_array_t *lengths; + ngx_http_script_code_pt code; + ngx_array_t *lengths; } ngx_http_script_complex_value_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t value; - uintptr_t text_len; - uintptr_t text_data; + ngx_http_script_code_pt code; + uintptr_t value; + uintptr_t text_len; + uintptr_t text_data; } ngx_http_script_value_code_t; +void ngx_http_scrip_flush_complex_value(ngx_http_request_t *r, + ngx_http_complex_value_t *val); +ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, + ngx_http_complex_value_t *val, ngx_str_t *value); +ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); + ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value); ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,