[master] 25897d3 h2: Don't panic if we reembark with a request body

Dag Haavi Finstad daghf at varnish-software.com
Mon Oct 23 10:45:07 UTC 2017


commit 25897d362b92117888d766ec6f0b8de53e954558
Author: Dag Haavi Finstad <daghf at varnish-software.com>
Date:   Thu Oct 19 13:40:32 2017 +0200

    h2: Don't panic if we reembark with a request body
    
    This moves the body status decision to h2_end_headers, to make sure that
    it is only done once per request.
    
    We also move the Cookie header concatenation to h2_end_headers, to avoid
    stepping on any changes that may have taken place in VCL.
    
    Fixes: #2305

diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
index d7d1dce..f826136 100644
--- a/bin/varnishd/http2/cache_http2_proto.c
+++ b/bin/varnishd/http2/cache_http2_proto.c
@@ -480,26 +480,11 @@ h2_do_req(struct worker *wrk, void *priv)
 {
 	struct req *req;
 	struct h2_req *r2;
-	const char *b;
 
 	CAST_OBJ_NOTNULL(req, priv, REQ_MAGIC);
 	CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
 	THR_SetRequest(req);
 
-	// XXX: Smarter to do this already at HPACK time into tail end of
-	// XXX: WS, then copy back once all headers received.
-	// XXX: Have I mentioned H/2 Is hodge-podge ?
-	http_CollectHdrSep(req->http, H_Cookie, "; ");	// rfc7540,l,3114,3120
-
-	if (req->req_body_status == REQ_BODY_INIT) {
-		if (!http_GetHdr(req->http, H_Content_Length, &b))
-			req->req_body_status = REQ_BODY_WITHOUT_LEN;
-		else
-			req->req_body_status = REQ_BODY_WITH_LEN;
-	} else {
-		assert (req->req_body_status == REQ_BODY_NONE);
-	}
-
 	req->http->conds = 1;
 	if (CNT_Request(wrk, req) != REQ_FSM_DISEMBARK) {
 		AZ(req->ws->r);
@@ -516,6 +501,7 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
     struct req *req, struct h2_req *r2)
 {
 	h2_error h2e;
+	const char *b;
 
 	ASSERT_RXTHR(h2);
 	assert(r2->state == H2_S_OPEN);
@@ -533,6 +519,20 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
 	}
 	VSLb_ts_req(req, "Req", req->t_req);
 
+	// XXX: Smarter to do this already at HPACK time into tail end of
+	// XXX: WS, then copy back once all headers received.
+	// XXX: Have I mentioned H/2 Is hodge-podge ?
+	http_CollectHdrSep(req->http, H_Cookie, "; ");	// rfc7540,l,3114,3120
+
+	if (req->req_body_status == REQ_BODY_INIT) {
+		if (!http_GetHdr(req->http, H_Content_Length, &b))
+			req->req_body_status = REQ_BODY_WITHOUT_LEN;
+		else
+			req->req_body_status = REQ_BODY_WITH_LEN;
+	} else {
+		assert (req->req_body_status == REQ_BODY_NONE);
+	}
+
 	req->req_step = R_STP_TRANSPORT;
 	req->task.func = h2_do_req;
 	req->task.priv = req;
diff --git a/bin/varnishtest/tests/r02305.vtc b/bin/varnishtest/tests/r02305.vtc
new file mode 100644
index 0000000..d0bb78a
--- /dev/null
+++ b/bin/varnishtest/tests/r02305.vtc
@@ -0,0 +1,52 @@
+varnishtest "#2305: h/2 reembark with a request body"
+
+barrier b1 cond 2
+barrier b2 sock 2
+
+server s1 {
+	rxreq
+	expect req.url == "/"
+	barrier b1 sync
+	delay 2
+	txresp
+} -start
+
+varnish v1 -cliok "param.set feature +http2"
+varnish v1 -cliok "param.set debug +syncvsl"
+varnish v1 -cliok "param.set debug +waitinglist"
+
+varnish v1 -vcl+backend {
+	import vtc;
+	sub vcl_recv {
+		return (hash);
+	}
+	sub vcl_deliver {
+		if (req.http.sync) {
+			vtc.barrier_sync("${b2_sock}");
+		}
+	}
+} -start
+
+client c1 {
+	stream 1 {
+		txreq
+		rxresp
+		expect resp.status == 200
+	} -start
+	stream 3 {
+		barrier b1 sync
+		txreq -req POST -hdr sync 1 -body "foo"
+		rxwinup
+		# barrier b2 is here to make HEADERS vs WINDOW_UPDATE
+		# less racy
+		barrier b2 sync
+		rxresp
+		expect resp.status == 200
+	} -run
+} -run
+
+varnish v1 -vsl_catchup
+varnish v1 -expect MEMPOOL.req0.live == 0
+varnish v1 -expect MEMPOOL.sess0.live == 0
+varnish v1 -expect MEMPOOL.req1.live == 0
+varnish v1 -expect MEMPOOL.sess1.live == 0


More information about the varnish-commit mailing list