[master] b109ee1 Fix sensitivity for header token matching. Rename GetHdrData -> GetHdrToken

Nils Goroll nils.goroll at uplex.de
Wed Aug 27 14:21:14 CEST 2014


commit b109ee1c099ebae6a9f9423b1a1f81c634c8f895
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Wed Aug 27 14:11:55 2014 +0200

    Fix sensitivity for header token matching. Rename GetHdrData -> GetHdrToken
    
    Section 4.2 (Messages Headers) of RFC2616 defines field (header) name as case
    insensitive, but the field (header) value/content may be case-sensitive.
    
    http_GetHdrToken looks up a token in a header value and the rfc does not say
    explicitly if tokens are to be compared with or without respect to case.
    
    But all examples and specific statements regarding tokens follow the rule
    that unquoted tokens are to be matched case-insensitively and quoted tokens
    case-sensitively.
    
    Fixes #1582

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 0d6c958..4b89207 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -962,8 +962,8 @@ void http_ForceField(const struct http *to, unsigned n, const char *t);
 void HTTP_Setup(struct http *, struct ws *, struct vsl_log *, enum VSL_tag_e);
 void http_Teardown(struct http *ht);
 int http_GetHdr(const struct http *hp, const char *hdr, char **ptr);
-int http_GetHdrData(const struct http *hp, const char *hdr,
-    const char *field, char **ptr);
+int http_GetHdrToken(const struct http *hp, const char *hdr,
+    const char *token, char **ptr);
 int http_GetHdrField(const struct http *hp, const char *hdr,
     const char *field, char **ptr);
 double http_GetHdrQ(const struct http *hp, const char *hdr, const char *field);
diff --git a/bin/varnishd/cache/cache_http.c b/bin/varnishd/cache/cache_http.c
index 16c21bb..acbee43 100644
--- a/bin/varnishd/cache/cache_http.c
+++ b/bin/varnishd/cache/cache_http.c
@@ -33,6 +33,7 @@
 
 #include <stdio.h>
 #include <stddef.h>
+#include <strings.h>
 
 #include "cache.h"
 
@@ -381,17 +382,30 @@ http_GetHdr(const struct http *hp, const char *hdr, char **ptr)
 	return (1);
 }
 
-/*--------------------------------------------------------------------
- * Find a given data element in a header according to RFC2616's #rule
+/*-----------------------------------------------------------------------------
+ * Find a given data element (token) in a header according to RFC2616's #rule
  * (section 2.1, p15)
+ *
+ * On case sensitivity:
+ *
+ * Section 4.2 (Messages Headers) defines field (header) name as case
+ * insensitive, but the field (header) value/content may be case-sensitive.
+ *
+ * http_GetHdrToken looks up a token in a header value and the rfc does not say
+ * explicitly if tokens are to be compared with or without respect to case.
+ *
+ * But all examples and specific statements regarding tokens follow the rule
+ * that unquoted tokens are to be matched case-insensitively and quoted tokens
+ * case-sensitively.
  */
 
 int
-http_GetHdrData(const struct http *hp, const char *hdr,
-    const char *field, char **ptr)
+http_GetHdrToken(const struct http *hp, const char *hdr,
+    const char *token, char **ptr)
 {
 	char *h, *e;
 	unsigned fl;
+	int quoted;
 
 	if (ptr != NULL)
 		*ptr = NULL;
@@ -399,7 +413,9 @@ http_GetHdrData(const struct http *hp, const char *hdr,
 		return (0);
 	AN(h);
 	e = strchr(h, '\0');
-	fl = strlen(field);
+	fl = strlen(token);
+	quoted = token[0] == '"' && token[fl] == '"';
+
 	while (h + fl <= e) {
 		/* Skip leading whitespace and commas */
 		if (vct_islws(*h) || *h == ',') {
@@ -408,7 +424,8 @@ http_GetHdrData(const struct http *hp, const char *hdr,
 		}
 		/* Check for substrings before memcmp() */
 		if ((h + fl == e || vct_issepctl(h[fl])) &&
-		    !memcmp(h, field, fl)) {
+		    ((quoted && !memcmp(h, token, fl)) ||
+		     !strncasecmp(h, token, fl))) {
 			if (ptr != NULL) {
 				h += fl;
 				while (vct_islws(*h))
@@ -436,7 +453,7 @@ http_GetHdrQ(const struct http *hp, const char *hdr, const char *field)
 	double a, b;
 
 	h = NULL;
-	i = http_GetHdrData(hp, hdr, field, &h);
+	i = http_GetHdrToken(hp, hdr, field, &h);
 	if (!i)
 		return (0.);
 
@@ -489,7 +506,7 @@ http_GetHdrField(const struct http *hp, const char *hdr,
 		*ptr = NULL;
 
 	h = NULL;
-	i = http_GetHdrData(hp, hdr, field, &h);
+	i = http_GetHdrToken(hp, hdr, field, &h);
 	if (!i)
 		return (i);
 
diff --git a/bin/varnishd/cache/cache_rfc2616.c b/bin/varnishd/cache/cache_rfc2616.c
index 75f74b5..b7737bc 100644
--- a/bin/varnishd/cache/cache_rfc2616.c
+++ b/bin/varnishd/cache/cache_rfc2616.c
@@ -322,7 +322,7 @@ RFC2616_Req_Gzip(const struct http *hp)
 	 * p104 says to not do q values for x-gzip, so we just test
 	 * for its existence.
 	 */
-	if (http_GetHdrData(hp, H_Accept_Encoding, "x-gzip", NULL))
+	if (http_GetHdrToken(hp, H_Accept_Encoding, "x-gzip", NULL))
 		return (1);
 
 	/*
@@ -395,7 +395,7 @@ RFC2616_Vary_AE(struct http *hp)
 {
 	char *vary;
 
-	if (http_GetHdrData(hp, H_Vary, "Accept-Encoding", NULL))
+	if (http_GetHdrToken(hp, H_Vary, "Accept-Encoding", NULL))
 		return;
 	if (http_GetHdr(hp, H_Vary, &vary)) {
 		http_Unset(hp, H_Vary);



More information about the varnish-commit mailing list