Compliance: delete Warnings that have warning-date different from Date.
Added HttpReply::removeStaleWarnings() method that iterates over all
Warning headers and removes stale warning-values. If a reply has no
valid Date header, all warning-values with warning-date are removed.
Also, we remove warning-value if we failed to parse warning-date.
removeStaleWarnings() is called from processReplyHeader(), after reply
headers are parsed.
Co-Advisor test cases:
test_case/rfc2616/date-accept-fmt-warn-asctime-rfc1123
test_case/rfc2616/date-accept-fmt-warn-asctime-rfc850
test_case/rfc2616/date-accept-fmt-warn-rfc1123-asctime
test_case/rfc2616/date-accept-fmt-warn-rfc1123-rfc850
test_case/rfc2616/date-accept-fmt-warn-rfc850-asctime
test_case/rfc2616/date-accept-fmt-warn-rfc850-rfc1123
Compliance: delete Warnings that have warning-date different from Date.
Added HttpReply::removeStaleWarnings() method that iterates over all Warning
headers and removes stale warning-values. If a reply has no valid Date header,
all warning-values with warning-date are removed. Also, we remove
warning-value if we failed to parse warning-date.
removeStaleWarnings() is called from processReplyHeader(), after reply headers
are parsed.
Co-Advisor test cases:
test_case/rfc2616/date-accept-fmt-warn-asctime-rfc1123
test_case/rfc2616/date-accept-fmt-warn-asctime-rfc850
test_case/rfc2616/date-accept-fmt-warn-rfc1123-asctime
test_case/rfc2616/date-accept-fmt-warn-rfc1123-rfc850
test_case/rfc2616/date-accept-fmt-warn-rfc850-asctime
test_case/rfc2616/date-accept-fmt-warn-rfc850-rfc1123
=== modified file 'src/HttpReply.cc'
--- src/HttpReply.cc 2010-08-24 04:18:51 +0000
+++ src/HttpReply.cc 2010-08-31 22:45:11 +0000
@@ -613,20 +613,105 @@ HttpReply::clone() const
rep->hdrCacheInit();
rep->hdr_sz = hdr_sz;
rep->http_ver = http_ver;
rep->pstate = pstate;
rep->body_pipe = body_pipe;
rep->protocol = protocol;
// keep_alive is handled in hdrCacheInit()
return rep;
}
bool HttpReply::inheritProperties(const HttpMsg *aMsg)
{
const HttpReply *aRep = dynamic_cast<const HttpReply*>(aMsg);
if (!aRep)
return false;
keep_alive = aRep->keep_alive;
return true;
}
+
+void HttpReply::removeStaleWarnings()
+{
+ if (header.has(HDR_WARNING)) {
+ HttpHeaderPos headerPos = HttpHeaderInitPos;
+ bool deletedAll = true;
+ while (HttpHeaderEntry *const e = header.getEntry(&headerPos)) {
+ if (e->id == HDR_WARNING) {
+ if (removeStaleWarningValues(*e)) {
+ int ignore = 0;
+ header.delAt(headerPos, ignore);
+ } else if (deletedAll)
+ deletedAll = false;
+ }
+ }
+ if (deletedAll)
+ CBIT_CLR(header.mask, HDR_WARNING);
+ }
+}
+
+/**
+ * Remove warning-values with warn-date different from Date value from
+ * a single header entry. Returns true if all warning-values are
+ * invalid and the header entry should be removed.
+ */
+bool HttpReply::removeStaleWarningValues(HttpHeaderEntry &e)
+{
+ String newValue;
+ bool skipped = false;
+ const char *item = 0;
+ int len = 0;
+ const char *pos = 0;
+ const char *prevItemEnd = 0;
+ while (strListGetItem(&e.value, ',', &item, &len, &pos)) {
+ bool keep = true;
+ // Does warning-value have warn-date (which contains quoted date)?
+ // We scan backwards, looking for two quoted strings.
+ // warning-value = warn-code SP warn-agent SP warn-text [SP warn-date]
+ const char *p = item + len - 1;
+
+ while (p >= item && xisspace(*p)) --p; // skip whitespace
+
+ // warning-value MUST end with quote
+ if (p >= item && *p == '"') {
+ const char *const warnDateEnd = p;
+ --p;
+ while (p >= item && *p != '"') --p; // find the next quote
+
+ const char *warnDate = p + 1;
+ --p;
+ while (p >= item && xisspace(*p)) --p; // skip whitespace
+
+ if (p >= item && *p == '"' && warnDate - p > 2) {
+ // found warn-text
+ // const_cast is safe because e.value is not const
+ *const_cast<char*>(warnDateEnd) = '\0';
+ const time_t time = parse_rfc1123(warnDate);
+ *const_cast<char*>(warnDateEnd) = '"';
+ keep = (time > 0 && time == date); // keep valid and matching date
+ }
+ }
+
+ if (!keep) {
+ if (!skipped) {
+ // skipping for the first time, copy all previous warning-values
+ if (prevItemEnd)
+ newValue = e.value.substr(0, prevItemEnd - e.value.termedBuf());
+ skipped = true;
+ }
+ } else if (skipped) {
+ newValue.append(", ");
+ newValue.append(item, len);
+ }
+
+ prevItemEnd = item + len;
+ }
+
+ if (skipped) {
+ if (newValue.undefined())
+ return true;
+ e.value = newValue;
+ }
+
+ return false;
+}
=== modified file 'src/HttpReply.h'
--- src/HttpReply.h 2010-02-06 06:32:11 +0000
+++ src/HttpReply.h 2010-08-31 22:27:30 +0000
@@ -121,55 +121,60 @@ public:
/** Checks whether received body exceeds known maximum size.
* Requires a prior call to calcMaxBodySize().
*/
bool receivedBodyTooLarge(HttpRequest&, int64_t receivedBodySize);
/** Checks whether expected body exceeds known maximum size.
* Requires a prior call to calcMaxBodySize().
*/
bool expectedBodyTooLarge(HttpRequest& request);
int validatorsMatch (HttpReply const *other) const;
void packHeadersInto(Packer * p) const;
/** Clone this reply.
* Could be done as a copy-contructor but we do not want to accidently copy a HttpReply..
*/
HttpReply *clone() const;
+ /// Remove Warnings with warn-date different from Date value
+ void removeStaleWarnings();
+
private:
/** initialize */
void init();
void clean();
void hdrCacheClean();
void packInto(Packer * p);
/* ez-routines */
/** \return construct 304 reply and pack it into a MemBuf */
MemBuf *packed304Reply();
/* header manipulation */
time_t hdrExpirationTime();
/** Calculates and stores maximum body size if needed.
* Used by receivedBodyTooLarge() and expectedBodyTooLarge().
*/
void calcMaxBodySize(HttpRequest& request);
+ bool removeStaleWarningValues(HttpHeaderEntry &e);
+
mutable int64_t bodySizeMax; /**< cached result of calcMaxBodySize */
protected:
virtual void packFirstLineInto(Packer * p, bool) const;
virtual bool parseFirstLine(const char *start, const char *end);
virtual void hdrCacheInit();
};
MEMPROXY_CLASS_INLINE(HttpReply);
#endif /* SQUID_HTTPREPLY_H */
=== modified file 'src/http.cc'
--- src/http.cc 2010-08-24 04:18:51 +0000
+++ src/http.cc 2010-08-31 22:27:41 +0000
@@ -714,40 +714,42 @@ HttpStateData::processReplyHeader()
// TODO: pass to the client anyway?
}
#endif
delete newrep;
debugs(11, 2, HERE << "1xx headers consume " << header_bytes_read << " bytes header.");
header_bytes_read = 0;
if (reply_bytes_read > 0)
debugs(11, 2, HERE << "1xx headers consume " << reply_bytes_read << " bytes reply.");
reply_bytes_read = 0;
ctx_exit(ctx);
processReplyHeader();
return;
}
flags.chunked = 0;
if (newrep->sline.protocol == PROTO_HTTP && newrep->header.chunked()) {
flags.chunked = 1;
httpChunkDecoder = new ChunkedCodingParser;
}
+ newrep->removeStaleWarnings();
+
if (!peerSupportsConnectionPinning())
orig_request->flags.connection_auth_disabled = 1;
HttpReply *vrep = setVirginReply(newrep);
flags.headers_parsed = 1;
keepaliveAccounting(vrep);
checkDateSkew(vrep);
processSurrogateControl (vrep);
/** \todo IF the reply is a 1.0 reply, AND it has a Connection: Header
* Parse the header and remove all referenced headers
*/
orig_request->hier.peer_reply_status = newrep->sline.status;
ctx_exit(ctx);
}