[PATCH] HTTP: Add the $upstream_cache_age variable, allowing better HTTP/1.1 compliance

Damien Tournoud damien at platform.sh
Mon Jun 8 23:08:30 UTC 2015


# HG changeset patch
# User Damien Tournoud <damien at platform.sh>
# Date 1433803821 -7200
#      Tue Jun 09 00:50:21 2015 +0200
# Node ID 04fab8a5fbac9a350c7552ac81569a5deb641240
# Parent  1729d8d3eb3acbb79b1b0c1d60b411aacc4f8461
HTTP: Add the $upstream_cache_age variable, allowing better HTTP/1.1 compliance.

Nginx, when used as a proxy cache, doesn't have any practical
ways to issue a `Age:` header, signaling to downstream clients
the age of objects that it serves from the cache.

This patch adds a $upstream_cache_age variable, that can be
used to issue such a header like:

    add_header Age "$upstream_cache_age";

The header is based on `r->cache->date`, so it gets reset with
revalidations, which I think is a reasonable behavior.

In other to make the variable useful, I had to where it is set
in `ngx_http_upstream_send_response()` (in the MISS path),
so that it is set before sending the headers.

diff -r 1729d8d3eb3a -r 04fab8a5fbac src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c	Mon Jun 08 23:13:56 2015 +0300
+++ b/src/http/ngx_http_upstream.c	Tue Jun 09 00:50:21 2015 +0200
@@ -23,6 +23,8 @@
     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);
@@ -393,6 +395,10 @@
       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_null_string, NULL, NULL, 0, 0, 0 }
@@ -2647,6 +2653,15 @@
     ngx_connection_t          *c;
     ngx_http_core_loc_conf_t  *clcf;
 
+#if (NGX_HTTP_CACHE)
+    time_t  now;
+    now = ngx_time();
+
+    if (r->cache) {
+        r->cache->date = now;
+    }
+#endif
+
     rc = ngx_http_send_header(r);
 
     if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
@@ -2787,9 +2802,7 @@
     }
 
     if (u->cacheable) {
-        time_t  now, valid;
-
-        now = ngx_time();
+        time_t  valid;
 
         valid = r->cache->valid_sec;
 
@@ -2802,7 +2815,6 @@
         }
 
         if (valid) {
-            r->cache->date = now;
             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
 
             if (u->headers_in.status_n == NGX_HTTP_OK
@@ -5248,6 +5260,39 @@
     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;
+
+    now = ngx_time();
+
+    if (r->upstream == NULL
+        || r->upstream->cacheable == 0
+        || r->cache->date > now)
+    {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = ngx_sprintf(p, "%T", now - r->cache->date) - 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