>From 7ae9b567e18f9622fa6d58cd56b9066837c60481 Mon Sep 17 00:00:00 2001 From: Mani Goyal <[email protected]> Date: Wed, 12 Aug 2026 12:26:22 +0530 Subject: [PATCH] BUG/MEDIUM: http: fix authority parsing for absolute-form URI with empty path
http_parse_authority() only stopped scanning at '/', not '?'. For an absolute-form request-target with no path but a query string (e.g. "http://host?token=..."), the authority scan ran to the end of the URI and swallowed the query string into the authority. This caused http_scheme_based_normalize() to see an empty path and append '/' after the query string instead of between the host and the query, corrupting the request on the wire. Per RFC 3986, authority terminates at '/', '?', or the end of the URI, so also stop at '?'. Add two cases to h1_host_normalization.vtc covering an empty path with a query string, with and without a port needing normalization. This should be backported to all stable versions. Should fix issue #3460. --- .../http-messaging/h1_host_normalization.vtc | 38 +++++++++++++++++++ src/http.c | 4 +- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/reg-tests/http-messaging/h1_host_normalization.vtc b/reg-tests/http-messaging/h1_host_normalization.vtc index 0d6112705..048ad95bd 100644 --- a/reg-tests/http-messaging/h1_host_normalization.vtc +++ b/reg-tests/http-messaging/h1_host_normalization.vtc @@ -231,6 +231,16 @@ syslog S1 -level info { # C43 recv expect ~ "^.* uri: GET https://hostname:444/ HTTP/1.1; host: {hostname:444}$" + barrier b1 sync + + # C44 + recv + expect ~ "^.* uri: GET http://hostname\\?a=b HTTP/1.1; host: {hostname}$" + barrier b1 sync + + # C45 + recv + expect ~ "^.* uri: GET http://hostname\\?c=d HTTP/1.1; host: {hostname}$" } -start @@ -908,4 +918,32 @@ client c43 -connect ${h1_fe_sock} { expect resp.status == 200 } -run +# Wait matching on log message +barrier b1 sync + +# empty path with a query string, no port => query must be preserved +client c44 -connect ${h1_fe_sock} { + txreq \ + -req "GET" \ + -url "http://hostname?a=b" \ + -hdr "host: hostname" + + rxresp + expect resp.status == 200 +} -run + +# Wait matching on log message +barrier b1 sync + +# empty path with a query string and a default port => no stray '/' after query +client c45 -connect ${h1_fe_sock} { + txreq \ + -req "GET" \ + -url "http://hostname:80?c=d" \ + -hdr "host: hostname:80" + + rxresp + expect resp.status == 200 +} -run + syslog S1 -wait diff --git a/src/http.c b/src/http.c index e7e78300d..66f14653f 100644 --- a/src/http.c +++ b/src/http.c @@ -682,12 +682,12 @@ struct ist http_parse_authority(struct http_uri_parser *parser, int no_userinfo) ptr = start = istptr(parser->uri); end = istend(parser->uri); - while (ptr < end && *ptr != '/') { + while (ptr < end && *ptr != '/' && *ptr != '?') { if (*ptr++ == '@' && no_userinfo) start = ptr; } - /* OK, ptr point on the '/' or the end */ + /* OK, ptr point on the '/', the '?' or the end */ authority: parser->uri = ist2(ptr, end - ptr); -- 2.34.1

