]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Make it possible to match empty header field values using req_header and rep_header.
authorAlex Rousskov <rousskov@measurement-factory.com>
Mon, 26 Nov 2012 18:54:43 +0000 (11:54 -0700)
committerAlex Rousskov <rousskov@measurement-factory.com>
Mon, 26 Nov 2012 18:54:43 +0000 (11:54 -0700)
Warning: Some req_header and rep_header ACLs that were [accidentally] not
matching empty headers (e.g., "^$" or ".*") will now start matching them.

A new HttpHeader::getByNameIfPresent() method is added to be able to detect
presence of empty header fields while ACLHTTPHeaderData::match() is adjusted
to convert undefined String values into empty c-strings ("") for
ACLRegexData::match() to work.

Prior to these changes, when trying to match an empty header value with a
regex like "^$", ACLHTTPHeaderData::match() would return false because:

  * HttpHeader::getStrOrList() and getByName() return an undefined String.
  * String::termedBuf() returns NULL for undefined Strings; and
  * ACLRegexData::match() always fails on NULL c-strings.

src/HttpHeader.cc
src/HttpHeader.h
src/acl/HttpHeaderData.cc

index 1333cf5ccb1a77c8a4dc8242bdfd2d135a8bca8c..451530380475d5aa9c33c924f0a91cb1a826b686 100644 (file)
@@ -1020,10 +1020,19 @@ HttpHeader::getStrOrList(http_hdr_type id) const
 }
 
 /*
- * Returns the value of the specified header.
+ * Returns the value of the specified header and/or an undefined String.
  */
 String
 HttpHeader::getByName(const char *name) const
+{
+    String result;
+    // ignore presence: return undefined string if an empty header is present
+    (void)getByNameIfPresent(name, result);
+    return result;
+}
+
+bool
+HttpHeader::getByNameIfPresent(const char *name, String &result) const
 {
     http_hdr_type id;
     HttpHeaderPos pos = HttpHeaderInitPos;
@@ -1034,19 +1043,23 @@ HttpHeader::getByName(const char *name) const
     /* First try the quick path */
     id = httpHeaderIdByNameDef(name, strlen(name));
 
-    if (id != -1)
-        return getStrOrList(id);
-
-    String result;
+    if (id != -1) {
+        if (!has(id))
+            return false;
+        result = getStrOrList(id);
+        return true;
+    }
 
     /* Sorry, an unknown header name. Do linear search */
+    bool found = false;
     while ((e = getEntry(&pos))) {
         if (e->id == HDR_OTHER && e->name.caseCmp(name) == 0) {
+            found = true;
             strListAdd(&result, e->value.termedBuf(), ',');
         }
     }
 
-    return result;
+    return found;
 }
 
 /*
index 4def174193ed30aa6fa3185a201739570a5a765e..e93cf95d676a09e1532bf624ae3ff39b3655d2ce 100644 (file)
@@ -247,6 +247,8 @@ public:
     bool getList(http_hdr_type id, String *s) const;
     String getStrOrList(http_hdr_type id) const;
     String getByName(const char *name) const;
+    /// sets value and returns true iff a [possibly empty] named field is there
+    bool getByNameIfPresent(const char *name, String &value) const;
     String getByNameListMember(const char *name, const char *member, const char separator) const;
     String getListMember(http_hdr_type id, const char *member, const char separator) const;
     int has(http_hdr_type id) const;
index 7ba80d90866dc6a49c22c0274ae3eb97acbfbe32..d84633df05a7b21e2a5133e081128a359ef4f89a 100644 (file)
@@ -65,9 +65,23 @@ ACLHTTPHeaderData::match(HttpHeader* hdr)
 
     debugs(28, 3, "aclHeaderData::match: checking '" << hdrName << "'");
 
-    String value = hdrId != HDR_BAD_HDR ? hdr->getStrOrList(hdrId) : hdr->getByName(hdrName.termedBuf());
+    String value;
+    if (hdrId != HDR_BAD_HDR) {
+        if (!hdr->has(hdrId))
+            return false;
+        value = hdr->getStrOrList(hdrId);
+    } else {
+        if (!hdr->getByNameIfPresent(hdrName.termedBuf(), value))
+            return false;
+    }
 
-    return regex_rule->match(value.termedBuf());
+    // By now, we know the header is present, but:
+    // HttpHeader::get*() return an undefined String for empty header values;
+    // String::termedBuf() returns NULL for undefined Strings; and
+    // ACLRegexData::match() always fails on NULL strings.
+    // This makes it possible to detect an empty header value using regex:
+    const char *cvalue = value.defined() ? value.termedBuf() : "";
+    return regex_rule->match(cvalue);
 }
 
 wordlist *