[master] b2f32cd Try to get http->protover into some kind of consistent state so we do not send HTTP/2.0 headers to backends on pass from HTTP/2.0 clients

Poul-Henning Kamp phk at FreeBSD.org
Wed Mar 1 00:04:05 CET 2017


commit b2f32cd82111a9e6f388af0e459b9c1511bcae07
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Feb 28 23:03:17 2017 +0000

    Try to get http->protover into some kind of consistent state so we
    do not send HTTP/2.0 headers to backends on pass from HTTP/2.0 clients

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index c9fda21..fba8763 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -761,9 +761,10 @@ void http_ForceHeader(struct http *to, const char *hdr, const char *val);
 void http_PrintfHeader(struct http *to, const char *fmt, ...)
     __v_printflike(2, 3);
 void http_TimeHeader(struct http *to, const char *fmt, double now);
+void http_Proto(struct http *to);
 void http_SetHeader(struct http *to, const char *hdr);
-void http_SetH(const struct http *to, unsigned n, const char *fm);
-void http_ForceField(const struct http *to, unsigned n, const char *t);
+void http_SetH(struct http *to, unsigned n, const char *fm);
+void http_ForceField(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, const char **ptr);
diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c
index 1287f08..4aa3dd2 100644
--- a/bin/varnishd/cache/cache_fetch.c
+++ b/bin/varnishd/cache/cache_fetch.c
@@ -185,9 +185,12 @@ vbf_stp_mkbereq(struct worker *wrk, struct busyobj *bo)
 		http_ForceField(bo->bereq0, HTTP_HDR_PROTO, "HTTP/1.1");
 		if (cache_param->http_gzip_support)
 			http_ForceHeader(bo->bereq0, H_Accept_Encoding, "gzip");
-		http_CopyHome(bo->bereq0);
-	} else
+	} else {
 		AZ(bo->stale_oc);
+		if (bo->bereq0->protover > 11)
+			http_ForceField(bo->bereq0, HTTP_HDR_PROTO, "HTTP/1.1");
+	}
+	http_CopyHome(bo->bereq0);
 
 	if (bo->stale_oc != NULL &&
 	    ObjCheckFlag(bo->wrk, bo->stale_oc, OF_IMSCAND) &&
diff --git a/bin/varnishd/cache/cache_http.c b/bin/varnishd/cache/cache_http.c
index 6642ea9..c200e24 100644
--- a/bin/varnishd/cache/cache_http.c
+++ b/bin/varnishd/cache/cache_http.c
@@ -199,12 +199,37 @@ HTTP_Copy(struct http *to, const struct http * const fm)
 	memcpy(&to->nhd, &fm->nhd, sizeof *to - offsetof(struct http, nhd));
 	memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd);
 	memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf);
+	to->protover = fm->protover;
 }
 
 /*--------------------------------------------------------------------*/
 
 void
-http_SetH(const struct http *to, unsigned n, const char *fm)
+http_Proto(struct http *to)
+{
+	const char *fm;
+
+	fm = to->hd[HTTP_HDR_PROTO].b;
+
+	if ((fm[0] == 'H' || fm[0] == 'h') &&
+	    (fm[1] == 'T' || fm[0] == 't') &&
+	    (fm[2] == 'T' || fm[0] == 't') &&
+	    (fm[3] == 'P' || fm[0] == 'p') &&
+	    fm[4] == '/' &&
+	    vct_isdigit(fm[5]) &&
+	    fm[6] == '.' &&
+	    vct_isdigit(fm[7]) &&
+	    fm[8] == '\0') {
+		to->protover = 10 * (fm[5] - '0') + (fm[7] - '0');
+	} else {
+		to->protover = 0;
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+http_SetH(struct http *to, unsigned n, const char *fm)
 {
 
 	assert(n < to->nhd);
@@ -213,12 +238,14 @@ http_SetH(const struct http *to, unsigned n, const char *fm)
 	to->hd[n].e = strchr(to->hd[n].b, '\0');
 	to->hdf[n] = 0;
 	http_VSLH(to, n);
+	if (n == HTTP_HDR_PROTO)
+		http_Proto(to);
 }
 
 /*--------------------------------------------------------------------*/
 
 static void
-http_PutField(const struct http *to, int field, const char *string)
+http_PutField(struct http *to, int field, const char *string)
 {
 	char *p;
 
@@ -233,6 +260,8 @@ http_PutField(const struct http *to, int field, const char *string)
 	to->hd[field].e = strchr(p, '\0');
 	to->hdf[field] = 0;
 	http_VSLH(to, field);
+	if (field == HTTP_HDR_PROTO)
+		http_Proto(to);
 }
 
 /*--------------------------------------------------------------------*/
@@ -759,7 +788,7 @@ http_GetMethod(const struct http *hp)
  */
 
 void
-http_ForceField(const struct http *to, unsigned n, const char *t)
+http_ForceField(struct http *to, unsigned n, const char *t)
 {
 	int i;
 
@@ -1077,6 +1106,7 @@ http_FilterReq(struct http *to, const struct http *fm, unsigned how)
 	http_linkh(to, fm, HTTP_HDR_METHOD);
 	http_linkh(to, fm, HTTP_HDR_URL);
 	http_linkh(to, fm, HTTP_HDR_PROTO);
+	to->protover = fm->protover;
 	http_filterfields(to, fm, how);
 }
 
diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c
index 000ae75..d0380a8 100644
--- a/bin/varnishd/cache/cache_vrt_var.c
+++ b/bin/varnishd/cache/cache_vrt_var.c
@@ -45,7 +45,7 @@ static char vrt_hostname[255] = "";
  */
 
 static void
-vrt_do_string(VRT_CTX, const struct http *hp, int fld,
+vrt_do_string(VRT_CTX, struct http *hp, int fld,
     const char *err, const char *p, va_list ap)
 {
 	const char *b;
diff --git a/bin/varnishd/http1/cache_http1_proto.c b/bin/varnishd/http1/cache_http1_proto.c
index e788ed6..05d23b3 100644
--- a/bin/varnishd/http1/cache_http1_proto.c
+++ b/bin/varnishd/http1/cache_http1_proto.c
@@ -285,6 +285,8 @@ http1_splitline(struct http *hp, struct http_conn *htc, const int *hf,
 	*p = '\0';
 	p += i;
 
+	http_Proto(hp);
+
 	return (http1_dissect_hdrs(hp, p, htc, maxhdr));
 }
 
@@ -340,19 +342,6 @@ http1_body_status(const struct http *hp, struct http_conn *htc, int request)
 
 /*--------------------------------------------------------------------*/
 
-static int8_t
-http1_proto_ver(const struct http *hp)
-{
-	if (!strcasecmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.0"))
-		return (10);
-	else if (!strcasecmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
-		return (11);
-	else
-		return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
 uint16_t
 HTTP1_DissectRequest(struct http_conn *htc, struct http *hp)
 {
@@ -367,8 +356,8 @@ HTTP1_DissectRequest(struct http_conn *htc, struct http *hp)
 	    HTTP1_Req, cache_param->http_req_hdr_len);
 	if (retval != 0)
 		return (retval);
-	hp->protover = http1_proto_ver(hp);
-	if (hp->protover == 0)
+
+	if (hp->protover < 10 || hp->protover > 11)
 		return (400);
 
 	if (http_CountHdr(hp, H_Host) > 1)
@@ -418,29 +407,24 @@ HTTP1_DissectRequest(struct http_conn *htc, struct http *hp)
 
 uint16_t
 HTTP1_DissectResponse(struct http_conn *htc, struct http *hp,
-    const struct http *req)
+    const struct http *rhttp)
 {
 	uint16_t retval = 0;
 	const char *p;
-	int8_t rv;
-
 
 	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
-	CHECK_OBJ_NOTNULL(req, HTTP_MAGIC);
+	CHECK_OBJ_NOTNULL(rhttp, HTTP_MAGIC);
 
 	if (http1_splitline(hp, htc,
 	    HTTP1_Resp, cache_param->http_resp_hdr_len))
 		retval = 503;
 
-	if (retval == 0) {
-		hp->protover = http1_proto_ver(hp);
-		if (hp->protover == 0)
-			retval = 503;
-		rv = http1_proto_ver(req);
-		if (hp->protover > rv)
-			hp->protover = rv;
-	}
+	if (retval == 0 && hp->protover < 10)
+		retval = 503;
+
+	if (retval == 0 && hp->protover > rhttp->protover)
+		http_SetH(hp, HTTP_HDR_PROTO, rhttp->hd[HTTP_HDR_PROTO].b);
 
 	if (retval == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3)
 		retval = 503;
diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
index 1a11609..3148751 100644
--- a/bin/varnishd/http2/cache_http2_proto.c
+++ b/bin/varnishd/http2/cache_http2_proto.c
@@ -471,7 +471,6 @@ h2_rx_headers(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 	}
 	VSLb_ts_req(req, "Req", req->t_req);
 	http_SetH(req->http, HTTP_HDR_PROTO, "HTTP/2.0");
-	req->http->protover = 20;
 
 	if (h2->rxf_flags & H2FF_HEADERS_END_STREAM)
 		req->req_body_status = REQ_BODY_NONE;
@@ -821,7 +820,6 @@ h2_new_ou_session(struct worker *wrk, struct h2_sess *h2,
 	req->task.priv = req;
 	req->err_code = 0;
 	http_SetH(req->http, HTTP_HDR_PROTO, "HTTP/2.0");
-	req->http->protover = 20;
 	XXXAZ(Pool_Task(wrk->pool, &req->task, TASK_QUEUE_REQ));
 
 	/* Wait for PRISM response */
diff --git a/bin/varnishtest/tests/t02006.vtc b/bin/varnishtest/tests/t02006.vtc
index d8354b9..1fd54e1 100644
--- a/bin/varnishtest/tests/t02006.vtc
+++ b/bin/varnishtest/tests/t02006.vtc
@@ -2,6 +2,7 @@ varnishtest "H2 POST w/ 100 Continue"
 
 server s1 {
 	rxreq
+	expect req.proto == HTTP/1.1
 	txresp -hdr "Content-Type: text/plain" -body response
 } -start
 



More information about the varnish-commit mailing list