extacl_message.clean();
+ etag.clean();
+
#if USE_ADAPTATION
adaptHistory_ = NULL;
#endif
// 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?
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;
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;
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
#include "clientStream.h"
#include "dlink.h"
#include "errorpage.h"
+#include "ETag.h"
#include "fd.h"
#include "fde.h"
#include "format/Token.h"
#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);
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));
}
}
+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
{