# HG changeset patch # User Maxim Dounin # Date 1328450986 0 # Node ID 2840ff6b97bdc1b6cc76a0cd7ed0e6a1167eae9a # Parent 3a1507f48686535b16913916ce9d6b6af180bac2 Merge of r4375, r4382: SSI changes: *) The "if" command did not work inside the "block" command and produced parsing errors. *) Added regex captures support in the expression of the "if" command. 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 @@ -78,6 +78,8 @@ static ngx_str_t *ngx_http_ssi_get_varia ngx_str_t *name, ngx_uint_t key); 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_regex_match(ngx_http_request_t *r, + ngx_str_t *pattern, ngx_str_t *str); static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); @@ -624,16 +626,6 @@ ngx_http_ssi_body_filter(ngx_http_reques continue; } - if (cmd->conditional - && (ctx->conditional == 0 - || ctx->conditional > cmd->conditional)) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid context of SSI command: \"%V\"", - &ctx->command); - goto ssi_error; - } - if (!ctx->output && !cmd->block) { if (ctx->block) { @@ -709,6 +701,16 @@ ngx_http_ssi_body_filter(ngx_http_reques } } + if (cmd->conditional + && (ctx->conditional == 0 + || ctx->conditional > cmd->conditional)) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid context of SSI command: \"%V\"", + &ctx->command); + goto ssi_error; + } + if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "too many SSI command paramters: \"%V\"", @@ -1531,6 +1533,30 @@ ngx_http_ssi_get_variable(ngx_http_reque ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); +#if (NGX_PCRE) + { + ngx_str_t *value; + + if (key >= '0' && key <= '9') { + i = key - '0'; + + if (i < ctx->ncaptures) { + value = ngx_palloc(r->pool, sizeof(ngx_str_t)); + if (value == NULL) { + return NULL; + } + + i *= 2; + + value->data = ctx->captures_data + ctx->captures[i]; + value->len = ctx->captures[i + 1] - ctx->captures[i]; + + return value; + } + } + } +#endif + if (ctx->variables == NULL) { return NULL; } @@ -1820,6 +1846,115 @@ invalid_variable: static ngx_int_t +ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern, + ngx_str_t *str) +{ +#if (NGX_PCRE) + int rc, *captures; + u_char *p, errstr[NGX_MAX_CONF_ERRSTR]; + size_t size; + ngx_int_t key; + ngx_str_t *vv, name, value; + ngx_uint_t i, n; + ngx_http_ssi_ctx_t *ctx; + ngx_http_ssi_var_t *var; + ngx_regex_compile_t rgc; + + ngx_memzero(&rgc, sizeof(ngx_regex_compile_t)); + + rgc.pattern = *pattern; + rgc.pool = r->pool; + rgc.err.len = NGX_MAX_CONF_ERRSTR; + rgc.err.data = errstr; + + if (ngx_regex_compile(&rgc) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err); + return NGX_HTTP_SSI_ERROR; + } + + n = (rgc.captures + 1) * 3; + + captures = ngx_palloc(r->pool, n * sizeof(int)); + if (captures == NULL) { + return NGX_ERROR; + } + + rc = ngx_regex_exec(rgc.regex, str, captures, n); + + if (rc < NGX_REGEX_NO_MATCHED) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", + rc, str, pattern); + return NGX_HTTP_SSI_ERROR; + } + + if (rc == NGX_REGEX_NO_MATCHED) { + return NGX_DECLINED; + } + + ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); + + ctx->ncaptures = rc; + ctx->captures = captures; + ctx->captures_data = str->data; + + if (rgc.named_captures > 0) { + + if (ctx->variables == NULL) { + ctx->variables = ngx_list_create(r->pool, 4, + sizeof(ngx_http_ssi_var_t)); + if (ctx->variables == NULL) { + return NGX_ERROR; + } + } + + size = rgc.name_size; + p = rgc.names; + + for (i = 0; i < (ngx_uint_t) rgc.named_captures; i++, p += size) { + + name.data = &p[2]; + name.len = ngx_strlen(name.data); + + n = 2 * ((p[0] << 8) + p[1]); + + value.data = &str->data[captures[n]]; + value.len = captures[n + 1] - captures[n]; + + key = ngx_hash_strlow(name.data, name.data, name.len); + + vv = ngx_http_ssi_get_variable(r, &name, key); + + if (vv) { + *vv = value; + continue; + } + + var = ngx_list_push(ctx->variables); + if (var == NULL) { + return NGX_ERROR; + } + + var->name = name; + var->key = key; + var->value = value; + } + } + + return NGX_OK; + +#else + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "the using of the regex \"%V\" in SSI requires PCRE library", + pattern); + return NGX_HTTP_SSI_ERROR; + +#endif +} + + +static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { @@ -2451,39 +2586,17 @@ ngx_http_ssi_if(ngx_http_request_t *r, n } } else { -#if (NGX_PCRE) - ngx_regex_compile_t rgc; - u_char errstr[NGX_MAX_CONF_ERRSTR]; - right.data[right.len] = '\0'; - ngx_memzero(&rgc, sizeof(ngx_regex_compile_t)); - - rgc.pattern = right; - rgc.pool = r->pool; - rgc.err.len = NGX_MAX_CONF_ERRSTR; - rgc.err.data = errstr; - - if (ngx_regex_compile(&rgc) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err); - return NGX_HTTP_SSI_ERROR; + rc = ngx_http_ssi_regex_match(r, &right, &left); + + if (rc == NGX_OK) { + rc = 0; + } else if (rc == NGX_DECLINED) { + rc = -1; + } else { + return rc; } - - rc = ngx_regex_exec(rgc.regex, &left, NULL, 0); - - if (rc < NGX_REGEX_NO_MATCHED) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", - rc, &left, &right); - return NGX_HTTP_SSI_ERROR; - } -#else - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "the using of the regex \"%V\" in SSI " - "requires PCRE library", &right); - - return NGX_HTTP_SSI_ERROR; -#endif } if ((rc == 0 && !negative) || (rc != 0 && negative)) { diff --git a/src/http/modules/ngx_http_ssi_filter_module.h b/src/http/modules/ngx_http_ssi_filter_module.h --- a/src/http/modules/ngx_http_ssi_filter_module.h +++ b/src/http/modules/ngx_http_ssi_filter_module.h @@ -64,6 +64,12 @@ typedef struct { ngx_list_t *variables; ngx_array_t *blocks; +#if (NGX_PCRE) + ngx_uint_t ncaptures; + int *captures; + u_char *captures_data; +#endif + unsigned conditional:2; unsigned encoding:2; unsigned block:1;