[Patch] proxy cache for 304 Not Modified

ビリビリⅤ orz at loli.my
Thu Sep 15 17:54:04 UTC 2011


Hello guys,
I have wrote a module to make nginx support 304 to decrease bandwidth usage.
note: I have a newbie for nginx module development, so the above module may
have some problem. Welcome to test it and feedback another problem with me.
Note:
I cannot found where can using nginx internal cache update without delete
the old cache, so I using reopen the cache file to write a new expire
header. Can anyone help me to fix this problem?

You can download full patch file from here:
http://m-b.cc/share/proxy_304.txt

# User MagicBear <magicbearmo at gmail.com>
Upstream:
add $upstream_last_modified variant.
add handler for 304 Unmodified.
Proxy:
change to send If-Modified-Since header.

diff -ruN a/http/modules/ngx_http_proxy_module.c
b/http/modules/ngx_http_proxy_module.c
--- a/http/modules/ngx_http_proxy_module.c      2011-09-15
22:23:03.284431407 +0800
+++ b/http/modules/ngx_http_proxy_module.c      2011-09-16
01:41:44.654428632 +0800
@@ -543,7 +543,7 @@
     { ngx_string("Connection"), ngx_string("close") },
     { ngx_string("Keep-Alive"), ngx_string("") },
     { ngx_string("Expect"), ngx_string("") },
-    { ngx_string("If-Modified-Since"), ngx_string("") },
+    { ngx_string("If-Modified-Since"),
ngx_string("$upstream_last_modified") },
     { ngx_string("If-Unmodified-Since"), ngx_string("") },
     { ngx_string("If-None-Match"), ngx_string("") },
     { ngx_string("If-Match"), ngx_string("") },
diff -ruN a/http/ngx_http_upstream.c b/http/ngx_http_upstream.c
--- a/http/ngx_http_upstream.c  2011-09-15 22:23:03.284431407 +0800
+++ b/http/ngx_http_upstream.c  2011-09-16 01:41:44.654428632 +0800
@@ -16,6 +16,8 @@
     ngx_http_upstream_t *u);
 static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_upstream_last_modified(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);
@@ -342,6 +344,10 @@
       ngx_http_upstream_cache_status, 0,
       NGX_HTTP_VAR_NOCACHEABLE, 0 },

+    { ngx_string("upstream_last_modified"), NULL,
+      ngx_http_upstream_last_modified, 0,
+      NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
 #endif

     { ngx_null_string, NULL, NULL, 0, 0, 0 }
@@ -1618,6 +1624,80 @@
             u->buffer.last = u->buffer.pos;
         }

+#if (NGX_HTTP_CACHE)
+
+        if (u->cache_status == NGX_HTTP_CACHE_EXPIRED &&
+                       u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED &&
+                       ngx_http_file_cache_valid(u->conf->cache_valid,
u->headers_in.status_n))
+        {
+            ngx_int_t  rc;
+
+            rc = u->reinit_request(r);
+
+            if (rc == NGX_OK) {
+                u->cache_status = NGX_HTTP_CACHE_BYPASS;
+                rc = ngx_http_upstream_cache_send(r, u);
+
+                               time_t  now, valid;
+
+                               now = ngx_time();
+
+                               valid = r->cache->valid_sec;
+
+                               if (valid == 0) {
+                                       valid =
ngx_http_file_cache_valid(u->conf->cache_valid,
+
                              u->headers_in.status_n);
+                                       if (valid) {
+                                               r->cache->valid_sec = now +
valid;
+                                       }
+                               }
+
+                               if (valid) {
+                                       r->cache->last_modified =
r->headers_out.last_modified_time;
+                                       r->cache->date = now;
+                                       r->cache->body_start = (u_short)
(u->buffer.pos - u->buffer.start);
+
+                                       // update Header
+                                       ngx_http_file_cache_set_header(r,
u->buffer.start);
+
+                                       ngx_log_debug1(NGX_LOG_DEBUG_HTTP,
r->connection->log, 0,
+
 "update cache \"%s\" header to new expired." , r->cache->file.name.data);
+
+                                       // Reopen file via RW
+                                       ngx_fd_t fd =
ngx_open_file(r->cache->file.name.data, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
+
+                                       if (fd == NGX_INVALID_FILE) {
+                                               ngx_log_error(NGX_LOG_CRIT,
r->connection->log, ngx_errno,
+
ngx_open_file_n " \"%s\" failed", r->cache->file.name.data);
+                                               return;
+                                       }
+
+                                       // Write cache
+                                       if (write(fd, u->buffer.start,
sizeof(ngx_http_file_cache_header_t)) < 0)
+                                       {
+                                               ngx_log_error(NGX_LOG_CRIT,
r->connection->log, ngx_errno,
+
"write proxy_cache \"%s\" failed", r->cache->file.name.data);
+                                               return;
+                                       }
+
+                                       if (ngx_close_file(fd) ==
NGX_FILE_ERROR) {
+                                               ngx_log_error(NGX_LOG_ALERT,
r->connection->log, ngx_errno,
+
ngx_close_file_n " \"%s\" failed", r->cache->file.name.data);
+                                       }
+                                       ngx_log_debug1(NGX_LOG_DEBUG_HTTP,
r->connection->log, 0,
+
 "update cache \"%s\" header to new expired done." ,
r->cache->file.name.data);
+                               } else {
+                                       u->cacheable = 0;
+                                       r->headers_out.last_modified_time =
-1;
+                               }
+            }
+
+            ngx_http_upstream_finalize_request(r, u, rc);
+            return;
+        }
+
+#endif
+
         if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
             return;
         }
@@ -4006,6 +4086,32 @@

     return NGX_OK;
 }
+
+ngx_int_t
+ngx_http_upstream_last_modified(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_char *u;
+
+    if (r->upstream == NULL || r->upstream->cache_status == 0 ||
r->cache==NULL || r->cache->last_modified <= 0) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+       u = ngx_pcalloc(r->pool, 30);
+    if (u == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = 29;
+       ngx_http_time(u, r->cache->last_modified);
+    v->data = u;
+
+    return NGX_OK;
+}

 #endif


MagicBear
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20110916/c5086bf9/attachment.html>


More information about the nginx-devel mailing list