static ngx_int_t ngx_http_srcache_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_srcache_ctx_t *ctx, *pr_ctx; ngx_int_t rc; ngx_str_t skip; ngx_chain_t *cl; ngx_http_srcache_loc_conf_t *slcf; size_t len; unsigned last; dd_enter(); if (in == NULL) { return ngx_http_srcache_next_body_filter(r, NULL); } ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module); if (ctx == NULL || ctx->from_cache || ctx->store_skip) { dd("bypass: %.*s", (int) r->uri.len, r->uri.data); return ngx_http_srcache_next_body_filter(r, in); } if (ctx->ignore_body || ctx->in_store_subrequest/* || ctx->fetch_error */) { dd("ignore body: ignore body %d, in store sr %d", (int) ctx->ignore_body, (int) ctx->in_store_subrequest); ngx_http_srcache_discard_bufs(r->pool, in); return NGX_OK; } if (ctx->in_fetch_subrequest) { if (ctx->parsing_cached_headers) { /* parse the cached response's headers and * set r->parent->headers_out */ if (ctx->process_header == NULL) { dd("restore parent request header"); ctx->process_header = ngx_http_srcache_process_status_line; r->state = 0; /* sw_start */ } for (cl = in; cl; cl = cl->next) { if (ngx_buf_in_memory(cl->buf)) { dd("old pos %p, last %p", cl->buf->pos, cl->buf->last); rc = ctx->process_header(r, cl->buf); if (rc == NGX_AGAIN) { dd("AGAIN/OK: new pos %p, last %p", cl->buf->pos, cl->buf->last); continue; } if (rc == NGX_ERROR) { r->state = 0; /* sw_start */ ctx->parsing_cached_headers = 0; ctx->ignore_body = 1; ngx_http_srcache_discard_bufs(r->pool, cl); pr_ctx = ngx_http_get_module_ctx(r->parent, ngx_http_srcache_filter_module); if (pr_ctx == NULL) { return NGX_ERROR; } pr_ctx->from_cache = 0; return NGX_OK; } /* rc == NGX_OK */ dd("OK: new pos %p, last %p", cl->buf->pos, cl->buf->last); dd("buf left: %.*s", (int) (cl->buf->last - cl->buf->pos), cl->buf->pos); ctx->parsing_cached_headers = 0; break; } } if (cl == NULL) { return NGX_OK; } if (cl->buf->pos == cl->buf->last) { cl = cl->next; } if (cl == NULL) { return NGX_OK; } in = cl; } dd("save the cached response body for parent"); pr_ctx = ngx_http_get_module_ctx(r->parent, ngx_http_srcache_filter_module); if (pr_ctx == NULL) { return NGX_ERROR; } rc = ngx_http_srcache_add_copy_chain(r->pool, &pr_ctx->body_from_cache, in, &last); if (rc != NGX_OK) { return NGX_ERROR; } if (last) { ctx->seen_subreq_eof = 1; } ngx_http_srcache_discard_bufs(r->pool, in); return NGX_OK; } if (ctx->store_response) { dd("storing the response: %p", in); if (ctx->response_length == 0) { /* store the response header to ctx->body_to_cache */ if (ngx_http_srcache_store_response_header(r, ctx) == NGX_ERROR) { return NGX_ERROR; } if (ngx_http_srcache_next_header_filter(r) == NGX_ERROR) { return NGX_ERROR; } } for (cl = in; cl; cl = cl->next) { if (ngx_buf_in_memory(cl->buf)) { len = ngx_buf_size(cl->buf); ctx->response_length += len; ctx->response_body_length += len; } } slcf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); if (slcf->store_max_size != 0 && ctx->response_length > slcf->store_max_size) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "srcache_store bypassed because response body " "exceeded maximum size: %z (limit is: %z)", ctx->response_length, slcf->store_max_size); ctx->store_response = 0; goto done; } rc = ngx_http_srcache_add_copy_chain(r->pool, &ctx->body_to_cache, in, &last); if (rc != NGX_OK) { ctx->store_response = 0; goto done; } if (last && r == r->main) { #if 1 if (r->headers_out.content_length_n > (off_t) ctx->response_body_length) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_store: skipped because response body " "truncated: %O > %uz", r->headers_out.content_length_n, ctx->response_body_length); ctx->store_response = 0; goto done; } if (r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE && r->headers_out.status != ctx->http_status) { /* data truncation or body receive timeout */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_store: skipped due to new error status " "code %ui (old: %ui)", r->headers_out.status, ctx->http_status); ctx->store_response = 0; goto done; } #endif if (slcf->store_skip != NULL && ngx_http_complex_value(r, slcf->store_skip, &skip) == NGX_OK && skip.len && (skip.len != 1 || skip.data[0] != '0')) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "srcache_store skipped due to the true value in " "srcache_store_skip: \"%V\"", &skip); ctx->store_response = 0; goto done; } rc = ngx_http_srcache_store_subrequest(r, ctx); if (rc != NGX_OK) { ctx->store_response = 0; goto done; } } } else { dd("NO store response"); } done: return ngx_http_srcache_next_body_filter(r, in); }
static ngx_int_t ngx_http_srcache_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_srcache_ctx_t *ctx, *pr_ctx; ngx_int_t rc; ngx_chain_t *cl; ngx_flag_t last; ngx_http_srcache_loc_conf_t *slcf; dd_enter(); if (in == NULL) { return ngx_http_srcache_next_body_filter(r, NULL); } ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module); if (ctx == NULL || ctx->from_cache || ctx->store_skip) { dd("bypass: %.*s", (int) r->uri.len, r->uri.data); return ngx_http_srcache_next_body_filter(r, in); } if (ctx->ignore_body || ctx->in_store_subrequest/* || ctx->fetch_error */) { dd("ignore body: ignore body %d, in store sr %d", (int) ctx->ignore_body, (int) ctx->in_store_subrequest); ngx_http_srcache_discard_bufs(r->pool, in); return NGX_OK; } if (ctx->in_fetch_subrequest) { if (ctx->parsing_cached_headers) { /* parse the cached response's headers and * set r->parent->headers_out */ if (ctx->process_header == NULL) { dd("restore parent request header"); ctx->process_header = ngx_http_srcache_process_status_line; r->state = 0; /* sw_start */ } for (cl = in; cl; cl = cl->next) { if (ngx_buf_in_memory(cl->buf)) { dd("old pos %p, last %p", cl->buf->pos, cl->buf->last); rc = ctx->process_header(r, cl->buf); if (rc == NGX_AGAIN) { dd("AGAIN/OK: new pos %p, last %p", cl->buf->pos, cl->buf->last); continue; } if (rc == NGX_ERROR) { r->state = 0; /* sw_start */ ctx->parsing_cached_headers = 0; ctx->ignore_body = 1; ngx_http_srcache_discard_bufs(r->pool, cl); pr_ctx = ngx_http_get_module_ctx(r->parent, ngx_http_srcache_filter_module); if (pr_ctx == NULL) { return NGX_ERROR; } pr_ctx->from_cache = 0; return NGX_OK; } /* rc == NGX_OK */ dd("OK: new pos %p, last %p", cl->buf->pos, cl->buf->last); dd("buf left: %.*s", (int) (cl->buf->last - cl->buf->pos), cl->buf->pos); ctx->parsing_cached_headers = 0; break; } } if (cl == NULL) { return NGX_OK; } if (cl->buf->pos == cl->buf->last) { cl = cl->next; } if (cl == NULL) { return NGX_OK; } in = cl; } dd("save the cached response body for parent"); pr_ctx = ngx_http_get_module_ctx(r->parent, ngx_http_srcache_filter_module); if (pr_ctx == NULL) { return NGX_ERROR; } rc = ngx_http_srcache_add_copy_chain(r->pool, &pr_ctx->body_from_cache, in); if (rc != NGX_OK) { return NGX_ERROR; } ngx_http_srcache_discard_bufs(r->pool, in); return NGX_OK; } if (ctx->store_response) { dd("storing the response: %p", in); if (ctx->response_length == 0) { /* store the response header to ctx->body_to_cache */ rc = ngx_http_srcache_store_response_header(r, ctx); if (rc == NGX_ERROR) { return NGX_ERROR; } } last = 0; for (cl = in; cl; cl = cl->next) { if (ngx_buf_in_memory(cl->buf)) { ctx->response_length += ngx_buf_size(cl->buf); } if (cl->buf->last_buf) { last = 1; break; } } slcf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); if (slcf->store_max_size != 0 && ctx->response_length > slcf->store_max_size) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "srcache_store bypassed because response body exceeded " "maximum size: %z (limit is: %z)", ctx->response_length, slcf->store_max_size); ctx->store_response = 0; goto done; } rc = ngx_http_srcache_add_copy_chain(r->pool, &ctx->body_to_cache, in); if (rc != NGX_OK) { ctx->store_response = 0; goto done; } if (last && r == r->main) { rc = ngx_http_srcache_store_subrequest(r, ctx); if (rc != NGX_OK) { ctx->store_response = 0; goto done; } } } else { dd("NO store response"); } done: return ngx_http_srcache_next_body_filter(r, in); }