diff options
author | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
---|---|---|
committer | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
commit | 3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch) | |
tree | 284c2ba95a41536ae1bff6bea710db0709a64739 /srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c | |
download | openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.tar.gz openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.zip |
openresty bundle
Diffstat (limited to 'srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c')
-rw-r--r-- | srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c b/srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c new file mode 100644 index 0000000..9d3e649 --- /dev/null +++ b/srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c @@ -0,0 +1,470 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_srcache_fetch.h" +#include "ngx_http_srcache_store.h" +#include "ngx_http_srcache_util.h" +#include <nginx.h> + + +static ngx_int_t ngx_http_srcache_fetch_subrequest(ngx_http_request_t *r, + ngx_http_srcache_loc_conf_t *conf, ngx_http_srcache_ctx_t *ctx); +static void ngx_http_srcache_post_read_body(ngx_http_request_t *r); + + +ngx_int_t +ngx_http_srcache_access_handler(ngx_http_request_t *r) +{ + ngx_str_t skip; + ngx_int_t rc; + ngx_http_srcache_loc_conf_t *conf; + ngx_http_srcache_main_conf_t *smcf; + ngx_http_srcache_ctx_t *ctx; + ngx_chain_t *cl; + size_t len; + unsigned no_store; + + /* access phase handlers are skipped in subrequests, + * so the current request must be a main request */ + + conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); + + if (conf->fetch == NULL && conf->store == NULL) { + dd("bypass: %.*s", (int) r->uri.len, r->uri.data); + return NGX_DECLINED; + } + + dd("store defined? %p", conf->store); + + dd("req method: %lu", (unsigned long) r->method); + dd("cache methods: %lu", (unsigned long) conf->cache_methods); + + if (!(r->method & conf->cache_methods)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "srcache_fetch and srcache_store skipped due to request " + "method %V", &r->method_name); + + return NGX_DECLINED; + } + + if (conf->req_cache_control + && ngx_http_srcache_request_no_cache(r, &no_store) == NGX_OK) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "srcache_fetch skipped due to request headers " + "\"Cache-Control: no-cache\" or \"Pragma: no-cache\""); + + if (!no_store) { + /* register a ctx to give a chance to srcache_store to run */ + + ctx = ngx_pcalloc(r->pool, + sizeof(ngx_http_srcache_filter_module)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module); + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "srcache_store skipped due to request header " + "\"Cache-Control: no-store\""); + } + + return NGX_DECLINED; + } + + if (conf->fetch_skip != NULL + && ngx_http_complex_value(r, conf->fetch_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_fetch skipped due to the true value fed into " + "srcache_fetch_skip: \"%V\"", &skip); + + /* register a ctx to give a chance to srcache_store to run */ + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_filter_module)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module); + + return NGX_DECLINED; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module); + + if (ctx != NULL) { + /* + if (ctx->fetch_error) { + return NGX_DECLINED; + } + */ + + if (ctx->waiting_subrequest) { + dd("waiting subrequest"); + return NGX_AGAIN; + } + + if (ctx->waiting_request_body) { + return NGX_AGAIN; + } + + if (ctx->request_body_done == 1) { + ctx->request_body_done = 0; + goto do_fetch_subrequest; + } + + if (ctx->request_done) { + dd("request done"); + + if (ngx_http_post_request(r, NULL) != NGX_OK) { + return NGX_ERROR; + } + + if (!ctx->from_cache) { + return NGX_DECLINED; + } + + dd("sending header"); + + if (ctx->body_from_cache) { + len = 0; + + for (cl = ctx->body_from_cache; cl->next; cl = cl->next) { + len += ngx_buf_size(cl->buf); + } + + len += ngx_buf_size(cl->buf); + + cl->buf->last_buf = 1; + + r->headers_out.content_length_n = len; + + rc = ngx_http_send_header(r); + + dd("srcache fetch header returned %d", (int) rc); + + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + +#if 1 + if (r->header_only) { + return NGX_HTTP_OK; + } +#endif + + if (!r->filter_finalize) { + rc = ngx_http_output_filter(r, ctx->body_from_cache); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + dd("sent body from cache: %d", (int) rc); + dd("finalize from here..."); + + ngx_http_finalize_request(r, rc); + + /* dd("r->main->count (post): %d", (int) r->main->count); */ + return NGX_DONE; + } + + return NGX_DECLINED; + } + + } else { + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_filter_module)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module); + } + + smcf = ngx_http_get_module_main_conf(r, ngx_http_srcache_filter_module); + + if (!smcf->postponed_to_access_phase_end) { + ngx_http_core_main_conf_t *cmcf; + ngx_http_phase_handler_t tmp; + ngx_http_phase_handler_t *ph; + ngx_http_phase_handler_t *cur_ph; + ngx_http_phase_handler_t *last_ph; + + smcf->postponed_to_access_phase_end = 1; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + ph = cmcf->phase_engine.handlers; + cur_ph = &ph[r->phase_handler]; + + /* we should skip the post_access phase handler here too */ + last_ph = &ph[cur_ph->next - 2]; + + if (cur_ph < last_ph) { + dd("swaping the contents of cur_ph and last_ph..."); + + tmp = *cur_ph; + + memmove(cur_ph, cur_ph + 1, + (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); + + *last_ph = tmp; + + r->phase_handler--; /* redo the current ph */ + + return NGX_DECLINED; + } + } + + if (conf->fetch == NULL) { + dd("fetch is not defined"); + return NGX_DECLINED; + } + + dd("running phase handler..."); + + if (!r->request_body) { + dd("reading request body: ctx = %p", ctx); + + rc = ngx_http_read_client_request_body(r, + ngx_http_srcache_post_read_body); + if (rc == NGX_ERROR || rc > NGX_OK) { +#if (nginx_version < 1002006) \ + || (nginx_version >= 1003000 && nginx_version < 1003009) + r->main->count--; +#endif + return rc; + } + + if (rc == NGX_AGAIN) { + ctx->waiting_request_body = 1; + return NGX_AGAIN; + } + + /* rc == NGX_OK */ + } + +do_fetch_subrequest: + + /* issue a subrequest to fetch cached stuff (if any) */ + + rc = ngx_http_srcache_fetch_subrequest(r, conf, ctx); + + if (rc != NGX_OK) { + return rc; + } + + ctx->waiting_subrequest = 1; + + dd("quit"); + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_srcache_fetch_post_subrequest(ngx_http_request_t *r, void *data, + ngx_int_t rc) +{ + ngx_http_srcache_ctx_t *ctx = data; + ngx_http_srcache_ctx_t *pr_ctx; + ngx_http_request_t *pr; + + dd_enter(); + + if (r != r->connection->data) { + dd("waited: %d, rc: %d", (int) r->waited, (int) rc); + } + + pr = r->parent; + + pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_srcache_filter_module); + if (pr_ctx == NULL) { + return NGX_ERROR; + } + + if (ctx == NULL) { + return NGX_OK; + } + + if (ctx->parsing_cached_headers) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "srcache_fetch: cache sent truncated status line " + "or headers"); + + pr_ctx->from_cache = 0; + + } else if (r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE + || rc == NGX_ERROR + || rc >= NGX_HTTP_SPECIAL_RESPONSE) + { + dd("HERE"); + pr_ctx->from_cache = 0; + + } else if (!ctx->seen_subreq_eof) { + +#if 1 + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "srcache_fetch: cache sent truncated " + "response body"); + + pr_ctx->from_cache = 0; +#endif + } + + pr_ctx->waiting_subrequest = 0; + pr_ctx->request_done = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_srcache_fetch_subrequest(ngx_http_request_t *r, + ngx_http_srcache_loc_conf_t *conf, ngx_http_srcache_ctx_t *ctx) +{ + ngx_http_srcache_ctx_t *sr_ctx; + ngx_http_post_subrequest_t *psr; + ngx_str_t args; + ngx_uint_t flags = 0; + ngx_http_request_t *sr; + ngx_int_t rc; + + ngx_http_srcache_parsed_request_t *parsed_sr; + + dd_enter(); + + parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t)); + if (parsed_sr == NULL) { + return NGX_ERROR; + } + + if (conf->fetch == NULL) { + return NGX_ERROR; + } + + parsed_sr->method = conf->fetch->method; + parsed_sr->method_name = conf->fetch->method_name; + + parsed_sr->request_body = NULL; + parsed_sr->content_length_n = -1; + + if (ngx_http_complex_value(r, &conf->fetch->location, + &parsed_sr->location) != NGX_OK) + { + return NGX_ERROR; + } + + if (parsed_sr->location.len == 0) { + return NGX_ERROR; + } + + if (ngx_http_complex_value(r, &conf->fetch->args, &parsed_sr->args) + != NGX_OK) + { + return NGX_ERROR; + } + + args.data = NULL; + args.len = 0; + + if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags) + != NGX_OK) + { + return NGX_ERROR; + } + + if (args.len > 0 && parsed_sr->args.len == 0) { + parsed_sr->args = args; + } + + sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t)); + if (sr_ctx == NULL) { + return NGX_ERROR; + } + + sr_ctx->in_fetch_subrequest = 1; + + psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); + if (psr == NULL) { + return NGX_ERROR; + } + + psr->handler = ngx_http_srcache_fetch_post_subrequest; + psr->data = sr_ctx; + + dd("firing the fetch subrequest"); + + dd("fetch location: %.*s", (int) parsed_sr->location.len, + parsed_sr->location.data); + + dd("fetch args: %.*s", (int) parsed_sr->args.len, + parsed_sr->args.data); + + rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args, + &sr, psr, flags); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module); + + ctx->issued_fetch_subrequest = 1; + + return NGX_OK; +} + + +static void +ngx_http_srcache_post_read_body(ngx_http_request_t *r) +{ + ngx_http_srcache_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module); + + dd("post read: ctx=%p", ctx); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "srcache post read for the access phase: wait:%ud c:%ud", + (unsigned) ctx->waiting_request_body, r->main->count); + + r->write_event_handler = ngx_http_core_run_phases; + +#if defined(nginx_version) && nginx_version >= 8011 + r->main->count--; +#endif + + dd("c:%u", r->main->count); + + if (ctx->waiting_request_body) { + ctx->request_body_done = 1; + ctx->waiting_request_body = 0; + ngx_http_core_run_phases(r); + } +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ |