Files
gost/tests/e2e/scripts/http_idle_timeout.py
ginuerzh 43724a5c40 test: add http2 handler e2e suite and tighten host-mapper + idle-timeout tests
Add tests/e2e/http2_test.go covering the http2 handler/listener/connector/dialer
end-to-end through the canonical gost-as-client pattern (8 subtests: forward,
auth, bypass, probeResist/metadata, h2 stream multiplexing). Include
testdata/http2/{server,server_auth,server_bypass,server_proberesist,client,
client_auth}.yaml. Note that h2/h2c listeners pair with the tunnel handler
and only http2 listener pairs with handler http2 (reads r/w from metadata).

Tighten TestDNSHostMapper by pointing the handler at an unreachable upstream
so unmapped names fail at the exchanger, confirming the host-mapper path was
the sole reason mapped names resolved. Fix http_idle_timeout.py to speak HTTP
through the CONNECT tunnel rather than a raw ping, matching the echo backend.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-27 20:15:31 +08:00

69 lines
2.0 KiB
Python

import socket
import sys
import time
def main():
host = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
port = int(sys.argv[2]) if len(sys.argv) > 2 else 8080
idle_timeout = int(sys.argv[3]) if len(sys.argv) > 3 else 3
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
s.connect((host, port))
# CONNECT to echo server
req = b"CONNECT tcp-echo:5678 HTTP/1.1\r\nHost: tcp-echo:5678\r\n\r\n"
s.sendall(req)
# Read 200 OK response
resp = b""
while b"\r\n\r\n" not in resp:
chunk = s.recv(4096)
if not chunk:
break
resp += chunk
if b"200" not in resp:
print(f"FAIL: expected 200, got {resp.decode(errors='replace')}")
sys.exit(1)
# Send an HTTP GET through the CONNECT tunnel. The tunnel target
# is an HTTP echo server (BaseHTTPRequestHandler), so we must speak
# HTTP or the connection closes.
req = b"GET / HTTP/1.0\r\nHost: tcp-echo\r\n\r\n"
s.sendall(req)
data = b""
while b"hello-gost" not in data:
chunk = s.recv(4096)
if not chunk:
break
data += chunk
if b"hello-gost" not in data:
print(f"FAIL: expected hello-gost echo, got {data!r}")
sys.exit(1)
print(f"PASS: first request through tunnel succeeded")
# Wait longer than idleTimeout
wait = idle_timeout + 2
print(f"Waiting {wait}s for idle timeout...")
time.sleep(wait)
# Try to send more data — idle timeout should have closed the pipe
try:
s.sendall(b"ping-2\n")
data = s.recv(4096)
if not data:
print("PASS: connection closed after idle timeout (empty recv)")
sys.exit(0)
# Got data means the pipe is still alive
print(f"FAIL: connection still alive after idle timeout, got {data!r}")
sys.exit(1)
except (socket.timeout, ConnectionResetError, BrokenPipeError, OSError) as e:
print(f"PASS: connection closed after idle timeout: {e}")
sys.exit(0)
if __name__ == "__main__":
main()