# HG changeset patch # User Maxim Dounin # Date 1374749693 -14400 # Node ID 102d7117ffb8a73320a44986b89b2a141316470a # Parent 2dbc5e38b65d27110f4efd6cdf5a4ce4ac6cdd54 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. 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" + */ + + 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; + } + } - } else { - copy_end = p; - looked = 0; - state = sub_start_state; + 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;