diff --git a/src/proxy.c b/src/proxy.c index 923f094..3a588ef 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -561,6 +561,15 @@ for(;;){ hdrfree(&buf, &bufown); hdrsdone = 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. */ + *param->username = 0; + *param->password = 0; + param->pwtype = 0; + *param->extusername = 0; + *param->extpassword = 0; + if(keepalive && (param->cliinbuf == param->clioffset) && (param->remsock != INVALID_SOCKET)){ memset(fds, 0, sizeof(fds)); fds[0].fd = param->clisock; 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")