[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