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);
 }

Reply via email to