# HG changeset patch # User Igor Sysoev # Date 1128369600 -14400 # Node ID f63280c59dd520f46039d7ee418c4d1a9aa96a03 # Parent 5bb09dde34e7af6ac95308402847da9a726c9026 nginx 0.2.5 *) Change: the duplicate value of the ngx_http_geo_module variable now causes the warning and changes old value. *) Feature: the ngx_http_ssi_module supports the "set" command. *) Feature: the ngx_http_ssi_module supports the "file" parameter in the "include" command. *) Feature: the ngx_http_ssi_module supports the variable value substitutions in expressions of the "if" command. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,17 @@ + +Changes with nginx 0.2.5 04 Oct 2005 + + *) Change: the duplicate value of the ngx_http_geo_module variable now + causes the warning and changes old value. + + *) Feature: the ngx_http_ssi_module supports the "set" command. + + *) Feature: the ngx_http_ssi_module supports the "file" parameter in + the "include" command. + + *) Feature: the ngx_http_ssi_module supports the variable value + substitutions in epxiressions of the "if" command. + Changes with nginx 0.2.4 03 Oct 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,18 @@ + +Изменения в nginx 0.2.5 04.10.2005 + + *) Изменение: дублирующее значение переменной модуля + ngx_http_geo_module теперь выдаёт предупреждение и изменяёт старое + значение. + + *) Добавление: модуль ngx_http_ssi_module поддерживает команду set. + + *) Добавление: модуль ngx_http_ssi_module поддерживает параметр file в + команде include. + + *) Добавление: модуль ngx_http_ssi_module поддерживает подстановку + значений переменных в выражениях команды if. + Изменения в nginx 0.2.4 03.10.2005 diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.2.4" +#define NGINX_VER "nginx/0.2.5" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -514,7 +514,7 @@ ngx_http_autoindex_handler(ngx_http_requ b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); - if (r->main == NULL) { + if (r->main == r) { b->last_buf = 1; } diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -50,7 +50,7 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_chunked_header_filter(ngx_http_request_t *r) { - if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->main) { + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->main != r) { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -182,11 +182,11 @@ static char * ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { ngx_int_t rc, n; + ngx_str_t *value, file; ngx_uint_t i; - ngx_str_t *value, file; ngx_inet_cidr_t cidrin; ngx_http_geo_conf_t *geo; - ngx_http_variable_value_t *var, **v; + ngx_http_variable_value_t *var, *old, **v; geo = cf->ctx; @@ -274,17 +274,33 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command *v = var; } - rc = ngx_radix32tree_insert(geo->tree, cidrin.addr, cidrin.mask, - (uintptr_t) var); - if (rc == NGX_ERROR) { - return NGX_CONF_ERROR; + for (i = 2; i; i--) { + rc = ngx_radix32tree_insert(geo->tree, cidrin.addr, cidrin.mask, + (uintptr_t) var); + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + /* rc == NGX_BUSY */ + + old = (ngx_http_variable_value_t *) + ngx_radix32tree_find(geo->tree, cidrin.addr & cidrin.mask); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate parameter \"%V\", value: \"%V\", " + "old value: \"%V\"", + &value[0], &var->text, &old->text); + + rc = ngx_radix32tree_delete(geo->tree, cidrin.addr, cidrin.mask); + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } } - if (rc == NGX_BUSY) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate parameter \"%V\"", - &value[0]); - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; + return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -280,7 +280,7 @@ ngx_http_gzip_header_filter(ngx_http_req && r->headers_out.status != NGX_HTTP_FORBIDDEN && r->headers_out.status != NGX_HTTP_NOT_FOUND) || r->header_only - || r->main + || r->main != r || r->http_version < conf->http_version || r->headers_out.content_type.len == 0 || (r->headers_out.content_encoding diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -84,7 +84,7 @@ ngx_http_headers_filter(ngx_http_request if ((r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) - || r->main) + || r->main != r) { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -52,7 +52,7 @@ static ngx_int_t ngx_http_not_modified_h time_t ims; if (r->headers_out.status != NGX_HTTP_OK - || r->main + || r->main != r || r->headers_in.if_modified_since == NULL || r->headers_out.last_modified_time == -1) { diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -134,7 +134,7 @@ ngx_http_range_header_filter(ngx_http_re if (r->http_version < NGX_HTTP_VERSION_10 || r->headers_out.status != NGX_HTTP_OK - || r->main + || r->main != r || r->headers_out.content_length_n == -1 || !r->filter_allow_ranges) { diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -8,15 +8,18 @@ #include #include -#define NGX_HTTP_SSI_MAX_PARAMS 16 - -#define NGX_HTTP_SSI_COMMAND_LEN 31 -#define NGX_HTTP_SSI_PARAM_LEN 31 -#define NGX_HTTP_SSI_PARAMS_N 4 - -#define NGX_HTTP_SSI_ERROR 1 - -#define NGX_HTTP_SSI_DATE_LEN 2048 +#define NGX_HTTP_SSI_MAX_PARAMS 16 + +#define NGX_HTTP_SSI_COMMAND_LEN 31 +#define NGX_HTTP_SSI_PARAM_LEN 31 +#define NGX_HTTP_SSI_PARAMS_N 4 + +#define NGX_HTTP_SSI_ERROR 1 + +#define NGX_HTTP_SSI_DATE_LEN 2048 + + +#define NGX_HTTP_SSI_ADD_PREFIX 1 typedef struct { @@ -32,6 +35,12 @@ typedef struct { typedef struct { + ngx_str_t name; + ngx_str_t value; +} ngx_http_ssi_var_t; + + +typedef struct { ngx_buf_t *buf; u_char *pos; @@ -56,6 +65,8 @@ typedef struct { size_t value_len; + ngx_array_t variables; + ngx_uint_t output; /* unsigned output:1; */ ngx_str_t timefmt; @@ -113,12 +124,18 @@ static ngx_int_t ngx_http_ssi_output(ngx ngx_http_ssi_ctx_t *ctx); static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx); - +static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags); + +static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); -static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, +static ngx_int_t ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); @@ -221,6 +238,8 @@ static u_char ngx_http_ssi_string[] = "< static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); +#define NGX_HTTP_SSI_INCLUDE_VIRTUAL 0 +#define NGX_HTTP_SSI_INCLUDE_FILE 1 #define NGX_HTTP_SSI_ECHO_VAR 0 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 @@ -228,26 +247,25 @@ static ngx_str_t ngx_http_ssi_none = ngx #define NGX_HTTP_SSI_CONFIG_ERRMSG 0 #define NGX_HTTP_SSI_CONFIG_TIMEFMT 1 -#define NGX_HTTP_SSI_INCLUDE_VIRTUAL 0 -#define NGX_HTTP_SSI_INCLUDE_FILE 1 +#define NGX_HTTP_SSI_SET_VAR 0 +#define NGX_HTTP_SSI_SET_VALUE 1 #define NGX_HTTP_SSI_IF_EXPR 0 +static ngx_http_ssi_param_t ngx_http_ssi_include_params[] = { + { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 }, + { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 }, + { ngx_null_string, 0, 0 } +}; + + static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0 }, { ngx_null_string, 0, 0 } }; -static ngx_http_ssi_param_t ngx_http_ssi_include_params[] = { - { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 }, -#if 0 - { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 }, -#endif - { ngx_null_string, 0, 0 } -}; - static ngx_http_ssi_param_t ngx_http_ssi_config_params[] = { { ngx_string("errmsg"), NGX_HTTP_SSI_CONFIG_ERRMSG, 0 }, @@ -256,8 +274,15 @@ static ngx_http_ssi_param_t ngx_http_ss }; +static ngx_http_ssi_param_t ngx_http_ssi_set_params[] = { + { ngx_string("var"), NGX_HTTP_SSI_SET_VAR, 1 }, + { ngx_string("value"), NGX_HTTP_SSI_SET_VALUE, 1 }, + { ngx_null_string, 0, 0 } +}; + + static ngx_http_ssi_param_t ngx_http_ssi_if_params[] = { - { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 0 }, + { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 1 }, { ngx_null_string, 0, 0 } }; @@ -268,11 +293,12 @@ static ngx_http_ssi_param_t ngx_http_ss static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { + { ngx_string("include"), ngx_http_ssi_include, + ngx_http_ssi_include_params, 0, 1 }, { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 }, { ngx_string("config"), ngx_http_ssi_config, ngx_http_ssi_config_params, 0, 0 }, - { ngx_string("include"), ngx_http_ssi_include, - ngx_http_ssi_include_params, 0, 1 }, + { ngx_string("set"), ngx_http_ssi_set, ngx_http_ssi_set_params, 0, 0 }, { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 }, { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 }, @@ -355,7 +381,7 @@ found: r->filter_need_in_memory = 1; - if (r->main == NULL) { + if (r->main == r) { r->headers_out.content_length_n = -1; if (r->headers_out.content_length) { r->headers_out.content_length->hash = 0; @@ -1301,6 +1327,296 @@ ngx_http_ssi_parse(ngx_http_request_t *r } +static ngx_str_t * +ngx_http_ssi_get_variable(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_uint_t i; + ngx_http_ssi_var_t *var; + ngx_http_ssi_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); + + var = ctx->variables.elts; + for (i = 0; i < ctx->variables.nelts; i++) { + if (name->len != var[i].name.len) { + continue; + } + + if (ngx_strncasecmp(name->data, var[i].name.data, name->len) == 0) { + return &var[i].value; + } + } + + return NULL; +} + + +static ngx_int_t +ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t *text, ngx_uint_t flags) +{ + u_char ch, *p, **value, *data; + size_t *size, len, prefix; + ngx_str_t var, part, *val; + ngx_uint_t i, j, n, bracket; + ngx_array_t lengths, values; + ngx_http_variable_value_t *vv; + + n = ngx_http_script_variables_count(text); + + if (n == 0) { + + if (!(flags & NGX_HTTP_SSI_ADD_PREFIX)) { + return NGX_OK; + } + + if (text->data[0] != '/') { + for (prefix = r->uri.len; prefix; prefix--) { + if (r->uri.data[prefix - 1] == '/') { + break; + } + } + + if (prefix) { + len = prefix + text->len; + + data = ngx_palloc(r->pool, len); + if (data == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(data, r->uri.data, prefix); + ngx_memcpy(p, text->data, text->len); + + text->len = len; + text->data = data; + } + } + + return NGX_OK; + } + + if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) { + return NGX_ERROR; + } + + len = 0; + i = 0; + + while (i < text->len) { + + if (text->data[i] == '$') { + + var.len = 0; + + if (++i == text->len) { + goto invalid_variable; + } + + if (text->data[i] == '{') { + bracket = 1; + + if (++i == text->len) { + goto invalid_variable; + } + + var.data = &text->data[i]; + + } else { + bracket = 0; + var.data = &text->data[i]; + } + + for ( /* void */ ; i < text->len; i++, var.len++) { + ch = text->data[i]; + + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "the closing bracket in \"%V\" " + "variable is missing", &var); + return NGX_ERROR; + } + + if (var.len == 0) { + goto invalid_variable; + } + + for (j = 0; j < var.len; j++) { + var.data[j] = ngx_tolower(var.data[j]); + } + + val = ngx_http_ssi_get_variable(r, &var); + + if (val == NULL) { + vv = ngx_http_get_variable(r, &var); + + if (vv == NULL) { + return NGX_ERROR; + } + + if (vv == NGX_HTTP_VAR_NOT_FOUND) { + continue; + } + + part = vv->text; + + } else { + part = *val; + } + + } else { + part.len = 0; + part.data = &text->data[i]; + + while (i < text->len && text->data[i] != '$') { + i++; + part.len++; + } + } + + len += part.len; + + size = ngx_array_push(&lengths); + if (size == NULL) { + return NGX_ERROR; + } + + *size = part.len; + + value = ngx_array_push(&values); + if (value == NULL) { + return NGX_ERROR; + } + + *value = part.data; + } + + prefix = 0; + + size = lengths.elts; + value = values.elts; + + if (flags & NGX_HTTP_SSI_ADD_PREFIX) { + for (i = 0; i < values.nelts; i++) { + if (size[i] != 0) { + if (*value[i] != '/') { + for (prefix = r->uri.len; prefix; prefix--) { + if (r->uri.data[prefix - 1] == '/') { + len += prefix; + break; + } + } + } + + break; + } + } + } + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + text->len = len; + text->data = p; + + if (prefix) { + p = ngx_cpymem(p, r->uri.data, prefix); + } + + for (i = 0; i < values.nelts; i++) { + p = ngx_cpymem(p, value[i], size[i]); + } + + return NGX_OK; + +invalid_variable: + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid variable name in \"%V\"", text); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t **params) +{ + ngx_str_t *uri, *file, args; + ngx_uint_t i; + + uri = params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; + file = params[NGX_HTTP_SSI_INCLUDE_FILE]; + + if (uri && file) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "inlcusion may be either virtual=\"%V\" or file=\"%V\"", + uri, file); + return NGX_HTTP_SSI_ERROR; + } + + if (uri == NULL && file == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "no parameter in \"include\" SSI command"); + return NGX_HTTP_SSI_ERROR; + } + + if (uri == NULL) { + uri = file; + } + + if (ngx_http_ssi_evaluate_string(r, ctx, uri, NGX_HTTP_SSI_ADD_PREFIX) + != NGX_OK) + { + return NGX_HTTP_SSI_ERROR; + } + + args.len = 0; + args.data = NULL; + + if (params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]) { + for (i = 0; i < uri->len; i++) { + if (uri->data[i] == '?') { + args.len = uri->len - i - 1; + args.data = &uri->data[i + 1]; + uri->len -= args.len + 1; + + break; + } + } + } + + if (ngx_http_subrequest(r, uri, &args) != NGX_OK) { + return NGX_HTTP_SSI_ERROR; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) @@ -1313,17 +1629,25 @@ ngx_http_ssi_echo(ngx_http_request_t *r, var = params[NGX_HTTP_SSI_ECHO_VAR]; - for (i = 0; i < var->len; i++) { - var->data[i] = ngx_tolower(var->data[i]); + value = ngx_http_ssi_get_variable(r, var); + + if (value == NULL) { + for (i = 0; i < var->len; i++) { + var->data[i] = ngx_tolower(var->data[i]); + } + + vv = ngx_http_get_variable(r, var); + + if (vv == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + if (vv != NGX_HTTP_VAR_NOT_FOUND) { + value = &vv->text; + } } - vv = ngx_http_get_variable(r, var); - - if (vv == NULL) { - return NGX_HTTP_SSI_ERROR; - } - - if (vv == NGX_HTTP_VAR_NOT_FOUND) { + if (value == NULL) { value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; if (value == NULL) { @@ -1334,8 +1658,6 @@ ngx_http_ssi_echo(ngx_http_request_t *r, } } else { - value = &vv->text; - if (value->len == 0) { return NGX_OK; } @@ -1387,215 +1709,49 @@ ngx_http_ssi_config(ngx_http_request_t * static ngx_int_t -ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, +ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - u_char ch, *p, **value, *data; - size_t *size, len, prefix; - ngx_uint_t i, j, n, bracket; - ngx_str_t uri, args, name; - ngx_array_t lengths, values; - ngx_http_variable_value_t *vv; - - /* TODO: file, virtual vs file */ - - uri = *params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; - args.len = 0; - args.data = NULL; - prefix = 0; - - n = ngx_http_script_variables_count(&uri); - - if (n > 0) { - - if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) { - return NGX_HTTP_SSI_ERROR; - } - - if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) { + ngx_str_t *name, *value, *vv; + ngx_http_ssi_var_t *var; + ngx_http_ssi_ctx_t *mctx; + + mctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); + + if (mctx->variables.elts == NULL) { + if (ngx_array_init(&mctx->variables, r->pool, 4, + sizeof(ngx_http_ssi_var_t)) != NGX_OK) + { return NGX_HTTP_SSI_ERROR; } - - len = 0; - - for (i = 0; i < uri.len; /* void */ ) { - - name.len = 0; - - if (uri.data[i] == '$') { - - if (++i == uri.len) { - goto invalid_variable; - } - - if (uri.data[i] == '{') { - bracket = 1; - - if (++i == uri.len) { - goto invalid_variable; - } - - name.data = &uri.data[i]; - - } else { - bracket = 0; - name.data = &uri.data[i]; - } - - for ( /* void */ ; i < uri.len; i++, name.len++) { - ch = uri.data[i]; - - if (ch == '}' && bracket) { - i++; - bracket = 0; - break; - } - - if ((ch >= 'A' && ch <= 'Z') - || (ch >= 'a' && ch <= 'z') - || (ch >= '0' && ch <= '9') - || ch == '_') - { - continue; - } - - break; - } - - if (bracket) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "the closing bracket in \"%V\" " - "variable is missing", &name); - return NGX_HTTP_SSI_ERROR; - } - - if (name.len == 0) { - goto invalid_variable; - } - - for (j = 0; j < name.len; j++) { - name.data[j] = ngx_tolower(name.data[j]); - } - - vv = ngx_http_get_variable(r, &name); - - if (vv == NULL) { - return NGX_HTTP_SSI_ERROR; - } - - if (vv == NGX_HTTP_VAR_NOT_FOUND) { - continue; - } - - name = vv->text; - - } else { - name.data = &uri.data[i]; - - while (i < uri.len && uri.data[i] != '$') { - i++; - name.len++; - } - } - - len += name.len; - - size = ngx_array_push(&lengths); - if (size == NULL) { - return NGX_HTTP_SSI_ERROR; - } - - *size = name.len; - - value = ngx_array_push(&values); - if (value == NULL) { - return NGX_HTTP_SSI_ERROR; - } - - *value = name.data; - } - - size = lengths.elts; - value = values.elts; - - for (i = 0; i < values.nelts; i++) { - if (size[i] != 0) { - if (*value[i] != '/') { - for (prefix = r->uri.len; prefix; prefix--) { - if (r->uri.data[prefix - 1] == '/') { - len += prefix; - break; - } - } - } - - break; - } - } - - p = ngx_palloc(r->pool, len); - if (p == NULL) { - return NGX_HTTP_SSI_ERROR; - } - - uri.len = len; - uri.data = p; - - if (prefix) { - p = ngx_cpymem(p, r->uri.data, prefix); - } - - for (i = 0; i < values.nelts; i++) { - p = ngx_cpymem(p, value[i], size[i]); - } - - } else { - if (uri.data[0] != '/') { - for (prefix = r->uri.len; prefix; prefix--) { - if (r->uri.data[prefix - 1] == '/') { - break; - } - } - - if (prefix) { - len = prefix + uri.len; - - data = ngx_palloc(r->pool, len); - if (data == NULL) { - return NGX_HTTP_SSI_ERROR; - } - - p = ngx_cpymem(data, r->uri.data, prefix); - ngx_memcpy(p, uri.data, uri.len); - - uri.len = len; - uri.data = data; - } - } } - for (i = 0; i < uri.len; i++) { - if (uri.data[i] == '?') { - args.len = uri.len - i - 1; - args.data = &uri.data[i + 1]; - uri.len -= args.len + 1; - - break; - } - } - - if (ngx_http_subrequest(r, &uri, &args) != NGX_OK) { + name = params[NGX_HTTP_SSI_SET_VAR]; + value = params[NGX_HTTP_SSI_SET_VALUE]; + + if (ngx_http_ssi_evaluate_string(r, ctx, value, 0) != NGX_OK) { return NGX_HTTP_SSI_ERROR; } + vv = ngx_http_ssi_get_variable(r, name); + + if (vv) { + *vv = *value; + return NGX_OK; + } + + var = ngx_array_push(&mctx->variables); + if (var == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + var->name = *name; + var->value = *value; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "set: \"%V\"=\"%V\"", name, value); + return NGX_OK; - -invalid_variable: - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid variable name in \"%V\"", &uri); - - return NGX_ERROR; } @@ -1603,55 +1759,55 @@ static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - u_char *p, *last; - ngx_str_t *expr, var, left, right; - ngx_int_t rc; - ngx_uint_t negative, noregex; - ngx_http_variable_value_t *vv; + u_char *p, *last; + ngx_str_t *expr, left, right; + ngx_int_t rc; + ngx_uint_t negative, noregex; #if (NGX_PCRE) - ngx_str_t err; - ngx_regex_t *regex; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_str_t err; + ngx_regex_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; #endif expr = params[NGX_HTTP_SSI_IF_EXPR]; - if (expr->data[0] != '$') { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid variable name in \"%V\"", expr); - return NGX_HTTP_SSI_ERROR; - } - - var.data = expr->data + 1; + left.data = expr->data; last = expr->data + expr->len; - for (p = var.data; p < last; p++) { + for (p = left.data; p < last; p++) { if (*p >= 'A' && *p <= 'Z') { *p |= 0x20; continue; } - if ((*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') { + if ((*p >= 'a' && *p <= 'z') + || (*p >= '0' && *p <= '9') + || *p == '$' || *p == '{' || *p == '}' || *p == '_') + { continue; } break; } - var.len = p - var.data; + left.len = p - left.data; while (p < last && *p == ' ') { p++; } - vv = ngx_http_get_variable(r, &var); - - if (vv == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "left: \"%V\"", &left); + + if (ngx_http_ssi_evaluate_string(r, ctx, &left, 0) != NGX_OK) { return NGX_HTTP_SSI_ERROR; } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "evaluted left: \"%V\"", &left); + if (p == last) { - if (vv != NGX_HTTP_VAR_NOT_FOUND && vv->text.len != 0) { + if (left.len) { ctx->output = 1; } else { @@ -1693,16 +1849,15 @@ ngx_http_ssi_if(ngx_http_request_t *r, n right.len = last - p; right.data = p; - if (vv == NGX_HTTP_VAR_NOT_FOUND) { - left.len = 0; - left.data = (u_char *) ""; - - } else { - left = vv->text; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "right: \"%V\"", &right); + + if (ngx_http_ssi_evaluate_string(r, ctx, &right, 0) != NGX_OK) { + return NGX_HTTP_SSI_ERROR; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "left: \"%V\" right: \"%V\"", &left, &right); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "evaluted right: \"%V\"", &right); if (noregex) { if (left.len != right.len) { diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -339,7 +339,7 @@ ngx_http_static_handler(ngx_http_request b->in_file = 1; - if (r->main == NULL) { + if (r->main == r) { b->last_buf = 1; } diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -206,7 +206,7 @@ ngx_http_userid_filter(ngx_http_request_ ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; - if (r->main) { + if (r->main != r) { return ngx_http_next_header_filter(r); } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -498,7 +498,7 @@ ngx_http_core_run_phases(ngx_http_reques r->phase = NGX_HTTP_FIND_CONFIG_PHASE; } - if (r->phase == NGX_HTTP_ACCESS_PHASE && r->main) { + if (r->phase == NGX_HTTP_ACCESS_PHASE && r->main != r) { continue; } @@ -1099,7 +1099,7 @@ ngx_http_subrequest(ngx_http_request_t * return NGX_HTTP_INTERNAL_SERVER_ERROR; } - sr->main = r->main ? r->main : r; + sr->main = r->main; sr->parent = r; sr->read_event_handler = ngx_http_request_empty_handler; sr->write_event_handler = ngx_http_request_empty_handler; diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -159,7 +159,7 @@ ngx_http_header_filter(ngx_http_request_ ngx_table_elt_t *header; ngx_http_core_loc_conf_t *clcf; - if (r->main) { + if (r->main != r) { return NGX_OK; } diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -51,7 +51,6 @@ ngx_http_postpone_filter(ngx_http_reques { ngx_int_t rc; ngx_chain_t *out; - ngx_http_request_t *mr; ngx_http_postponed_request_t *pr, **ppr; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -110,16 +109,14 @@ ngx_http_postpone_filter(ngx_http_reques out = in; } - mr = r->main ? r->main : r; - - if (out == NULL && mr->out == NULL && !mr->connection->buffered) { + if (out == NULL && r->main->out == NULL && !r->main->connection->buffered) { return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postpone filter out \"%V\"", &r->uri); - rc = ngx_http_next_filter(mr, out); + rc = ngx_http_next_filter(r->main, out); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -423,6 +423,8 @@ void ngx_http_init_request(ngx_event_t * c->single_connection = 1; r->connection = c; + r->main = r; + r->start_time = ngx_time(); r->headers_in.content_length_n = -1; @@ -1666,8 +1668,7 @@ ngx_http_writer(ngx_http_request_t *r) wev->delayed = 0; if (!wev->ready) { - clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_core_module); + clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); ngx_add_timer(wev, clcf->send_timeout); if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) { @@ -1683,8 +1684,7 @@ ngx_http_writer(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer delayed"); - clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_core_module); + clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) { ngx_http_close_request(r, 0); @@ -1712,8 +1712,7 @@ ngx_http_writer(ngx_http_request_t *r) "http writer output filter: %d, \"%V\"", rc, &r->uri); if (rc == NGX_AGAIN) { - clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_core_module); + clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); if (!wev->ready && !wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } @@ -1809,7 +1808,7 @@ ngx_http_discard_body(ngx_http_request_t ssize_t size; ngx_event_t *rev; - if (r->main) { + if (r->main != r) { return NGX_OK; } 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 @@ -361,11 +361,11 @@ ngx_http_script_copy_var_len_code(ngx_ht value = ngx_http_get_indexed_variable(e->request, code->index); - if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) { - return 0; + if (value && value != NGX_HTTP_VAR_NOT_FOUND) { + return value->text.len; } - return value->text.len; + return 0; } @@ -382,15 +382,14 @@ ngx_http_script_copy_var_code(ngx_http_s if (!e->skip) { value = ngx_http_get_indexed_variable(e->request, code->index); - if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) { - return; - } + if (value && value != NGX_HTTP_VAR_NOT_FOUND) { + e->pos = ngx_cpymem(e->pos, value->text.data, value->text.len); - e->pos = ngx_cpymem(e->pos, value->text.data, value->text.len); - - if (e->log) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http script var: \"%V\"", &e->buf); + if (e->log) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + e->request->connection->log, 0, + "http script var: \"%V\"", &e->buf); + } } } } @@ -879,19 +878,18 @@ ngx_http_script_var_code(ngx_http_script value = ngx_http_get_indexed_variable(e->request, code->index); - if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + if (value && value != NGX_HTTP_VAR_NOT_FOUND) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script var: %ui, \"%V\"", value->value, &value->text); + *e->sp = *value; e->sp++; return; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http script var: %ui, \"%V\"", value->value, &value->text); - - *e->sp = *value; + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; e->sp++; } diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -423,7 +423,7 @@ ngx_http_special_response_handler(ngx_ht cl->buf = b; } - if (r->main == NULL) { + if (r->main == r) { b->last_buf = 1; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -495,7 +495,7 @@ ngx_http_upstream_connect(ngx_http_reque } if (r->request_body) { - if (r->request_body->temp_file && r->main == NULL) { + if (r->request_body->temp_file && r->main == r) { /* * the r->request_body->buf can be reused for one request only, @@ -560,7 +560,7 @@ ngx_http_upstream_reinit(ngx_http_reques /* reinit the subrequest's ngx_output_chain() context */ if (r->request_body) { - if (r->request_body->temp_file && r->main && u->output.buf) { + if (r->request_body->temp_file && r->main != r && u->output.buf) { u->output.free = ngx_alloc_chain_link(r->pool); if (u->output.free == NULL) { @@ -1454,7 +1454,7 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; - if (rc == 0 && r->main == NULL) { + if (rc == 0 && r->main == r) { rc = ngx_http_send_last(r); } diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -229,7 +229,7 @@ ngx_http_get_indexed_variable(ngx_http_r cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - if (cmcf->variables.elts == NULL || cmcf->variables.nelts <= index) { + if (cmcf->variables.nelts <= index) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "unknown variable index: %d", index); return NULL;