[master] b12b829 Avoid leaving the h2sess hanging on return (fail)

Dag Haavi Finstad daghf at varnish-software.com
Fri Mar 9 14:38:08 UTC 2018


commit b12b8294cd431c9f82b54bafac5614d76e9ce744
Author: Dag Haavi Finstad <daghf at varnish-software.com>
Date:   Fri Mar 9 15:35:01 2018 +0100

    Avoid leaving the h2sess hanging on return (fail)
    
    If we fail a stream early from VCL via return (fail) after sending a
    request body, the h2 sess will be stuck waiting forever.

diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
index 542a10e..8b61020 100644
--- a/bin/varnishd/http2/cache_http2_proto.c
+++ b/bin/varnishd/http2/cache_http2_proto.c
@@ -509,6 +509,7 @@ h2_do_req(struct worker *wrk, void *priv)
 {
 	struct req *req;
 	struct h2_req *r2;
+	struct h2_sess *h2;
 
 	CAST_OBJ_NOTNULL(req, priv, REQ_MAGIC);
 	CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
@@ -517,10 +518,16 @@ h2_do_req(struct worker *wrk, void *priv)
 	req->http->conds = 1;
 	if (CNT_Request(wrk, req) != REQ_FSM_DISEMBARK) {
 		AZ(req->ws->r);
+		h2 = r2->h2sess;
+		CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
+		Lck_Lock(&h2->sess->mtx);
 		r2->scheduled = 0;
 		r2->state = H2_S_CLOSED;
-		if (r2->h2sess->error)
-			AZ(pthread_cond_signal(r2->h2sess->cond));
+		if (h2->mailcall == r2) {
+			h2->mailcall = NULL;
+			AZ(pthread_cond_signal(h2->cond));
+		}
+		Lck_Unlock(&h2->sess->mtx);
 	}
 	THR_SetRequest(NULL);
 }
diff --git a/bin/varnishtest/tests/t02005.vtc b/bin/varnishtest/tests/t02005.vtc
index c80432b..2bcd1da 100644
--- a/bin/varnishtest/tests/t02005.vtc
+++ b/bin/varnishtest/tests/t02005.vtc
@@ -2,15 +2,30 @@ varnishtest "H2 POST"
 
 barrier b1 cond 2
 
+barrier b2 sock 2
+barrier b3 sock 2
+
 server s1 {
 	rxreq
 	expect req.http.content-length == 7
 	expect req.http.transfer-encoding == <undef>
 	barrier b1 sync
 	txresp -hdr "Content-Type: text/plain" -body response
+
+	rxreq
+	txresp
 } -start
 
-varnish v1 -vcl+backend {} -cliok "param.set feature +http2" -start
+varnish v1 -vcl+backend {
+	import vtc;
+	sub vcl_recv {
+		if (req.url == "/a") {
+			vtc.barrier_sync("${b2_sock}");
+			vtc.barrier_sync("${b3_sock}");
+			return (fail);
+		}
+	}
+} -cliok "param.set feature +http2" -start
 varnish v1 -cliok "param.set debug +syncvsl"
 
 logexpect l1 -v v1 -g raw {
@@ -41,5 +56,27 @@ client c1 {
 	stream 0 -wait
 } -run
 
+client c1 {
+	stream 0 {
+		barrier b2 sync
+		delay 1
+		barrier b3 sync
+		rxwinup
+	} -start
+	stream 1 {
+		txreq -url "/a" -req POST -nostrend
+		txdata -datalen 100
+		rxresp
+		rxwinup
+		expect resp.status == 503
+	} -run
+	stream 3 {
+		txreq -url "/b"
+		rxresp
+		expect resp.status == 200
+	} -run
+	stream 0 -wait
+} -run
+
 
 logexpect l1 -wait


More information about the varnish-commit mailing list