[master] f92e560 Write a general http_split() function to use when finding tokens and what's not in http headers.

Poul-Henning Kamp phk at FreeBSD.org
Mon Sep 29 22:21:50 CEST 2014


commit f92e560e4ed21b20e21e9b039be9b189b7d11071
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Sep 29 20:20:23 2014 +0000

    Write a general http_split() function to use when finding tokens
    and what's not in http headers.
    
    Make http_GetHdrToken() return both start and end of tokendata so
    we can chew on it without thinking about NUL vs. anything else.

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 61298a3..4c9568f 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -880,7 +880,7 @@ 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, const char **ptr);
 int http_GetHdrToken(const struct http *hp, const char *hdr,
-    const char *token, const char **ptr);
+    const char *token, const char **pb, const char **pe);
 int http_GetHdrField(const struct http *hp, const char *hdr,
     const char *field, const 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 c74aa38..4735000 100644
--- a/bin/varnishd/cache/cache_http.c
+++ b/bin/varnishd/cache/cache_http.c
@@ -402,6 +402,54 @@ http_GetHdr(const struct http *hp, const char *hdr, const char **ptr)
 }
 
 /*-----------------------------------------------------------------------------
+ * Split source string at any of the separators, return pointer to first
+ * and last+1 char of substrings, with whitespace trimed at both ends.
+ * If sep being an empty string is shorthand for VCT::SP
+ * If stop is NULL, src is NUL terminated.
+ */
+
+static int
+http_split(const char **src, const char *stop, const char *sep,
+    const char **b, const char **e)
+{
+	const char *p, *q;
+
+	AN(src);
+	AN(*src);
+	AN(sep);
+	AN(b);
+	AN(e);
+
+	if (stop == NULL)
+		stop = strchr(*src, '\0');
+
+	for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++)
+		continue;
+
+	if (p >= stop) {
+		*b = NULL;
+		*e = NULL;
+		return (0);
+	}
+
+	*b = p;
+	if (*sep == '\0') {
+		for (q = p + 1; q < stop && !vct_issp(*q); q++)
+			continue;
+		*e = q;
+		*src = q;
+		return (1);
+	}
+	for (q = p + 1; q < stop && !strchr(sep, *q); q++)
+		continue;
+	*src = q;
+	while (q > p && vct_issp(q[-1]))
+		q--;
+	*e = q;
+	return (1);
+}
+
+/*-----------------------------------------------------------------------------
  * Find a given data element (token) in a header according to RFC2616's #rule
  * (section 2.1, p15)
  *
@@ -416,49 +464,47 @@ http_GetHdr(const struct http *hp, const char *hdr, const char **ptr)
  * 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.
+ *
+ * The optional pb and pe arguments will point to the token content start and
+ * end+1, white space trimmed on both sides.
  */
 
 int
 http_GetHdrToken(const struct http *hp, const char *hdr,
-    const char *token, const char **ptr)
+    const char *token, const char **pb, const char **pe)
 {
-	const char *h, *e;
+	const char *h, *b, *e;
 	unsigned fl;
-	int quoted;
 
-	if (ptr != NULL)
-		*ptr = NULL;
+	if (pb != NULL)
+		*pb = NULL;
+	if (pe != NULL)
+		*pe = NULL;
 	if (!http_GetHdr(hp, hdr, &h))
 		return (0);
 	AN(h);
-	e = strchr(h, '\0');
 	fl = strlen(token);
-	quoted = token[0] == '"' && token[fl] == '"';
 
-	while (h + fl <= e) {
-		/* Skip leading whitespace and commas */
-		if (vct_islws(*h) || *h == ',') {
-			h++;
+	while(http_split(&h, NULL, ",", &b, &e)) {
+		if (*b == '"' && !memcmp(b + 1, token, fl) && b[fl + 1] == '"')
+			break;
+		if (!strncasecmp(b, token, fl) && !vct_istchar(b[fl]))
+			break;
+	}
+	if (b == NULL)
+		return (0);
+	if (pb != NULL) {
+		for (b += fl; vct_islws(*b); b++)
 			continue;
+		if (b == e) {
+			b = NULL;
+			e = NULL;
 		}
-		/* Check for substrings before memcmp() */
-		if ((h + fl == e || vct_issepctl(h[fl])) &&
-		    (quoted
-		    ? !memcmp(h, token, fl)
-		    : !strncasecmp(h, token, fl))) {
-			if (ptr != NULL) {
-				h += fl;
-				while (vct_islws(*h))
-					h++;
-				*ptr = h;
-			}
-			return (1);
-		}
-		/* Skip until end of header or comma */
-		while (*h && *h != ',')
-			h++;
+		*pb = b;
+		if (pe != NULL)
+			*pe = e;
 	}
-	return (0);
+	return (1);
 }
 
 /*--------------------------------------------------------------------
@@ -468,45 +514,44 @@ http_GetHdrToken(const struct http *hp, const char *hdr,
 double
 http_GetHdrQ(const struct http *hp, const char *hdr, const char *field)
 {
-	const char *h;
+	const char *hb, *he, *b, *e;
 	int i;
-	double a, b;
+	double a, f;
 
-	h = NULL;
-	i = http_GetHdrToken(hp, hdr, field, &h);
+	i = http_GetHdrToken(hp, hdr, field, &hb, &he);
 	if (!i)
 		return (0.);
 
-	if (h == NULL)
+	if (hb == NULL)
 		return (1.);
-	/* Skip whitespace, looking for '=' */
-	while (*h && vct_issp(*h))
-		h++;
-	if (*h++ != ';')
-		return (1.);
-	while (*h && vct_issp(*h))
-		h++;
-	if (*h++ != 'q')
-		return (1.);
-	while (*h && vct_issp(*h))
-		h++;
-	if (*h++ != '=')
+	while(http_split(&hb, he, ";", &b, &e)) {
+		if (*b != 'q')
+			continue;
+		for (b++; b < e && vct_issp(*b); b++)
+			continue;
+		if (b == e || *b != '=')
+			continue;
+		break;
+	}
+	if (b == NULL)
 		return (1.);
-	while (*h && vct_issp(*h))
-		h++;
-	a = 0.;
-	while (vct_isdigit(*h)) {
+	for (b++; b < e && vct_issp(*b); b++)
+		continue;
+	if (b == e || (*b != '.' && !vct_isdigit(*b)))
+		return (0.);
+	a = 0;
+	while (b < e && vct_isdigit(*b)) {
 		a *= 10.;
-		a += *h - '0';
-		h++;
+		a += *b - '0';
+		b++;
 	}
-	if (*h++ != '.')
+	if (b == e || *b++ != '.')
 		return (a);
-	b = .1;
-	while (vct_isdigit(*h)) {
-		a += b * (*h - '0');
-		b *= .1;
-		h++;
+	f = .1;
+	while (b < e && vct_isdigit(*b)) {
+		a += f * (*b - '0');
+		f *= .1;
+		b++;
 	}
 	return (a);
 }
@@ -526,7 +571,7 @@ http_GetHdrField(const struct http *hp, const char *hdr,
 		*ptr = NULL;
 
 	h = NULL;
-	i = http_GetHdrToken(hp, hdr, field, &h);
+	i = http_GetHdrToken(hp, hdr, field, &h, NULL);
 	if (!i)
 		return (i);
 
@@ -579,7 +624,7 @@ http_GetContentLength(const struct http *hp)
 enum sess_close
 http_DoConnection(struct http *hp)
 {
-	const char *p, *q;
+	const char *h, *b, *e;
 	enum sess_close retval;
 	unsigned u;
 
@@ -589,26 +634,16 @@ http_DoConnection(struct http *hp)
 		retval = SC_NULL;
 
 	http_CollectHdr(hp, H_Connection);
-	if (!http_GetHdr(hp, H_Connection, &p))
+	if (!http_GetHdr(hp, H_Connection, &h))
 		return (retval);
-	AN(p);
-	for (; *p; p++) {
-		if (vct_issp(*p))
-			continue;
-		if (*p == ',')
-			continue;
-		for (q = p + 1; *q; q++)
-			if (*q == ',' || vct_issp(*q))
-				break;
-		u = pdiff(p, q);
-		if (u == 5 && !strncasecmp(p, "close", u))
+	AN(h);
+	while (http_split(&h, NULL, ",", &b, &e)) {
+		u = pdiff(b, e);
+		if (u == 5 && !strncasecmp(b, "close", u))
 			retval = SC_REQ_CLOSE;
-		if (u == 10 && !strncasecmp(p, "keep-alive", u))
+		if (u == 10 && !strncasecmp(b, "keep-alive", u))
 			retval = SC_NULL;
-		http_MarkHeader(hp, p, u, HDF_FILTER);
-		if (!*q)
-			break;
-		p = q;
+		http_MarkHeader(hp, b, u, HDF_FILTER);
 	}
 	return (retval);
 }
diff --git a/bin/varnishd/cache/cache_rfc2616.c b/bin/varnishd/cache/cache_rfc2616.c
index 7c086b9..20b366b 100644
--- a/bin/varnishd/cache/cache_rfc2616.c
+++ b/bin/varnishd/cache/cache_rfc2616.c
@@ -194,7 +194,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_GetHdrToken(hp, H_Accept_Encoding, "x-gzip", NULL))
+	if (http_GetHdrToken(hp, H_Accept_Encoding, "x-gzip", NULL, NULL))
 		return (1);
 
 	/*
@@ -266,7 +266,7 @@ RFC2616_Vary_AE(struct http *hp)
 {
 	const char *vary;
 
-	if (http_GetHdrToken(hp, H_Vary, "Accept-Encoding", NULL))
+	if (http_GetHdrToken(hp, H_Vary, "Accept-Encoding", NULL, NULL))
 		return;
 	if (http_GetHdr(hp, H_Vary, &vary)) {
 		http_Unset(hp, H_Vary);



More information about the varnish-commit mailing list