]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Reload into If-None-Match
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Mon, 15 Jul 2013 07:49:43 +0000 (10:49 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Mon, 15 Jul 2013 07:49:43 +0000 (10:49 +0300)
This patch sends an If-None-Match  request, when we need to re-validate
if a cached object which has a strong ETag is still valid.

This is also done in the cases an HTTP client request contains HTTP
headers prohibiting a from-cache response (i.e., a "reload" request).
The use of If-None-Match request in this context violates RFC 2616 and
requires using reload-into-ims option within refresh_pattern squid.conf
directive.

The exact definition of a "reload request" and the adjustment/removal of
"reload" headers is the same as currently used for reload-into-ims
option support. This patch is not modifying that code/logic, just adding
an If-None-Match header in addition to the IMS header that Squid already
adds.

This is a Measurement Factory Project

src/HttpRequest.cc
src/HttpRequest.h
src/Store.h
src/cf.data.pre
src/client_side_reply.cc
src/http.cc
src/store.cc

index cd9b9905b8a6309e88bc0b373b0391ce3317c00c..9c1315d6ba3722e898555e5537df0bb1860d7138 100644 (file)
@@ -177,6 +177,8 @@ HttpRequest::clean()
 
     extacl_message.clean();
 
+    etag.clean();
+
 #if USE_ADAPTATION
     adaptHistory_ = NULL;
 #endif
@@ -222,6 +224,7 @@ HttpRequest::clone() const
     // XXX: what to do with copy->peer_login?
 
     copy->lastmod = lastmod;
+    copy->etag = etag;
     copy->vary_headers = vary_headers ? xstrdup(vary_headers) : NULL;
     // XXX: what to do with copy->peer_domain?
 
index 3f23606995ceb46a479cdd8a073e9f3eec552471..b1301fa7064808be54a8f86a9cc134b72cedbffe 100644 (file)
@@ -219,6 +219,9 @@ public:
     String x_forwarded_for_iterator; /* XXX a list of IP addresses */
 #endif /* FOLLOW_X_FORWARDED_FOR */
 
+    /// A strong etag of the cached entry. Used for refreshing that entry.
+    String etag;
+
 public:
     bool multipartRangeRequest() const;
 
index 44c1fda7995833607d8c849a3aca8aef3e7e3235..5576388302b7ba00a6ea7e1c6597ee0a691d91d5 100644 (file)
@@ -140,6 +140,8 @@ public:
     bool hasIfMatchEtag(const HttpRequest &request) const;
     /// has ETag matching at least one of the If-None-Match etags
     bool hasIfNoneMatchEtag(const HttpRequest &request) const;
+    /// whether this entry has an ETag; if yes, puts ETag value into parameter
+    bool hasEtag(ETag &etag) const;
 
     /** What store does this entry belong too ? */
     virtual RefCount<SwapDir> store() const;
index 5fdbf615c5d5e9143d1027baa1acac18c3b0b7d6..79007a96ff46d2021723ea3aa008b0ec10cca3c5 100644 (file)
@@ -4861,10 +4861,12 @@ DOC_START
                override-lastmod enforces min age even on objects
                that were modified recently.
 
-               reload-into-ims changes client no-cache or ``reload''
-               to If-Modified-Since requests. Doing this VIOLATES the
-               HTTP standard. Enabling this feature could make you
-               liable for problems which it causes.
+               reload-into-ims changes a client no-cache or ``reload''
+               request for a cached entry into a conditional request using
+               If-Modified-Since and/or If-None-Match headers, provided the
+               cached entry has a Last-Modified and/or a strong ETag header.
+               Doing this VIOLATES the HTTP standard. Enabling this feature
+               could make you liable for problems which it causes.
 
                ignore-reload ignores a client no-cache or ``reload''
                header. Doing this VIOLATES the HTTP standard. Enabling
index 297569de6c7628c669410439a0d612fa9427b87d..77a963cf3ca7a735b99eac52bf472d88e000293f 100644 (file)
@@ -35,6 +35,7 @@
 #include "anyp/PortCfg.h"
 #include "client_side_reply.h"
 #include "errorpage.h"
+#include "ETag.h"
 #include "fd.h"
 #include "fde.h"
 #include "format/Token.h"
@@ -271,6 +272,13 @@ clientReplyContext::processExpired()
 #endif
 
     http->request->lastmod = old_entry->lastmod;
+
+    if (!http->request->header.has(HDR_IF_NONE_MATCH)) {
+        ETag etag = {NULL, -1}; // TODO: make that a default ETag constructor
+        if (old_entry->hasEtag(etag) && !etag.weak)
+            http->request->etag = etag.str;
+    }
+
     debugs(88, 5, "clientReplyContext::processExpired : lastmod " << entry->lastmod );
     http->storeEntry(entry);
     assert(http->out.offset == 0);
index 5d44c921b1eeeb640e76366c567a31f1a70e3394..ce0515575168cd60a59392807df63af7e010b269 100644 (file)
@@ -1703,10 +1703,17 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
     HttpHeaderPos pos = HttpHeaderInitPos;
     assert (hdr_out->owner == hoRequest);
 
-    /* append our IMS header */
+    /* use our IMS header if the cached entry has Last-Modified time */
     if (request->lastmod > -1)
         hdr_out->putTime(HDR_IF_MODIFIED_SINCE, request->lastmod);
 
+    // Add our own If-None-Match field if the cached entry has a strong ETag.
+    // copyOneHeaderFromClientsideRequestToUpstreamRequest() adds client ones.
+    if (request->etag.defined()) {
+        hdr_out->addEntry(new HttpHeaderEntry(HDR_IF_NONE_MATCH, NULL,
+                          request->etag.termedBuf()));
+    }
+
     bool we_do_ranges = decideIfWeDoRanges (request);
 
     String strConnection (hdr_in->getList(HDR_CONNECTION));
index bed4525af8cd5fae5b66e8c3f403ed1b89ed997c..4d6b771bab533c559f9b3e690fb40053ba706ef2 100644 (file)
@@ -1968,6 +1968,17 @@ StoreEntry::modifiedSince(HttpRequest * request) const
     }
 }
 
+bool
+StoreEntry::hasEtag(ETag &etag) const
+{
+    if (const HttpReply *reply = getReply()) {
+        etag = reply->header.getETag(HDR_ETAG);
+        if (etag.str)
+            return true;
+    }
+    return false;
+}
+
 bool
 StoreEntry::hasIfMatchEtag(const HttpRequest &request) const
 {