Repository: varnishcache/varnish-cache (2025-07-21T12:26:30Z)

Issue:
Bad chunked encoding should cause 400 error, not 503
### Expected Behavior

Bad chunked encoding should cause a 400 error.

### Current Behavior

The [test for VSV16](https://github.com/varnishcache/varnish-cache/blob/7d6cfa384d7296646e73c80e572fbe182274d701/bin/varnishtest/tests/f00016.vtc) shows that malformed chunked responses cause a 503 error, which is clearly wrong.

### Possible Solution

Varnish should differentiate between “failed to parse data from client” and “failed to fetch response from backend”.  It appears that it is the conflation of the two that causes the error.

### Steps to Reproduce (for bugs)

Run `make -C bin/varnishtest check-TESTS TESTS=tests/f00016.vtc` and notice that the tests passes with the 503 status codes.

### Context

This is almost certainly quite minor, as only buggy or malicious clients can trigger this code path.  Correct clients will not be affected, and setups where Varnish is behind NGINX or HAProxy (as a layer 7 reverse proxy) will not be affected either.

### Varnish Cache version

 varnishd (varnish-trunk revision 7d6cfa384d7296646e73c80e572fbe182274d701)

### Operating system

Fedora 41 with Linux 6.12.25

### Source of binary packages used (if any)

None


Discussion:
bugwash agrees.



Patch:
diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c
index 803810210e..a8fa68be92 100644
--- a/bin/varnishd/cache/cache_req_fsm.c
+++ b/bin/varnishd/cache/cache_req_fsm.c
@@ -1007,6 +1007,7 @@ cnt_recv(struct worker *wrk, struct req *req)
 	/* Attempts to cache req.body may fail */
 	if (req->req_body_status == BS_ERROR) {
 		req->doclose = SC_RX_BODY;
+		(void)req->transport->minimal_response(req, 400);
 		return (REQ_FSM_DONE);
 	}
 
diff --git a/bin/varnishd/http1/cache_http1_fetch.c b/bin/varnishd/http1/cache_http1_fetch.c
index e0c53b96ba..f8bcf43cd4 100644
--- a/bin/varnishd/http1/cache_http1_fetch.c
+++ b/bin/varnishd/http1/cache_http1_fetch.c
@@ -162,6 +162,7 @@ V1F_SendReq(struct worker *wrk, struct busyobj *bo, uint64_t *ctr_hdrbytes,
 			    "req.body read error: %d (%s)",
 			    errno, VAS_errtxt(errno));
 			bo->req->doclose = SC_RX_BODY;
+			bo->err_code = 400;
 		}
 		if (cl < 0)
 			V1L_EndChunk(v1l);


Test patch:
diff --git a/bin/varnishtest/tests/c00055.vtc b/bin/varnishtest/tests/c00055.vtc
index 0484219671..a84f61f902 100644
--- a/bin/varnishtest/tests/c00055.vtc
+++ b/bin/varnishtest/tests/c00055.vtc
@@ -72,5 +72,6 @@ client c4 {
 # req body overflow
 client c5 {
 	txreq -req POST -hdr "Content-Length: 1025"
-	expect_close
+	rxresp
+	expect resp.status == 400
 } -run
diff --git a/bin/varnishtest/tests/c00067.vtc b/bin/varnishtest/tests/c00067.vtc
index 71e8c90f04..ebfeebff79 100644
--- a/bin/varnishtest/tests/c00067.vtc
+++ b/bin/varnishtest/tests/c00067.vtc
@@ -91,7 +91,8 @@ client c1 {
 	chunked {BLAST}
 	delay .2
 	chunkedlen 106
-	expect_close
+	rxresp
+	expect resp.status == 400
 } -run
 
 logexpect l2 -wait
diff --git a/bin/varnishtest/tests/f00001.vtc b/bin/varnishtest/tests/f00001.vtc
index 2c756c9cd3..2cab540ba4 100644
--- a/bin/varnishtest/tests/f00001.vtc
+++ b/bin/varnishtest/tests/f00001.vtc
@@ -18,7 +18,7 @@ client c1 {
 	send "0\r\n\r\n"
 
 	rxresp
-	expect resp.status == 503
+	expect resp.status == 400
 } -run
 
 # Check that the published workaround does not cause harm
diff --git a/bin/varnishtest/tests/f00016.vtc b/bin/varnishtest/tests/f00016.vtc
index a38b8b1eff..322bff7e88 100644
--- a/bin/varnishtest/tests/f00016.vtc
+++ b/bin/varnishtest/tests/f00016.vtc
@@ -23,7 +23,7 @@ client c1 {
 	send "\r\n"
 	fatal
 	rxresp
-	expect resp.status == 503
+	expect resp.status == 400
 	expect_close
 } -run
 
@@ -38,7 +38,7 @@ client c2 {
 	send "\r\n"
 	fatal
 	rxresp
-	expect resp.status == 503
+	expect resp.status == 400
 	expect_close
 } -run
 
@@ -51,7 +51,7 @@ client c3 {
 	send "\r\n"
 	fatal
 	rxresp
-	expect resp.status == 503
+	expect resp.status == 400
 	expect_close
 } -run
 
@@ -62,8 +62,29 @@ client c4 {
 	send "\r\n"
 	fatal
 	rxresp
-	expect resp.status == 503
+	expect resp.status == 400
 	expect_close
 } -run
 
 logexpect l1 -wait
+
+varnish v1 -vcl+backend {
+	import std;
+
+	sub vcl_recv {
+		std.cache_req_body(10kb);
+	}
+}
+
+client c5 {
+	non_fatal
+	txreq -req POST -hdr "Transfer-encoding: chunked"
+	send "1\r\n"
+	send "This is more than one byte of data\r\n"
+	send "0\r\n"
+	send "\r\n"
+	fatal
+	rxresp
+	expect resp.status == 400
+	expect_close
+} -run
diff --git a/bin/varnishtest/tests/r02722.vtc b/bin/varnishtest/tests/r02722.vtc
index 1268864b54..ac1027823a 100644
--- a/bin/varnishtest/tests/r02722.vtc
+++ b/bin/varnishtest/tests/r02722.vtc
@@ -18,7 +18,7 @@ client c1 {
         txreq -req POST -hdr "Content-Length: 100"
         send some
         rxresp
-        expect resp.status == 503
+        expect resp.status == 400
 }
 
 # This run performs the inheritance test on a TCP connection