cocoon/tests/http10_backend.py
xfy911 90601e0f67 fix(proxy): 修复连接池 HTTP/1.0 兼容与配置合并 bug
- proxy.c: 当后端发送 Connection: close 或关闭连接时,不再归还已关闭连接
  到池中。避免复用已关闭连接导致请求失败。
- http2.c: HTTP/2 代理检测到 HTTP/1.0 响应时默认关闭连接,不再错误归还。
- main.c: 修复 -c 配置文件与 --cert/--key 同时使用时 config_merge 的
  use-after-free 问题。先加载配置文件,再用命令行参数覆盖。
- tests/http10_backend.py: 新增 HTTP/1.0 后端模拟器,用于测试连接池兼容。
- tests/integration_test.sh: 添加 HTTP/1.0 后端兼容测试,验证两次连续请求
  均成功(第二次必须新建连接)。
2026-06-09 12:35:26 +08:00

102 lines
2.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
http10_backend.py — HTTP/1.0 后端模拟器
模拟一个 HTTP/1.0 后端,响应后发送 Connection: close 并立即关闭连接。
用于验证反向代理连接池的 HTTP/1.0 兼容性。
用法: python3 http10_backend.py <port> <directory>
"""
import sys
import socket
import os
import mimetypes
HTTP10_RESPONSE = """HTTP/1.0 200 OK
Connection: close
Content-Type: {ctype}
Content-Length: {length}
""".replace("\n", "\r\n")
HTTP10_NOT_FOUND = """HTTP/1.0 404 Not Found
Connection: close
Content-Type: text/plain
Content-Length: 13
404 Not Found
""".replace("\n", "\r\n")
def handle_client(conn, addr, doc_root):
try:
data = conn.recv(4096)
if not data:
return
# 解析请求行
lines = data.decode("utf-8", errors="replace").split("\r\n")
if not lines:
return
parts = lines[0].split()
if len(parts) < 2:
return
path = parts[1]
if path == "/":
path = "/index.html"
# 去掉路径中的前缀(如 /backend
if path.startswith("/backend"):
path = path[len("/backend"):]
if not path.startswith("/"):
path = "/" + path
# 安全路径
safe_path = os.path.normpath(os.path.join(doc_root, path.lstrip("/")))
print(f"[http10] doc_root={doc_root}, path={path}, safe_path={safe_path}", flush=True)
print(f"[http10] abspath={os.path.abspath(doc_root)}", flush=True)
print(f"[http10] exists={os.path.exists(safe_path)}, isfile={os.path.isfile(safe_path) if os.path.exists(safe_path) else False}", flush=True)
if not os.path.abspath(safe_path).startswith(os.path.abspath(doc_root)):
conn.sendall(HTTP10_NOT_FOUND.encode())
return
if os.path.exists(safe_path) and os.path.isfile(safe_path):
with open(safe_path, "rb") as f:
body = f.read()
ctype, _ = mimetypes.guess_type(safe_path)
if not ctype:
ctype = "application/octet-stream"
header = HTTP10_RESPONSE.format(ctype=ctype, length=len(body))
conn.sendall(header.encode() + body)
else:
conn.sendall(HTTP10_NOT_FOUND.encode())
except Exception as e:
print(f"[http10] 错误: {e}", file=sys.stderr)
finally:
conn.close()
def main():
if len(sys.argv) < 3:
print("用法: python3 http10_backend.py <port> <directory>", file=sys.stderr)
sys.exit(1)
port = int(sys.argv[1])
doc_root = sys.argv[2]
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("", port))
s.listen(5)
print(f"[http10] 启动于端口 {port}, 根目录: {doc_root}")
while True:
conn, addr = s.accept()
handle_client(conn, addr, doc_root)
if __name__ == "__main__":
main()