Hello guys, <div>I have wrote a module to make nginx support 304 to decrease bandwidth usage.</div><div>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.</div>
<div>Note:</div><div>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?</div><div>
<br></div><div>You can download full patch file from here: <a href="http://m-b.cc/share/proxy_304.txt">http://m-b.cc/share/proxy_304.txt</a></div><div><br><div># User MagicBear <<a href="mailto:magicbearmo@gmail.com">magicbearmo@gmail.com</a>></div>
<div>Upstream:</div><div>add $upstream_last_modified variant.</div><div>add handler for 304 Unmodified.</div><div>Proxy:</div><div>change to send If-Modified-Since header. </div><div><br></div><div>diff -ruN a/http/modules/ngx_http_proxy_module.c b/http/modules/ngx_http_proxy_module.c</div>
<div>--- a/http/modules/ngx_http_proxy_module.c      2011-09-15 22:23:03.284431407 +0800</div><div>+++ b/http/modules/ngx_http_proxy_module.c      2011-09-16 01:41:44.654428632 +0800</div><div>@@ -543,7 +543,7 @@</div><div>
     { ngx_string("Connection"), ngx_string("close") },</div><div>     { ngx_string("Keep-Alive"), ngx_string("") },</div><div>     { ngx_string("Expect"), ngx_string("") },</div>
<div>-    { ngx_string("If-Modified-Since"), ngx_string("") },</div><div>+    { ngx_string("If-Modified-Since"), ngx_string("$upstream_last_modified") },</div><div>     { ngx_string("If-Unmodified-Since"), ngx_string("") },</div>
<div>     { ngx_string("If-None-Match"), ngx_string("") },</div><div>     { ngx_string("If-Match"), ngx_string("") },</div><div>diff -ruN a/http/ngx_http_upstream.c b/http/ngx_http_upstream.c</div>
<div>--- a/http/ngx_http_upstream.c  2011-09-15 22:23:03.284431407 +0800</div><div>+++ b/http/ngx_http_upstream.c  2011-09-16 01:41:44.654428632 +0800</div><div>@@ -16,6 +16,8 @@</div><div>     ngx_http_upstream_t *u);</div>
<div> static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,</div><div>     ngx_http_variable_value_t *v, uintptr_t data);</div><div>+static ngx_int_t ngx_http_upstream_last_modified(ngx_http_request_t *r,</div>
<div>+    ngx_http_variable_value_t *v, uintptr_t data);</div><div> #endif</div><div><br></div><div> static void ngx_http_upstream_init_request(ngx_http_request_t *r);</div><div>@@ -342,6 +344,10 @@</div><div>       ngx_http_upstream_cache_status, 0,</div>
<div>       NGX_HTTP_VAR_NOCACHEABLE, 0 },</div><div><br></div><div>+    { ngx_string("upstream_last_modified"), NULL,</div><div>+      ngx_http_upstream_last_modified, 0,</div><div>+      NGX_HTTP_VAR_NOCACHEABLE, 0 },</div>
<div>+</div><div> #endif</div><div><br></div><div>     { ngx_null_string, NULL, NULL, 0, 0, 0 }</div><div>@@ -1618,6 +1624,80 @@</div><div>             u->buffer.last = u->buffer.pos;</div><div>         }</div><div>
<br></div><div>+#if (NGX_HTTP_CACHE)</div><div>+</div><div>+        if (u->cache_status == NGX_HTTP_CACHE_EXPIRED &&</div><div>+                       u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED &&</div>
<div>+                       ngx_http_file_cache_valid(u->conf->cache_valid, u->headers_in.status_n))</div><div>+        {</div><div>+            ngx_int_t  rc;</div><div>+</div><div>+            rc = u->reinit_request(r);</div>
<div>+</div><div>+            if (rc == NGX_OK) {</div><div>+                u->cache_status = NGX_HTTP_CACHE_BYPASS;</div><div>+                rc = ngx_http_upstream_cache_send(r, u);</div><div>+</div><div>+                               time_t  now, valid;</div>
<div>+</div><div>+                               now = ngx_time();</div><div>+</div><div>+                               valid = r->cache->valid_sec;</div><div>+</div><div>+                               if (valid == 0) {</div>
<div>+                                       valid = ngx_http_file_cache_valid(u->conf->cache_valid,</div><div>+                                                                                                         u->headers_in.status_n);</div>
<div>+                                       if (valid) {</div><div>+                                               r->cache->valid_sec = now + valid;</div><div>+                                       }</div><div>+                               }</div>
<div>+</div><div>+                               if (valid) {</div><div>+                                       r->cache->last_modified = r->headers_out.last_modified_time;</div><div>+                                       r->cache->date = now;</div>
<div>+                                       r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);</div><div>+</div><div>+                                       // update Header</div><div>+                                       ngx_http_file_cache_set_header(r, u->buffer.start);</div>
<div>+</div><div>+                                       ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</div><div>+                                                                          "update cache \"%s\" header to new expired." , r->cache->file.name.data);</div>
<div>+</div><div>+                                       // Reopen file via RW</div><div>+                                       ngx_fd_t fd = ngx_open_file(r->cache->file.name.data, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);</div>
<div>+</div><div>+                                       if (fd == NGX_INVALID_FILE) {</div><div>+                                               ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,</div><div>+                                                                         ngx_open_file_n " \"%s\" failed", r->cache->file.name.data);</div>
<div>+                                               return;</div><div>+                                       }</div><div>+</div><div>+                                       // Write cache</div><div>+                                       if (write(fd, u->buffer.start, sizeof(ngx_http_file_cache_header_t)) < 0)</div>
<div>+                                       {</div><div>+                                               ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,</div><div>+                                                                         "write proxy_cache \"%s\" failed", r->cache->file.name.data);</div>
<div>+                                               return;</div><div>+                                       }</div><div>+</div><div>+                                       if (ngx_close_file(fd) == NGX_FILE_ERROR) {</div>
<div>+                                               ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,</div><div>+                                                                         ngx_close_file_n " \"%s\" failed", r->cache->file.name.data);</div>
<div>+                                       }</div><div>+                                       ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</div><div>+                                                                          "update cache \"%s\" header to new expired done." , r->cache->file.name.data);</div>
<div>+                               } else {</div><div>+                                       u->cacheable = 0;</div><div>+                                       r->headers_out.last_modified_time = -1;</div><div>+                               }</div>
<div>+            }</div><div>+</div><div>+            ngx_http_upstream_finalize_request(r, u, rc);</div><div>+            return;</div><div>+        }</div><div>+</div><div>+#endif</div><div>+</div><div>         if (ngx_http_upstream_test_next(r, u) == NGX_OK) {</div>
<div>             return;</div><div>         }</div><div>@@ -4006,6 +4086,32 @@</div><div><br></div><div>     return NGX_OK;</div><div> }</div><div>+</div><div>+ngx_int_t</div><div>+ngx_http_upstream_last_modified(ngx_http_request_t *r,</div>
<div>+    ngx_http_variable_value_t *v, uintptr_t data)</div><div>+{</div><div>+    u_char *u;</div><div>+</div><div>+    if (r->upstream == NULL || r->upstream->cache_status == 0 || r->cache==NULL || r->cache->last_modified <= 0) {</div>
<div>+        v->not_found = 1;</div><div>+        return NGX_OK;</div><div>+    }</div><div>+</div><div>+    v->valid = 1;</div><div>+    v->no_cacheable = 0;</div><div>+    v->not_found = 0;</div><div>+       u = ngx_pcalloc(r->pool, 30);</div>
<div>+    if (u == NULL) {</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    v->len = 29;</div><div>+       ngx_http_time(u, r->cache->last_modified);</div><div>+    v->data = u;</div>
<div>+</div><div>+    return NGX_OK;</div><div>+}</div><div><br></div><div> #endif</div></div><div><br></div><div><br></div><div>MagicBear</div><div><br></div>