static ngx_int_t ngx_http_subs_out_chain_append(ngx_http_request_t *r, ngx_http_subs_ctx_t *ctx, ngx_buf_t *b) { size_t len, capcity; if (b == NULL || ngx_buf_size(b) == 0) { return NGX_OK; } if (ctx->out_buf == NULL) { if (ngx_http_subs_get_chain_buf(r, ctx) != NGX_OK) { return NGX_ERROR; } } while (1) { len = (size_t) ngx_buf_size(b); if (len == 0) { break; } capcity = ctx->out_buf->end - ctx->out_buf->last; if (len <= capcity) { ctx->out_buf->last = ngx_copy(ctx->out_buf->last, b->pos, len); b->pos += len; break; } else { ctx->out_buf->last = ngx_copy(ctx->out_buf->last, b->pos, capcity); } b->pos += capcity; /* get more buffers */ if (ngx_http_subs_get_chain_buf(r, ctx) != NGX_OK) { return NGX_ERROR; } } return NGX_OK; }
static ngx_int_t ngx_http_subs_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_log_t *log; ngx_chain_t *cl, *ll; ngx_http_subs_ctx_t *ctx; ngx_http_subs_loc_conf_t *slcf; ll = NULL; log = r->connection->log; slcf = ngx_http_get_module_loc_conf(r, ngx_http_subs_filter_module); if (slcf == NULL) { return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_subs_filter_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http subs filter \"%V\"", &r->uri); if (in == NULL && ctx->busy == NULL) { return ngx_http_next_body_filter(r, in); } if (ngx_http_subs_body_filter_init_context(r, in) != NGX_OK){ goto failed; } for (cl = ctx->in; cl; cl = cl->next) { if (cl->buf->last_buf || cl->buf->last_in_chain){ ctx->last = 1; } /* TODO: check the flush tag */ rc = ngx_http_subs_body_filter_process_buffer(r, cl->buf); if (rc == NGX_DECLINED) { continue; } else if (rc == NGX_ERROR) { goto failed; } if (cl->next != NULL) { continue; } if (ctx->last) { /* copy line_in to ctx->out. */ if (ngx_buf_size(ctx->line_in) > 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "[subs_filter] Lost last linefeed, output anyway."); if (ngx_http_subs_out_chain_append(r, ctx, ctx->line_in) != NGX_OK) { goto failed; } } if (ctx->out_buf == NULL) { if (ngx_http_subs_get_chain_buf(r, ctx) != NGX_OK) { goto failed; } } ctx->out_buf->sync = 1; ctx->out_buf->last_buf = (r == r->main) ? 1 : 0; ctx->out_buf->last_in_chain = cl->buf->last_in_chain; break; } } /* It doesn't output anything, return */ if ((ctx->last_out == &ctx->out) && (ctx->busy == NULL)) { return NGX_OK; } ngx_http_subs_body_filter_clean_context(r, ctx); return ngx_http_subs_output(r, ctx, in); failed: ngx_http_subs_body_filter_clean_context(r, ctx); ngx_log_error(NGX_LOG_ERR, log, 0, "[subs_filter] ngx_http_subs_body_filter error."); return NGX_ERROR; }