"""W41 回归用的窄代理:HTTP 全放行,只把 /ws/chat 掐掉。 用途:模拟「WS 断了但 HTTP 通」——W41 三级阶梯应该在这种情况下 探测 /api/v1/health 成功、回落 POST /api/v1/chat 把消息发出去。 仅本机开发用;这个文件**在 git 里**(`devtools/ws-block-proxy/`),不再放 `app/build/`—— 那里被 gitignore,一次 `gradlew clean` 就把它扫没了。用法见同目录的 README.md。 用法:python ws_block_proxy.py """ import http.client import socketserver import sys LISTEN = int(sys.argv[1]) TARGET = int(sys.argv[2]) BLOCK = "/ws/chat" HOP_BY_HOP = { "connection", "keep-alive", "proxy-authenticate", "proxy-authorization", "te", "trailers", "transfer-encoding", "upgrade", } class Handler(socketserver.BaseRequestHandler): def handle(self): self.request.settimeout(30) buf = b"" while b"\r\n\r\n" not in buf: chunk = self.request.recv(4096) if not chunk: return buf += chunk head, _, rest = buf.partition(b"\r\n\r\n") lines = head.decode("latin-1").split("\r\n") method, path, _ = lines[0].split(" ", 2) if path.split("?")[0] == BLOCK: body = b"ws blocked by test proxy" self.request.sendall( b"HTTP/1.1 503 Service Unavailable\r\n" b"Content-Type: text/plain\r\n" b"Content-Length: " + str(len(body)).encode() + b"\r\n\r\n" + body ) print("BLOCKED %s %s" % (method, path), flush=True) return headers = {} for line in lines[1:]: k, _, v = line.partition(":") if k.lower() in HOP_BY_HOP: continue headers[k.strip()] = v.strip() length = int(headers.get("Content-Length") or 0) body = rest while len(body) < length: more = self.request.recv(length - len(body)) if not more: break body += more conn = http.client.HTTPConnection("127.0.0.1", TARGET, timeout=60) try: conn.request(method, path, body=body if length else None, headers=headers) resp = conn.getresponse() payload = resp.read() out = ["HTTP/1.1 %d %s" % (resp.status, resp.reason)] for k, v in resp.getheaders(): if k.lower() in HOP_BY_HOP or k.lower() == "content-length": continue out.append("%s: %s" % (k, v)) out.append("Content-Length: %d" % len(payload)) self.request.sendall(("\r\n".join(out) + "\r\n\r\n").encode("latin-1") + payload) print("PASS %s %s -> %d" % (method, path, resp.status), flush=True) except Exception as exc: # noqa: BLE001 self.request.sendall(b"HTTP/1.1 502 Bad Gateway\r\nContent-Length: 0\r\n\r\n") print("ERR %s %s -> %r" % (method, path, exc), flush=True) finally: conn.close() class Server(socketserver.ThreadingTCPServer): allow_reuse_address = True daemon_threads = True if __name__ == "__main__": print("proxy %d -> 127.0.0.1:%d, blocking %s" % (LISTEN, TARGET, BLOCK), flush=True) Server(("127.0.0.1", LISTEN), Handler).serve_forever()