diff --git a/repro-scgi-content-type.py b/repro-scgi-content-type.py deleted file mode 100644 index 34f38d30..00000000 --- a/repro-scgi-content-type.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -"""Reproduce SCGI content-type auto-detection bug in rtorrent. - -Sends a JSON SCGI request without Content-Type header, splitting the -TCP stream so that the header arrives before the body. If the server -peeks at the body start (m_buffer[m_body]) before the body has arrived, -it reads a null byte instead of '{' and defaults to XML — causing the -JSON-RPC call to fail. - -Usage: - python3 repro-scgi-content-type.py host:port - python3 repro-scgi-content-type.py 127.0.0.1:5101 -""" - -import socket -import sys -import time - - -SCGI_HEADERS = ( - b"CONTENT_LENGTH\x00154\x00" - b"SCGI\x001\x00" -) - -JSON_BODY = ( - b'{"method":"system.listMethods","params":[],"id":1}' -) - -HEADER_LENGTH = len(SCGI_HEADERS) -HEADER_LEN_STR = str(HEADER_LENGTH).encode() - - -def send_in_chunks(host: str, port: int, chunks: list[bytes]) -> bytes: - with socket.create_connection((host, port), timeout=5) as sock: - for data in chunks: - sock.sendall(data) - time.sleep(0.05) - return sock.recv(4096) - - -def test_normal(host: str, port: int) -> bool: - """All in one segment (works either way).""" - full_request = HEADER_LEN_STR + b":" + SCGI_HEADERS + b"," + JSON_BODY - response = send_in_chunks(host, port, [full_request]) - ok = len(response) > 0 - print(f" Normal send: {'OK' if ok else 'FAIL'} (got {len(response)} bytes)") - return ok - - -def test_split_header_body(host: str, port: int) -> bool: - """Header arrives first, body second (triggers the bug).""" - chunks = [ - HEADER_LEN_STR + b":" + SCGI_HEADERS + b",", - JSON_BODY, - ] - response = send_in_chunks(host, port, chunks) - ok = len(response) > 0 - print(f" Split header/body: {'OK' if ok else 'FAIL'} (got {len(response)} bytes)") - return ok - - -def main() -> None: - if len(sys.argv) != 2: - print(__doc__) - sys.exit(1) - - addr = sys.argv[1] - if ":" in addr: - host, port_str = addr.rsplit(":", 1) - port = int(port_str) - else: - host, port = addr, 80 - - print(f"=== Reproducing SCGI content-type defer bug against {host}:{port} ===\n") - - normal_ok = test_normal(host, port) - if not normal_ok: - print("\nServer doesn't seem to be running or reachable. Aborting.") - sys.exit(1) - - split_ok = test_split_header_body(host, port) - - print() - if not split_ok: - print("RESULT: BUG CONFIRMED — JSON request fails when body arrives after header.") - print(" detect_content_type() peeked at m_buffer[m_body] which was \\0 (not '{').") - else: - print("RESULT: Bug not reproduced — server handles content-type defer correctly.") - print(f" normal={normal_ok} split_header_body={split_ok}") - - -if __name__ == "__main__": - main()