# HG changeset patch # User Maxim Dounin # Date 1413399443 -14400 # Node ID 973fded4f461f3a397779b3a1dc80881b1b34974 # Parent d91b98232e4c1b6a9a37c957d713269089fcce60 Gzip, gunzip: flush busy buffers if any. Previous code resulted in transfer stalls when client happened to read all the data in buffers at once, while all gzip buffers were exhausted (but ctx->nomem wasn't set). Make sure to call next body filter at least once per call if there are busy buffers. Additionally, handling of calls with NULL chain was changed to follow the same logic, i.e., next body filter is only called with NULL chain if there are busy buffers. This is expected to fix "output chain is empty" alerts as reported by some users after c52a761a2029 (1.5.7). diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c --- a/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -175,6 +175,7 @@ static ngx_int_t ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; + ngx_uint_t flush; ngx_chain_t *cl; ngx_http_gunzip_ctx_t *ctx; @@ -199,7 +200,7 @@ ngx_http_gunzip_body_filter(ngx_http_req } } - if (ctx->nomem || in == NULL) { + if (ctx->nomem) { /* flush busy buffers */ @@ -212,6 +213,10 @@ ngx_http_gunzip_body_filter(ngx_http_req ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); ctx->nomem = 0; + flush = 0; + + } else { + flush = ctx->busy ? 1 : 0; } for ( ;; ) { @@ -258,7 +263,7 @@ ngx_http_gunzip_body_filter(ngx_http_req /* rc == NGX_AGAIN */ } - if (ctx->out == NULL) { + if (ctx->out == NULL && !flush) { return ctx->busy ? NGX_AGAIN : NGX_OK; } @@ -276,6 +281,7 @@ ngx_http_gunzip_body_filter(ngx_http_req "gunzip out: %p", ctx->out); ctx->nomem = 0; + flush = 0; if (ctx->done) { return rc; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -316,6 +316,7 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; + ngx_uint_t flush; ngx_chain_t *cl; ngx_http_gzip_ctx_t *ctx; @@ -372,7 +373,7 @@ ngx_http_gzip_body_filter(ngx_http_reque r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; } - if (ctx->nomem || in == NULL) { + if (ctx->nomem) { /* flush busy buffers */ @@ -385,6 +386,10 @@ ngx_http_gzip_body_filter(ngx_http_reque ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, (ngx_buf_tag_t) &ngx_http_gzip_filter_module); ctx->nomem = 0; + flush = 0; + + } else { + flush = ctx->busy ? 1 : 0; } for ( ;; ) { @@ -432,7 +437,7 @@ ngx_http_gzip_body_filter(ngx_http_reque /* rc == NGX_AGAIN */ } - if (ctx->out == NULL) { + if (ctx->out == NULL && !flush) { ngx_http_gzip_filter_free_copy_buf(r, ctx); return ctx->busy ? NGX_AGAIN : NGX_OK; @@ -457,6 +462,7 @@ ngx_http_gzip_body_filter(ngx_http_reque ctx->last_out = &ctx->out; ctx->nomem = 0; + flush = 0; if (ctx->done) { return rc;