]> err.no Git - varnish/commitdiff
Implement "If-Modified-Since" conditional queries
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 20 Jul 2006 09:29:45 +0000 (09:29 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 20 Jul 2006 09:29:45 +0000 (09:29 +0000)
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@513 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_fetch.c
varnish-cache/bin/varnishd/cache_http.c
varnish-cache/bin/varnishd/cache_response.c

index e759968fc74f8f939fd59e8977ae95cdbbcb2715..f3b1407158e5773ab6d3bfae87b7acf0b4ae28a0 100644 (file)
@@ -56,6 +56,8 @@ struct http {
        char                    *proto;
        char                    *status;
        char                    *response;
+
+       unsigned                conds;          /* If-* headers present */
        
        unsigned                nhdr;
        char                    **hdr;
@@ -151,6 +153,8 @@ struct object {
        time_t                  entered;
        time_t                  ttl;
 
+       time_t                  last_modified;
+
        char                    *header;
        TAILQ_ENTRY(object)     list;
 
@@ -337,7 +341,7 @@ void VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...);
 /* cache_response.c */
 void RES_Error(struct sess *sp, int error, const char *msg);
 void RES_Flush(struct sess *sp);
-void RES_Write(struct sess *sp, void *ptr, size_t len);
+void RES_Write(struct sess *sp, const void *ptr, size_t len);
 void RES_WriteObj(struct sess *sp);
 
 /* cache_vcl.c */
index ba8ed484375d690872ce32fe7e25a76273899430..a052a3585c041c72fdc182c236b5c4c2db52b491 100644 (file)
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
+#include <time.h>
 
 #include "shmlog.h"
+#include "libvarnish.h"
 #include "cache.h"
 
 /*
@@ -211,6 +213,8 @@ FetchBody(struct worker *w, struct sess *sp)
        vc = sp->vbc;
        hp = sp->bkd_http;
 
+       if (http_GetHdr(hp, "Last-Modified", &b))
+               sp->obj->last_modified = TIM_parse(b);
        http_BuildSbuf(sp->fd, Build_Reply, w->sb, hp);
        if (body) {
                if (http_GetHdr(hp, "Content-Length", &b))
index 483d04f8596c89979597e5bbbffa7cc9bd116ae1..dc1dd829d039a0055104960f03aa706ee3d0a623 100644 (file)
@@ -156,7 +156,10 @@ http_GetStatus(struct http *hp)
        return (strtoul(hp->status, NULL /* XXX */, 10));
 }
 
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * Dissect the headers of the HTTP protocol message.
+ * Detect conditionals (headers which start with '^[Ii][Ff]-')
+ */
 
 static int
 http_dissect_hdrs(struct http *hp, int fd, char *p)
@@ -167,6 +170,7 @@ http_dissect_hdrs(struct http *hp, int fd, char *p)
                p++;
 
        hp->nhdr = 0;
+       hp->conds = 0;
        r = NULL;               /* For FlexeLint */
        assert(p < hp->v);      /* http_header_complete() guarantees this */
        for (; p < hp->v; p = r) {
@@ -179,6 +183,11 @@ http_dissect_hdrs(struct http *hp, int fd, char *p)
                if (p == q)
                        break;
 
+               if ((p[0] == 'i' || p[0] == 'I') &&
+                   (p[1] == 'f' || p[1] == 'F') &&
+                   p[2] == '-') 
+                       hp->conds = 1;
+
                if (hp->nhdr < heritage.mem_http_headers) {
                        hp->hdr[hp->nhdr++] = p;
                        VSLR(SLT_Header, fd, p, q);
index 4fb384bed01714f64f02a06a7f33739770d96a24..4290007c0f04669962157f41afc3144219e51583 100644 (file)
@@ -93,20 +93,76 @@ RES_Flush(struct sess *sp)
 }
 
 void
-RES_Write(struct sess *sp, void *ptr, size_t len)
+RES_Write(struct sess *sp, const void *ptr, size_t len)
 {
 
        if (sp->fd < 0 || len == 0)
                return;
+       if (len == -1)
+               len = strlen(ptr);
        if (sp->wrk->niov == MAX_IOVS)
                RES_Flush(sp);
        if (sp->fd < 0)
                return;
-       sp->wrk->iov[sp->wrk->niov].iov_base = ptr;
+       sp->wrk->iov[sp->wrk->niov].iov_base = (void*)(uintptr_t)ptr;
        sp->wrk->iov[sp->wrk->niov++].iov_len = len;
        sp->wrk->liov += len;
 }
 
+/*--------------------------------------------------------------------*/
+
+static void
+res_do_304(struct sess *sp, char *p)
+{
+       struct sbuf *sb;
+
+       sb = sp->wrk->sb;
+       sbuf_clear(sb);
+
+       VSL(SLT_Status, sp->fd, "%u", 304);
+       VSL(SLT_Length, sp->fd, "%u", 0);
+       RES_Write(sp, "HTTP/1.1 304 Not Modified\r\n", -1);
+       RES_Write(sp, "Via: 1.1 varnish\r\n", -1);
+       RES_Write(sp, "Last-Modified: ", -1);
+       RES_Write(sp, p, -1);
+       RES_Write(sp, "\r\n", -1);
+       if (strcmp(sp->http->proto, "HTTP/1.1")) 
+               RES_Write(sp, "Connection: close\r\n", -1);
+       sbuf_printf(sb, "X-Varnish: xid %u\r\n", sp->obj->xid);
+       sbuf_printf(sb, "\r\n");
+       sbuf_finish(sb);
+       RES_Write(sp, sbuf_data(sb), sbuf_len(sb));
+       RES_Flush(sp);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+res_do_conds(struct sess *sp)
+{
+       char *p;
+       time_t ims;
+
+       if (sp->obj->last_modified > 0 &&
+           http_GetHdr(sp->http, "If-Modified-Since", &p)) {
+               ims = TIM_parse(p);
+               if (ims > sp->t_req)    /* [RFC2616 14.25] */
+                       return (0);
+               if (ims > sp->obj->last_modified) {
+                       VSL(SLT_Debug, sp->fd,
+                           "Cond: %d > %d ", sp->obj->last_modified, ims);
+                       return (0);
+               }
+               VSL(SLT_Debug, sp->fd,
+                   "Cond: %d <= %d", sp->obj->last_modified, ims);
+               res_do_304(sp, p);
+               return (1);
+       }
+       return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
 void
 RES_WriteObj(struct sess *sp)
 {
@@ -118,6 +174,9 @@ RES_WriteObj(struct sess *sp)
 
        sb = sp->wrk->sb;
 
+       if (sp->obj->response == 200 && sp->http->conds && res_do_conds(sp))
+               return;
+               
        VSL(SLT_Status, sp->fd, "%u", sp->obj->response);
        VSL(SLT_Length, sp->fd, "%u", sp->obj->len);