[nginx] Upstream: $upstream_cache_age variable.

Maxim Dounin mdounin at mdounin.ru
Thu Jul 18 20:44:00 UTC 2024


details:   http://freenginx.org/hg/nginx/rev/e46e1ea89ccd
branches:  
changeset: 9306:e46e1ea89ccd
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Thu Jul 18 19:39:45 2024 +0300
description:
Upstream: $upstream_cache_age variable.

The variable reflects response age, including the time spent in the
cache and the upstream response age as obtained from the "Age" header.
If the response wasn't cached, the variable reflects the "Age" header
of the upstream response.

If the intended use case is to cache responses as per HTTP/1.1 caching
model, the $upstream_cache_age variable can be used to provide the "Age"
header with the "add_header" directive, such as:

    add_header Age $upstream_cache_age;

This now removes the "Age" header if it was present.

Further, the "expires" directives now removes the "Age" header if it
was present in the response, as the "expires" directive assumes zero
age when it adds "Expires" and "Cache-Control" headers.

diffstat:

 src/http/modules/ngx_http_headers_filter_module.c |   9 +++
 src/http/ngx_http_request.h                       |   1 +
 src/http/ngx_http_upstream.c                      |  63 ++++++++++++++++++++++-
 3 files changed, 72 insertions(+), 1 deletions(-)

diffs (131 lines):

diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -93,6 +93,10 @@ static ngx_http_set_header_t  ngx_http_s
                  offsetof(ngx_http_headers_out_t, etag),
                  ngx_http_set_response_header },
 
+    { ngx_string("Age"),
+                 offsetof(ngx_http_headers_out_t, age),
+                 ngx_http_set_response_header },
+
     { ngx_null_string, 0, NULL }
 };
 
@@ -352,6 +356,11 @@ ngx_http_set_expires(ngx_http_request_t 
         }
     }
 
+    if (r->headers_out.age) {
+        r->headers_out.age->hash = 0;
+        r->headers_out.age = NULL;
+    }
+
     e = r->headers_out.expires;
 
     if (e == NULL) {
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -278,6 +278,7 @@ typedef struct {
 
     ngx_table_elt_t                  *cache_control;
     ngx_table_elt_t                  *link;
+    ngx_table_elt_t                  *age;
 
     ngx_str_t                        *override_charset;
 
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -31,6 +31,8 @@ static ngx_int_t ngx_http_upstream_cache
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_upstream_cache_etag(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_upstream_cache_age(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 #endif
 
 static void ngx_http_upstream_init_request(ngx_http_request_t *r);
@@ -297,7 +299,8 @@ static ngx_http_upstream_header_t  ngx_h
 
     { ngx_string("Age"),
                  ngx_http_upstream_process_age, 0,
-                 ngx_http_upstream_copy_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line,
+                 offsetof(ngx_http_headers_out_t, age), 0 },
 
     { ngx_string("X-Accel-Expires"),
                  ngx_http_upstream_process_accel_expires, 0,
@@ -436,6 +439,10 @@ static ngx_http_variable_t  ngx_http_ups
       ngx_http_upstream_cache_etag, 0,
       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
+    { ngx_string("upstream_cache_age"), NULL,
+      ngx_http_upstream_cache_age, 0,
+      NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
 #endif
 
     { ngx_string("upstream_http_"), NULL, ngx_http_upstream_header_variable,
@@ -6211,6 +6218,60 @@ ngx_http_upstream_cache_etag(ngx_http_re
     return NGX_OK;
 }
 
+
+static ngx_int_t
+ngx_http_upstream_cache_age(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_char  *p;
+    time_t   now, age;
+
+    if (r->upstream == NULL) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    if (!r->cached
+        || r->cache == NULL
+        || r->upstream->cache_status == NGX_HTTP_CACHE_REVALIDATED)
+    {
+        if (r->upstream->headers_in.age == NULL) {
+            v->not_found = 1;
+            return NGX_OK;
+        }
+
+        v->valid = 1;
+        v->no_cacheable = 0;
+        v->not_found = 0;
+        v->len = r->upstream->headers_in.age->value.len;
+        v->data = r->upstream->headers_in.age->value.data;
+
+        return NGX_OK;
+    }
+
+    p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    now = ngx_time();
+    age = now - r->cache->date;
+
+    if (r->cache->date > now) {
+        age = 0;
+    }
+
+    age += r->upstream->headers_in.age_n;
+
+    v->len = ngx_sprintf(p, "%T", age) - p;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = p;
+
+    return NGX_OK;
+}
+
 #endif
 
 


More information about the nginx-devel mailing list