comparison src/http/modules/ngx_http_sub_filter_module.c @ 6757:cc327c3caf4a stable-1.10

Sub filter: eliminate unnecessary buffering. Previously, when a buffer was processed by the sub filter, its final bytes could be buffered by the filter even if they don't match any pattern. This happened because the Boyer-Moore algorithm, employed by the sub filter since b9447fc457b4 (1.9.4), matches the last characters of patterns prior to checking other characters. If the last character is out of scope, initial bytes of a potential match are buffered until the last character is available. Now, after receiving a flush or recycled buffer, the filter performs additional checks to reduce the number of buffered bytes. The potential match is checked against the initial parts of all patterns. Non-matching bytes are not buffered. This improves processing of a chunked response from upstream by sending the entire chunks without buffering unless a partial match is found at the end of a chunk.
author Roman Arutyunyan <arut@nginx.com>
date Sat, 02 Jul 2016 15:59:53 +0300
parents 521f5aa6e8fb
children f18c285c2e59
comparison
equal deleted inserted replaced
6756:521f5aa6e8fb 6757:cc327c3caf4a
81 81
82 82
83 static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r, 83 static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r,
84 ngx_http_sub_ctx_t *ctx); 84 ngx_http_sub_ctx_t *ctx);
85 static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, 85 static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r,
86 ngx_http_sub_ctx_t *ctx); 86 ngx_http_sub_ctx_t *ctx, ngx_uint_t flush);
87 static ngx_int_t ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, 87 static ngx_int_t ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start,
88 ngx_str_t *m); 88 ngx_str_t *m);
89 89
90 static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, 90 static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd,
91 void *conf); 91 void *conf);
285 ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 285 ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
286 { 286 {
287 ngx_int_t rc; 287 ngx_int_t rc;
288 ngx_buf_t *b; 288 ngx_buf_t *b;
289 ngx_str_t *sub; 289 ngx_str_t *sub;
290 ngx_uint_t flush, last;
290 ngx_chain_t *cl; 291 ngx_chain_t *cl;
291 ngx_http_sub_ctx_t *ctx; 292 ngx_http_sub_ctx_t *ctx;
292 ngx_http_sub_match_t *match; 293 ngx_http_sub_match_t *match;
293 ngx_http_sub_loc_conf_t *slcf; 294 ngx_http_sub_loc_conf_t *slcf;
294 295
326 } 327 }
327 328
328 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 329 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
329 "http sub filter \"%V\"", &r->uri); 330 "http sub filter \"%V\"", &r->uri);
330 331
332 flush = 0;
333 last = 0;
334
331 while (ctx->in || ctx->buf) { 335 while (ctx->in || ctx->buf) {
332 336
333 if (ctx->buf == NULL) { 337 if (ctx->buf == NULL) {
334 ctx->buf = ctx->in->buf; 338 ctx->buf = ctx->in->buf;
335 ctx->in = ctx->in->next; 339 ctx->in = ctx->in->next;
336 ctx->pos = ctx->buf->pos; 340 ctx->pos = ctx->buf->pos;
337 } 341 }
338 342
343 if (ctx->buf->flush || ctx->buf->recycled) {
344 flush = 1;
345 }
346
347 if (ctx->in == NULL) {
348 last = flush;
349 }
350
339 b = NULL; 351 b = NULL;
340 352
341 while (ctx->pos < ctx->buf->last) { 353 while (ctx->pos < ctx->buf->last) {
342 354
343 rc = ngx_http_sub_parse(r, ctx); 355 rc = ngx_http_sub_parse(r, ctx, last);
344 356
345 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 357 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
346 "parse: %i, looked: \"%V\" %p-%p", 358 "parse: %i, looked: \"%V\" %p-%p",
347 rc, &ctx->looked, ctx->copy_start, ctx->copy_end); 359 rc, &ctx->looked, ctx->copy_start, ctx->copy_end);
348 360
590 return rc; 602 return rc;
591 } 603 }
592 604
593 605
594 static ngx_int_t 606 static ngx_int_t
595 ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) 607 ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx,
608 ngx_uint_t flush)
596 { 609 {
597 u_char *p, c; 610 u_char *p, c;
598 ngx_str_t *m; 611 ngx_str_t *m;
599 ngx_int_t offset, start, next, end, len, rc; 612 ngx_int_t offset, start, next, end, len, rc;
600 ngx_uint_t shift, i, j; 613 ngx_uint_t shift, i, j;
602 ngx_http_sub_tables_t *tables; 615 ngx_http_sub_tables_t *tables;
603 ngx_http_sub_loc_conf_t *slcf; 616 ngx_http_sub_loc_conf_t *slcf;
604 617
605 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); 618 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
606 tables = ctx->tables; 619 tables = ctx->tables;
620 match = ctx->matches->elts;
607 621
608 offset = ctx->offset; 622 offset = ctx->offset;
609 end = ctx->buf->last - ctx->pos; 623 end = ctx->buf->last - ctx->pos;
610 624
611 if (ctx->once) { 625 if (ctx->once) {
628 } 642 }
629 643
630 /* a potential match */ 644 /* a potential match */
631 645
632 start = offset - (ngx_int_t) tables->min_match_len + 1; 646 start = offset - (ngx_int_t) tables->min_match_len + 1;
633 match = ctx->matches->elts;
634 647
635 i = ngx_max(tables->index[c], ctx->index); 648 i = ngx_max(tables->index[c], ctx->index);
636 j = tables->index[c + 1]; 649 j = tables->index[c + 1];
637 650
638 while (i != j) { 651 while (i != j) {
667 i++; 680 i++;
668 } 681 }
669 682
670 offset++; 683 offset++;
671 ctx->index = 0; 684 ctx->index = 0;
685 }
686
687 if (flush) {
688 for ( ;; ) {
689 start = offset - (ngx_int_t) tables->min_match_len + 1;
690
691 if (start >= end) {
692 break;
693 }
694
695 for (i = 0; i < ctx->matches->nelts; i++) {
696 m = &match[i].match;
697
698 if (ngx_http_sub_match(ctx, start, m) == NGX_AGAIN) {
699 goto again;
700 }
701 }
702
703 offset++;
704 }
672 } 705 }
673 706
674 again: 707 again:
675 708
676 ctx->offset = offset; 709 ctx->offset = offset;