mirror of
https://github.com/3proxy/3proxy.git
synced 2026-11-05 01:15:48 +08:00
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
3proxy --help (and the usage message of a bad invocation) now lists what the build was made with: TLS and its backend, RADIUS, PCRE, IPv6, UNIX sockets, the built-in HTTP server, transparency, ODBC and the optional proxy services. The test runner reads the list before the first case and the cases state the features they need with t.skip_unless(), so a build without a feature skips its cases instead of failing them; a binary too old to report anything skips the cases with needs and runs the rest.
111 lines
4.0 KiB
Python
111 lines
4.0 KiB
Python
"""The HTTP proxy, with the built-in server as the origin.
|
|
|
|
Access rules accumulate until "flush", so each service section here starts
|
|
from a clean list.
|
|
"""
|
|
|
|
|
|
def run(t):
|
|
if not t.skip_unless("httpsrv"):
|
|
return
|
|
srv = t.free_port()
|
|
other = t.free_port()
|
|
prx = t.free_port()
|
|
deny = t.free_port()
|
|
auth = t.free_port()
|
|
|
|
t.start("proxy_http", f"""
|
|
log
|
|
auth iponly
|
|
allow *
|
|
http echo * /echo**
|
|
http data * /data
|
|
httpsrv -p{srv}
|
|
|
|
# a second origin, used as a destination the rules must keep out
|
|
flush
|
|
auth iponly
|
|
allow *
|
|
http echo * /echo**
|
|
httpsrv -p{other}
|
|
|
|
# an open proxy
|
|
flush
|
|
auth iponly
|
|
allow *
|
|
proxy -p{prx}
|
|
|
|
# only the first origin is reachable
|
|
flush
|
|
auth iponly
|
|
allow * * * {srv}
|
|
proxy -p{deny}
|
|
|
|
# credentials required
|
|
flush
|
|
auth strong
|
|
users alice:CL:secret
|
|
allow alice
|
|
proxy -p{auth}
|
|
""", ports=[srv, other, prx, deny, auth])
|
|
|
|
origin = f"http://127.0.0.1:{srv}"
|
|
second = f"http://127.0.0.1:{other}"
|
|
open_proxy = f"127.0.0.1:{prx}"
|
|
|
|
# --- plain proxying -------------------------------------------------
|
|
r = t.http(origin + "/echo", proxy=open_proxy)
|
|
t.eq(200, r.status, "a GET through the proxy")
|
|
t.contains(r, "path=/echo", "the origin sees the proxied path")
|
|
t.contains(r, "peer.addr=127.0.0.1", "the origin sees the proxy as the peer")
|
|
|
|
t.eq(10000, t.http(origin + "/data?size=10000", proxy=open_proxy).length,
|
|
"a sized body survives proxying")
|
|
t.eq(10000,
|
|
t.http(origin + "/data?size=10000&chunked=1", proxy=open_proxy).length,
|
|
"a chunked body survives proxying")
|
|
t.eq(503, t.http(origin + "/data?size=5&status=503", proxy=open_proxy).status,
|
|
"the origin status is relayed")
|
|
|
|
# --- POST and keep-alive ---------------------------------------------
|
|
r = t.http(origin + "/echo", proxy=open_proxy, method="POST", body="x=1")
|
|
t.contains(r, "method=POST", "POST is proxied")
|
|
|
|
# two requests on one connection, which may carry different methods
|
|
conn = t.connection("127.0.0.1", srv, proxy=open_proxy)
|
|
try:
|
|
first = t.http(origin + "/echo", proxy=open_proxy, method="POST",
|
|
body="x=1", conn=conn)
|
|
second_reply = t.http(origin + "/echo", proxy=open_proxy, conn=conn)
|
|
t.eq((200, 200), (first.status, second_reply.status),
|
|
"two requests on one proxied connection")
|
|
finally:
|
|
conn.close()
|
|
|
|
# --- CONNECT ----------------------------------------------------------
|
|
t.eq(200, t.http(origin + "/echo", proxy=open_proxy, tunnel=True).status,
|
|
"CONNECT tunnels to the origin")
|
|
|
|
# --- access control ----------------------------------------------------
|
|
denying = f"127.0.0.1:{deny}"
|
|
t.eq(200, t.http(origin + "/echo", proxy=denying).status,
|
|
"the permitted destination is reachable")
|
|
t.ne(200, t.http(second + "/echo", proxy=denying).status,
|
|
"a destination outside the rules is refused")
|
|
t.ne(200, t.http(second + "/echo", proxy=denying, tunnel=True).status,
|
|
"CONNECT to a destination outside the rules is refused")
|
|
# the open proxy still reaches it, so the refusal came from the rules
|
|
t.eq(200, t.http(second + "/echo", proxy=open_proxy).status,
|
|
"the same destination is reachable through the open proxy")
|
|
|
|
# --- proxy authentication -----------------------------------------------
|
|
needs_auth = f"127.0.0.1:{auth}"
|
|
t.eq(407, t.http(origin + "/echo", proxy=needs_auth).status,
|
|
"the proxy demands credentials")
|
|
t.eq(200, t.http(origin + "/echo", proxy=needs_auth,
|
|
proxy_auth=("alice", "secret")).status,
|
|
"valid proxy credentials pass")
|
|
t.eq(407, t.http(origin + "/echo", proxy=needs_auth,
|
|
proxy_auth=("alice", "wrong")).status,
|
|
"wrong proxy credentials are refused")
|