changeset 4438:2840ff6b97bd stable-1.0

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.
author Maxim Dounin <mdounin@mdounin.ru>
date Sun, 05 Feb 2012 14:09:46 +0000
parents 3a1507f48686
children 5c97978d2717
files src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssi_filter_module.h
diffstat 2 files changed, 159 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- 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)) {
--- 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;