-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
76 lines (59 loc) · 2.45 KB
/
server.py
File metadata and controls
76 lines (59 loc) · 2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
"""
Server that sends zstd-compressed HTTP responses where each chunk
is a complete, independent zstd frame.
This is valid HTTP but exposes a bug in httpx's ZStandardDecoder.
"""
import zstandard as zstd
from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
import time
class ZstdChunkedHandler(BaseHTTPRequestHandler):
"""Handler that sends multiple zstd frames as separate HTTP chunks."""
def do_GET(self):
if self.path == "/zstd-chunks":
self.send_zstd_chunked_response()
else:
self.send_error(404)
def send_zstd_chunked_response(self):
# Send headers
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Transfer-Encoding", "chunked")
self.send_header("Content-Encoding", "zstd")
self.end_headers()
# Create chunks of data, each compressed as a COMPLETE zstd frame
messages = [
b"First chunk of data - this is a complete zstd frame",
b"Second chunk of data - another independent zstd frame",
b"Third chunk of data - yet another independent zstd frame",
]
cctx = zstd.ZstdCompressor()
for msg in messages:
# Each message is compressed as its own complete zstd frame
# This is the key: each chunk is INDEPENDENT, not a continuous stream
compressed = cctx.compress(msg)
# Send as HTTP chunk: size in hex, \r\n, data, \r\n
chunk_size = len(compressed)
self.wfile.write(f"{chunk_size:x}\r\n".encode())
self.wfile.write(compressed)
self.wfile.write(b"\r\n")
self.wfile.flush()
print(f"Sent chunk: {chunk_size} bytes compressed, {len(msg)} bytes original")
# Small delay to ensure chunks are received separately
time.sleep(0.1)
# Send final empty chunk to signal end of response
self.wfile.write(b"0\r\n\r\n")
self.wfile.flush()
print("Response complete")
def log_message(self, format, *args):
# Suppress default logging
pass
def run_server(port=8765):
server = HTTPServer(("127.0.0.1", port), ZstdChunkedHandler)
print(f"Server running on http://127.0.0.1:{port}")
print("Endpoints:")
print(f" GET http://127.0.0.1:{port}/zstd-chunks - Sends zstd chunked response")
print()
server.serve_forever()
if __name__ == "__main__":
run_server()