From 5babf687f6278c5e4cc796cb9546be00fd90de9a Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Fri, 13 Nov 2026 17:38:47 +0300 Subject: [PATCH] proxy: credentials of an earlier request not inherited by the next --- src/proxy.c | 21 +++++++++++++++++++++ tests/cases/proxy_http.py | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/proxy.c b/src/proxy.c index 644232b..8fba873 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -340,6 +340,27 @@ for(;;){ clhdrofs_req = -1; param->nolongdatfilter = 0; + /* What the request brought belongs to it alone. A connection can carry + a request after another's, so the credentials of an earlier request + decide nothing for this one. */ + if(param->username){ + free(param->username); + param->username = NULL; + } + if(param->password){ + free(param->password); + param->password = NULL; + } + param->pwtype = 0; + if(param->extusername){ + free(param->extusername); + param->extusername = NULL; + } + if(param->extpassword){ + free(param->extpassword); + param->extpassword = NULL; + } + /* A connection waiting a while for its next request, or a tunnel, holds no buffer: it is taken again once a request starts coming. */ if(buf && param->cliinbuf == param->clioffset){ diff --git a/tests/cases/proxy_http.py b/tests/cases/proxy_http.py index f9cf276..8856a6c 100644 --- a/tests/cases/proxy_http.py +++ b/tests/cases/proxy_http.py @@ -4,6 +4,8 @@ Access rules accumulate until "flush", so each service section here starts from a clean list. """ +import base64 + def run(t): if not t.skip_unless("httpsrv"): @@ -108,3 +110,18 @@ def run(t): t.eq(407, t.http(origin + "/echo", proxy=needs_auth, proxy_auth=("alice", "wrong")).status, "wrong proxy credentials are refused") + + # credentials do not outlive the request which carried them: a second + # request on the same connection, without them, is asked again + creds = base64.b64encode(b"alice:secret").decode() + text, closed = t.raw_session(auth, + f"GET {origin}/echo HTTP/1.1\r\nHost: 127.0.0.1:{srv}\r\n" + f"Proxy-Authorization: Basic {creds}\r\n\r\n" + f"GET {origin}/echo HTTP/1.1\r\nHost: 127.0.0.1:{srv}\r\n" + f"Connection: close\r\n\r\n") + parts = text.split("HTTP/1.") + t.eq(3, len(parts), "the kept connection answers both requests") + t.eq(True, parts[1].startswith("1 200"), + "the request with credentials is allowed") + t.eq(True, parts[2].startswith("0 407"), + "the request after it, without credentials, is refused")