import socket, struct, threading, urllib.request, urllib.error, time
def server(mode, port_box):
    s = socket.socket(); s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(("127.0.0.1", 0)); s.listen(5); port_box.append(s.getsockname()[1])
    c, _ = s.accept()
    got = b""
    if mode in ("after_read", "close_after_read"):
        c.settimeout(2)
        while b"\r\n\r\n" not in got:
            got += c.recv(65536)
        # read body
        head, _, body = got.partition(b"\r\n\r\n")
        n = int([l.split(b":")[1] for l in head.split(b"\r\n") if l.lower().startswith(b"content-length")][0])
        while len(body) < n: body += c.recv(65536)
    if mode in ("after_read", "immediate"):
        c.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", 1, 0))
    c.close(); s.close()
    print(f"  server[{mode}] read {len(got)} bytes before closing")
def run(mode, size):
    box = []
    t = threading.Thread(target=server, args=(mode, box)); t.start()
    while not box: time.sleep(0.01)
    if mode == "immediate": time.sleep(0.2)
    req = urllib.request.Request(f"http://127.0.0.1:{box[0]}/api/seal", data=b"x"*size, method="POST")
    try:
        urllib.request.urlopen(req, timeout=3)
    except Exception as e:
        r = getattr(e, "reason", None)
        print(f"{mode:17} body={size:>8}: {type(e).__name__}" + (f"(reason {type(r).__name__})" if r is not None else ""), str(e)[:60])
    t.join()
for size in (200, 4_000_000):
    run("immediate", size)
    run("after_read", size)
    run("close_after_read", size)
# refused: a port nobody listens on
s = socket.socket(); s.bind(("127.0.0.1", 0)); p = s.getsockname()[1]; s.close()
try: urllib.request.urlopen(urllib.request.Request(f"http://127.0.0.1:{p}/", data=b"x", method="POST"), timeout=3)
except Exception as e: print("refused          :", type(e).__name__, type(getattr(e,'reason',None)).__name__)
