Description: VSV00018: normalize query-only absolute-form paths
 .
 Backport parser logic without the new counter; preserve http_method_eq.
 Extend downstream stable tests for HTTP/HTTPS, conflicting Host and query-only
 paths. Drop the old r01847 backend expectation for unnormalized HTTPS which
 is now rejected by the URL guard when https_scheme is explicitly disabled.
Author: Nils Goroll <nils.goroll@uplex.de>
Origin: https://code.vinyl-cache.org/vinyl-cache/vinyl-cache/commit/613b6f6a3b5ef35df0ab5139310f4944bf1adf58
Bug: https://vinyl-cache.org/security/VSV00018.html
Forwarded: not-needed
Last-Update: 2026-10-23

Index: varnish-7.7.0/bin/varnishd/http1/cache_http1_proto.c
===================================================================
--- varnish-7.7.0.orig/bin/varnishd/http1/cache_http1_proto.c
+++ varnish-7.7.0/bin/varnishd/http1/cache_http1_proto.c
@@ -355,6 +355,7 @@ HTTP1_DissectRequest(struct http_conn *h
 	uint16_t retval;
 	const char *p;
 	const char *b = NULL, *e;
+	char c = '\0';
 
 	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
@@ -374,9 +375,11 @@ HTTP1_DissectRequest(struct http_conn *h
 	    http_scheme_at(hp->hd[HTTP_HDR_URL].b, https))
 		b = hp->hd[HTTP_HDR_URL].b + 8;
 	if (b) {
-		e = strchr(b, '/');
+		e = strpbrk(b, "/?");
 		if (e == NULL)
 			e = hp->hd[HTTP_HDR_URL].e;
+		else
+			c = *e;
 		if (e == b) {
 			// rfc9110 4.2.1 4.2.2 reject empty host
 			return (400);
@@ -389,6 +392,10 @@ HTTP1_DissectRequest(struct http_conn *h
 				hp->hd[HTTP_HDR_URL] = Tstr("*");
 			else
 				hp->hd[HTTP_HDR_URL] = Tstr("/");
+		} else if (c == '?') {
+			hp->hd[HTTP_HDR_URL].b--;
+			char *t = TRUST_ME(hp->hd[HTTP_HDR_URL].b);
+			*t = '/';
 		}
 	}
 
Index: varnish-7.7.0/bin/varnishtest/tests/r01255.vtc
===================================================================
--- varnish-7.7.0.orig/bin/varnishtest/tests/r01255.vtc
+++ varnish-7.7.0/bin/varnishtest/tests/r01255.vtc
@@ -1,6 +1,6 @@
 varnishtest "Test RFC9112 3.2 compliance"
 
-server s1 -repeat 4 {
+server s1 -repeat 8 {
 	rxreq
 	txresp -hdr "Foo: 1"
 } -start
@@ -34,6 +34,30 @@ client c1 {
 	expect resp.http.rxhost == www.example.com
 	expect resp.http.url == *
 
+	txreq -url https://www.example.com -hdr "host: another"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.rxhost == www.example.com
+	expect resp.http.url == /
+
+	txreq -url http://www.example.com?/foo -hdr "host: another"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.rxhost == www.example.com
+	expect resp.http.url == /?/foo
+
+	txreq -url https://www.example.com?/foo -hdr "host: another"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.rxhost == www.example.com
+	expect resp.http.url == /?/foo
+
+	txreq -url https://www.example.com/?a=b -hdr "host: another"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.rxhost == www.example.com
+	expect resp.http.url == /?a=b
+
 	txreq -url http:///bar -hdr "host: another"
 	rxresp
 	expect resp.status == 400
Index: varnish-7.7.0/bin/varnishtest/tests/r01847.vtc
===================================================================
--- varnish-7.7.0.orig/bin/varnishtest/tests/r01847.vtc
+++ varnish-7.7.0/bin/varnishtest/tests/r01847.vtc
@@ -5,9 +5,6 @@ server s1 {
 	expect req.url == /bar
 	txresp
 
-	rxreq
-	expect req.url == https://www.example.com/bar
-	txresp
 } -start
 
 varnish v1 -vcl+backend {
