[nginx] Sub filter: fixed matching after a partial match.

Maxim Dounin mdounin at mdounin.ru
Thu Jul 25 11:58:41 UTC 2013


details:   http://hg.nginx.org/nginx/rev/102d7117ffb8
branches:  
changeset: 5288:102d7117ffb8
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Thu Jul 25 14:54:53 2013 +0400
description:
Sub filter: fixed matching after a partial match.

After a failed partial match we now check if there is another partial
match in previously matched substring to fix cases like "aab" in "aaab".

The ctx->saved string is now always sent if it's present on return
from the ngx_http_sub_parse() function (and reset accordingly).  This
allows to release parts of previously matched data.

diffstat:

 src/http/modules/ngx_http_sub_filter_module.c |  100 +++++++++++++++++--------
 1 files changed, 69 insertions(+), 31 deletions(-)

diffs (157 lines):

diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -261,36 +261,36 @@ ngx_http_sub_body_filter(ngx_http_reques
                 return rc;
             }
 
-            if (ctx->copy_start != ctx->copy_end) {
+            if (ctx->saved.len) {
 
                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                                "saved: \"%V\"", &ctx->saved);
 
-                if (ctx->saved.len) {
+                cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+                if (cl == NULL) {
+                    return NGX_ERROR;
+                }
 
-                    cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
-                    if (cl == NULL) {
-                        return NGX_ERROR;
-                    }
+                b = cl->buf;
 
-                    b = cl->buf;
+                ngx_memzero(b, sizeof(ngx_buf_t));
 
-                    ngx_memzero(b, sizeof(ngx_buf_t));
+                b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
+                if (b->pos == NULL) {
+                    return NGX_ERROR;
+                }
 
-                    b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
-                    if (b->pos == NULL) {
-                        return NGX_ERROR;
-                    }
+                ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
+                b->last = b->pos + ctx->saved.len;
+                b->memory = 1;
 
-                    ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
-                    b->last = b->pos + ctx->saved.len;
-                    b->memory = 1;
+                *ctx->last_out = cl;
+                ctx->last_out = &cl->next;
 
-                    *ctx->last_out = cl;
-                    ctx->last_out = &cl->next;
+                ctx->saved.len = 0;
+            }
 
-                    ctx->saved.len = 0;
-                }
+            if (ctx->copy_start != ctx->copy_end) {
 
                 cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
                 if (cl == NULL) {
@@ -325,6 +325,11 @@ ngx_http_sub_body_filter(ngx_http_reques
                 ctx->copy_end = NULL;
             }
 
+            if (ctx->looked.len > (size_t) (ctx->pos - ctx->buf->pos)) {
+                ctx->saved.len = ctx->looked.len - (ctx->pos - ctx->buf->pos);
+                ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len);
+            }
+
             if (rc == NGX_AGAIN) {
                 continue;
             }
@@ -502,7 +507,7 @@ static ngx_int_t
 ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
 {
     u_char                *p, *last, *copy_end, ch, match;
-    size_t                 looked;
+    size_t                 looked, i;
     ngx_http_sub_state_e   state;
 
     if (ctx->once) {
@@ -573,13 +578,11 @@ ngx_http_sub_parse(ngx_http_request_t *r
             looked++;
 
             if (looked == ctx->match.len) {
-                if ((size_t) (p - ctx->pos) < looked) {
-                    ctx->saved.len = 0;
-                }
 
                 ctx->state = sub_start_state;
                 ctx->pos = p + 1;
                 ctx->looked.len = 0;
+                ctx->saved.len = 0;
                 ctx->copy_end = copy_end;
 
                 if (ctx->copy_start == NULL && copy_end) {
@@ -589,18 +592,53 @@ ngx_http_sub_parse(ngx_http_request_t *r
                 return NGX_OK;
             }
 
-        } else if (ch == ctx->match.data[0]) {
-            copy_end = p;
-            ctx->looked.data[0] = *p;
-            looked = 1;
+        } else {
+            /*
+             * check if there is another partial match in previously
+             * matched substring to catch cases like "aab" in "aaab"
+             */
 
-        } else {
-            copy_end = p;
-            looked = 0;
-            state = sub_start_state;
+            ctx->looked.data[looked] = *p;
+            looked++;
+
+            for (i = 1; i < looked; i++) {
+                if (ngx_strncasecmp(ctx->looked.data + i,
+                                    ctx->match.data, looked - i)
+                    == 0)
+                {
+                    break;
+                }
+            }
+
+            if (i < looked) {
+                if (ctx->saved.len > i) {
+                    ctx->saved.len = i;
+                }
+
+                if ((size_t) (p + 1 - ctx->buf->pos) >= looked - i) {
+                    copy_end = p + 1 - (looked - i);
+                }
+
+                ngx_memmove(ctx->looked.data, ctx->looked.data + i, looked - i);
+                looked = looked - i;
+
+            } else {
+                copy_end = p;
+                looked = 0;
+                state = sub_start_state;
+            }
+
+            if (ctx->saved.len) {
+                p++;
+                goto out;
+            }
         }
     }
 
+    ctx->saved.len = 0;
+
+out:
+
     ctx->state = state;
     ctx->pos = p;
     ctx->looked.len = looked;



More information about the nginx-devel mailing list