Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions httpserver/httpserver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# /// zerodep
# version = "0.1.0"
# version = "0.1.1"
# deps = []
# tier = "subsystem"
# category = "network"
Expand Down Expand Up @@ -299,9 +299,10 @@ def __init__(
class StreamingResponse:
"""HTTP response streamed from an async generator.

Writes chunks using ``Transfer-Encoding: chunked`` unless
``content_type`` is ``text/event-stream`` (SSE), in which case raw
bytes are flushed directly for maximum compatibility with SSE clients.
All streaming responses use ``Transfer-Encoding: chunked`` for
maximum compatibility with reverse proxies and intermediaries.
SSE (``text/event-stream``) responses additionally set
``Cache-Control: no-cache``.

Args:
generator: Async iterator yielding ``bytes`` or ``str`` chunks.
Expand Down Expand Up @@ -330,9 +331,8 @@ async def _write(self, writer: asyncio.StreamWriter) -> None:
is_sse = self.content_type.startswith("text/event-stream")

self.headers["Content-Type"] = self.content_type
if not is_sse:
self.headers.setdefault("Transfer-Encoding", "chunked")
else:
self.headers.setdefault("Transfer-Encoding", "chunked")
if is_sse:
self.headers.setdefault("Cache-Control", "no-cache")
self.headers.setdefault("Date", _http_date())
self.headers.setdefault("Connection", "close")
Expand All @@ -349,16 +349,12 @@ async def _write(self, writer: asyncio.StreamWriter) -> None:
async for chunk in self._generator:
if isinstance(chunk, str):
chunk = chunk.encode("utf-8")
if is_sse:
writer.write(chunk)
else:
writer.write(f"{len(chunk):x}\r\n".encode("latin-1"))
writer.write(chunk)
writer.write(b"\r\n")
await writer.drain()
if not is_sse:
writer.write(b"0\r\n\r\n")
writer.write(f"{len(chunk):x}\r\n".encode("latin-1"))
writer.write(chunk)
writer.write(b"\r\n")
await writer.drain()
writer.write(b"0\r\n\r\n")
await writer.drain()
except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError):
logger.debug("Client disconnected during streaming")
finally:
Expand Down
10 changes: 5 additions & 5 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1",
"generated": "2026-06-12T19:01:08.872115+00:00",
"generated": "2026-06-12T20:41:21.760825+00:00",
"modules": {
"a2a": {
"description": "A2A (Agent-to-Agent Protocol) - Zero-dependency Python implementation",
Expand Down Expand Up @@ -93,7 +93,7 @@
],
"tier": "subsystem",
"category": "config",
"last_updated": "2026-06-12T12:49:15-05:00",
"last_updated": "2026-06-12T14:01:49-05:00",
"content_hash": "83e2fc106c73f02bf5d239538c0e5916dcd9b2cc147bf648ae16c49ff4e5f459"
},
"depdetect": {
Expand Down Expand Up @@ -175,12 +175,12 @@
"files": [
"httpserver/httpserver.py"
],
"version": "0.1.0",
"version": "0.1.1",
"deps": [],
"tier": "subsystem",
"category": "network",
"last_updated": "2026-05-02T17:34:53+08:00",
"content_hash": "b477e97b7f4f4149ebf7911719eef117061a0efc72599ff6dc0b76b215f0492b"
"content_hash": "f168c322d56180d14759db3160ac8bcaf5a72b07895205beb9fd16270fbb0eb6"
},
"jsonrpc": {
"description": "JSON-RPC 2.0 -- Zero-dependency Python implementation",
Expand Down Expand Up @@ -215,7 +215,7 @@
"deps": [],
"tier": "simple",
"category": "serialization",
"last_updated": "2026-06-12T13:46:30-05:00",
"last_updated": "2026-06-12T14:01:49-05:00",
"content_hash": "2bfc0d657c366c2e09cfcbbd433545172989f615d67debd2ca8f55284af37ddd"
},
"llmstxt": {
Expand Down
Loading