summaryrefslogtreecommitdiff
path: root/srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c
diff options
context:
space:
mode:
authorkaiwu <kaiwu2004@gmail.com>2025-03-01 12:42:23 +0800
committerkaiwu <kaiwu2004@gmail.com>2025-03-01 12:42:23 +0800
commit3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch)
tree284c2ba95a41536ae1bff6bea710db0709a64739 /srcache-nginx-module-0.33/src/ngx_http_srcache_fetch.c
downloadopenresty-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.c470
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: */