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.
This commit is contained in:
Maxim Dounin 2012-02-05 14:09:46 +00:00
parent f6ee2be6a0
commit b48566c574
2 changed files with 158 additions and 39 deletions

View File

@ -78,6 +78,8 @@ static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r,
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_request_t *r, ngx_chain_t *in)
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_request_t *r, ngx_chain_t *in)
}
}
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_request_t *r, ngx_str_t *name,
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;
}
@ -1819,6 +1845,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, ngx_http_ssi_ctx_t *ctx,
}
} 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));
rc = ngx_http_ssi_regex_match(r, &right, &left);
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;
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)) {

View File

@ -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;