codex-lb 0.5.0__py3-none-any.whl → 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- app/core/middleware/request_decompression.py +80 -23
- {codex_lb-0.5.0.dist-info → codex_lb-0.5.1.dist-info}/METADATA +2 -1
- {codex_lb-0.5.0.dist-info → codex_lb-0.5.1.dist-info}/RECORD +6 -6
- {codex_lb-0.5.0.dist-info → codex_lb-0.5.1.dist-info}/WHEEL +0 -0
- {codex_lb-0.5.0.dist-info → codex_lb-0.5.1.dist-info}/entry_points.txt +0 -0
- {codex_lb-0.5.0.dist-info → codex_lb-0.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import gzip
|
|
3
4
|
import io
|
|
5
|
+
import zlib
|
|
4
6
|
from collections.abc import Awaitable, Callable
|
|
5
7
|
from typing import Protocol
|
|
6
8
|
|
|
@@ -37,6 +39,67 @@ def _read_limited(reader: _Readable, max_size: int) -> bytes:
|
|
|
37
39
|
return bytes(buffer)
|
|
38
40
|
|
|
39
41
|
|
|
42
|
+
def _decompress_gzip(data: bytes, max_size: int) -> bytes:
|
|
43
|
+
with gzip.GzipFile(fileobj=io.BytesIO(data)) as reader:
|
|
44
|
+
return _read_limited(reader, max_size)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _decompress_deflate(data: bytes, max_size: int) -> bytes:
|
|
48
|
+
decompressor = zlib.decompressobj()
|
|
49
|
+
buffer = bytearray()
|
|
50
|
+
chunk_size = 64 * 1024
|
|
51
|
+
for start in range(0, len(data), chunk_size):
|
|
52
|
+
chunk = data[start : start + chunk_size]
|
|
53
|
+
# Bound output growth to avoid oversized allocations.
|
|
54
|
+
while chunk:
|
|
55
|
+
remaining = max_size - len(buffer)
|
|
56
|
+
if remaining == 0:
|
|
57
|
+
raise _DecompressedBodyTooLarge(max_size)
|
|
58
|
+
buffer.extend(decompressor.decompress(chunk, max_length=remaining))
|
|
59
|
+
chunk = decompressor.unconsumed_tail
|
|
60
|
+
while True:
|
|
61
|
+
remaining = max_size - len(buffer)
|
|
62
|
+
if remaining == 0:
|
|
63
|
+
raise _DecompressedBodyTooLarge(max_size)
|
|
64
|
+
drained = decompressor.decompress(b"", max_length=remaining)
|
|
65
|
+
if not drained:
|
|
66
|
+
break
|
|
67
|
+
buffer.extend(drained)
|
|
68
|
+
if not decompressor.eof:
|
|
69
|
+
raise zlib.error("Incomplete deflate stream")
|
|
70
|
+
return bytes(buffer)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _decompress_zstd(data: bytes, max_size: int) -> bytes:
|
|
74
|
+
try:
|
|
75
|
+
decompressed = zstd.ZstdDecompressor().decompress(data, max_output_size=max_size)
|
|
76
|
+
if len(decompressed) > max_size:
|
|
77
|
+
raise _DecompressedBodyTooLarge(max_size)
|
|
78
|
+
return decompressed
|
|
79
|
+
except _DecompressedBodyTooLarge:
|
|
80
|
+
raise
|
|
81
|
+
except Exception:
|
|
82
|
+
with zstd.ZstdDecompressor().stream_reader(io.BytesIO(data)) as reader:
|
|
83
|
+
return _read_limited(reader, max_size)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _decompress_body(data: bytes, encodings: list[str], max_size: int) -> bytes:
|
|
87
|
+
supported = {"zstd", "gzip", "deflate", "identity"}
|
|
88
|
+
if any(encoding not in supported for encoding in encodings):
|
|
89
|
+
raise ValueError("Unsupported content-encoding")
|
|
90
|
+
result = data
|
|
91
|
+
for encoding in reversed(encodings):
|
|
92
|
+
if encoding == "zstd":
|
|
93
|
+
result = _decompress_zstd(result, max_size)
|
|
94
|
+
elif encoding == "gzip":
|
|
95
|
+
result = _decompress_gzip(result, max_size)
|
|
96
|
+
elif encoding == "deflate":
|
|
97
|
+
result = _decompress_deflate(result, max_size)
|
|
98
|
+
elif encoding == "identity":
|
|
99
|
+
continue
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
|
|
40
103
|
def _replace_request_body(request: Request, body: bytes) -> None:
|
|
41
104
|
request._body = body
|
|
42
105
|
headers: list[tuple[bytes, bytes]] = []
|
|
@@ -60,15 +123,13 @@ def add_request_decompression_middleware(app: FastAPI) -> None:
|
|
|
60
123
|
if not content_encoding:
|
|
61
124
|
return await call_next(request)
|
|
62
125
|
encodings = [enc.strip().lower() for enc in content_encoding.split(",") if enc.strip()]
|
|
63
|
-
if encodings
|
|
126
|
+
if not encodings:
|
|
64
127
|
return await call_next(request)
|
|
65
128
|
body = await request.body()
|
|
66
129
|
settings = get_settings()
|
|
67
130
|
max_size = settings.max_decompressed_body_bytes
|
|
68
131
|
try:
|
|
69
|
-
decompressed =
|
|
70
|
-
if len(decompressed) > max_size:
|
|
71
|
-
raise _DecompressedBodyTooLarge(max_size)
|
|
132
|
+
decompressed = _decompress_body(body, encodings, max_size)
|
|
72
133
|
except _DecompressedBodyTooLarge:
|
|
73
134
|
return JSONResponse(
|
|
74
135
|
status_code=413,
|
|
@@ -77,25 +138,21 @@ def add_request_decompression_middleware(app: FastAPI) -> None:
|
|
|
77
138
|
"Request body exceeds the maximum allowed size",
|
|
78
139
|
),
|
|
79
140
|
)
|
|
141
|
+
except ValueError:
|
|
142
|
+
return JSONResponse(
|
|
143
|
+
status_code=400,
|
|
144
|
+
content=dashboard_error(
|
|
145
|
+
"invalid_request",
|
|
146
|
+
"Unsupported Content-Encoding",
|
|
147
|
+
),
|
|
148
|
+
)
|
|
80
149
|
except Exception:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"payload_too_large",
|
|
89
|
-
"Request body exceeds the maximum allowed size",
|
|
90
|
-
),
|
|
91
|
-
)
|
|
92
|
-
except Exception:
|
|
93
|
-
return JSONResponse(
|
|
94
|
-
status_code=400,
|
|
95
|
-
content=dashboard_error(
|
|
96
|
-
"invalid_request",
|
|
97
|
-
"Request body is zstd-compressed but could not be decompressed",
|
|
98
|
-
),
|
|
99
|
-
)
|
|
150
|
+
return JSONResponse(
|
|
151
|
+
status_code=400,
|
|
152
|
+
content=dashboard_error(
|
|
153
|
+
"invalid_request",
|
|
154
|
+
"Request body is compressed but could not be decompressed",
|
|
155
|
+
),
|
|
156
|
+
)
|
|
100
157
|
_replace_request_body(request, decompressed)
|
|
101
158
|
return await call_next(request)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-lb
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Codex load balancer and proxy for ChatGPT accounts with usage dashboard
|
|
5
5
|
Author-email: Soju06 <qlskssk@gmail.com>
|
|
6
6
|
Maintainer-email: Soju06 <qlskssk@gmail.com>
|
|
@@ -161,6 +161,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
|
161
161
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Quack6765"><img src="https://avatars.githubusercontent.com/u/5446230?v=4?s=100" width="100px;" alt="Quack"/><br /><sub><b>Quack</b></sub></a><br /><a href="https://github.com/Soju06/codex-lb/commits?author=Quack6765" title="Code">💻</a> <a href="https://github.com/Soju06/codex-lb/issues?q=author%3AQuack6765" title="Bug reports">🐛</a> <a href="#maintenance-Quack6765" title="Maintenance">🚧</a> <a href="#design-Quack6765" title="Design">🎨</a></td>
|
|
162
162
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hhsw2015"><img src="https://avatars.githubusercontent.com/u/103614420?v=4?s=100" width="100px;" alt="Jill Kok, San Mou"/><br /><sub><b>Jill Kok, San Mou</b></sub></a><br /><a href="https://github.com/Soju06/codex-lb/commits?author=hhsw2015" title="Code">💻</a> <a href="https://github.com/Soju06/codex-lb/commits?author=hhsw2015" title="Tests">⚠️</a> <a href="#maintenance-hhsw2015" title="Maintenance">🚧</a></td>
|
|
163
163
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pcy06"><img src="https://avatars.githubusercontent.com/u/44970486?v=4?s=100" width="100px;" alt="PARK CHANYOUNG"/><br /><sub><b>PARK CHANYOUNG</b></sub></a><br /><a href="https://github.com/Soju06/codex-lb/commits?author=pcy06" title="Documentation">📖</a></td>
|
|
164
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/choi138"><img src="https://avatars.githubusercontent.com/u/84369321?v=4?s=100" width="100px;" alt="Choi138"/><br /><sub><b>Choi138</b></sub></a><br /><a href="https://github.com/Soju06/codex-lb/commits?author=choi138" title="Code">💻</a> <a href="https://github.com/Soju06/codex-lb/issues?q=author%3Achoi138" title="Bug reports">🐛</a> <a href="https://github.com/Soju06/codex-lb/commits?author=choi138" title="Tests">⚠️</a></td>
|
|
164
165
|
</tr>
|
|
165
166
|
</tbody>
|
|
166
167
|
</table>
|
|
@@ -24,7 +24,7 @@ app/core/handlers/__init__.py,sha256=iyLUtPdBMYjK0mGpyRZ8hII8hiLF5jLR2jHiSI0C2zU
|
|
|
24
24
|
app/core/handlers/exceptions.py,sha256=edNaaPSPweBUSIpBUjV3GWKVTQkARngQV4Oe32p32tI,1453
|
|
25
25
|
app/core/middleware/__init__.py,sha256=3u3ibH0TTkvMjpN7tDu2phDBdTsssSFsyDJPAhq0Um0,372
|
|
26
26
|
app/core/middleware/api_errors.py,sha256=W5FpmbWiQ2rGfNCOHUums_Es7Qz7ktzCNONdj27k2Ps,1046
|
|
27
|
-
app/core/middleware/request_decompression.py,sha256=
|
|
27
|
+
app/core/middleware/request_decompression.py,sha256=8qwpXVWlLGijhtLMBWfcq9sRrKwEHI3wxqah0BghNFY,5572
|
|
28
28
|
app/core/middleware/request_id.py,sha256=f2CMCTy9HbHM_QfWs-EvqIAOHxLhuuC5Sd13ecUKrpc,924
|
|
29
29
|
app/core/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
app/core/openai/chat_requests.py,sha256=M1Mfu4_WNb5f5PXg4-SMjMWGtI1gkhweIfa1ENANz3k,6787
|
|
@@ -101,8 +101,8 @@ app/modules/usage/updater.py,sha256=TUFLIjIe8c0m06bnO6iumzAyFuMED3B1ry3Ty5o8JRo,
|
|
|
101
101
|
app/static/index.css,sha256=4EcLWTHAkhbqldi9fE1Y_bQCtmJuXUgEs0JHV-KmV9w,31757
|
|
102
102
|
app/static/index.html,sha256=g1U2AlbvGChev5KIyPoVI5TJ3dnvEOqoAot1tENvQOs,39799
|
|
103
103
|
app/static/index.js,sha256=q-IXWQURYksd-i68yXwyqBazs-AYiz3Tvk5t_B6NbSY,69750
|
|
104
|
-
codex_lb-0.5.
|
|
105
|
-
codex_lb-0.5.
|
|
106
|
-
codex_lb-0.5.
|
|
107
|
-
codex_lb-0.5.
|
|
108
|
-
codex_lb-0.5.
|
|
104
|
+
codex_lb-0.5.1.dist-info/METADATA,sha256=XuzL3i-rYS2lIxLr9XJ_XzHN7mcQSyF2qFBBoofJSew,7857
|
|
105
|
+
codex_lb-0.5.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
106
|
+
codex_lb-0.5.1.dist-info/entry_points.txt,sha256=SEa5T6Uz2Fhy574No6Y0XyGmYi3PXLrhu2xStJTqyI8,42
|
|
107
|
+
codex_lb-0.5.1.dist-info/licenses/LICENSE,sha256=cHPibxiL0TXwrUX_kNY6ym544EX1UCzKhxdaca5cFuk,1062
|
|
108
|
+
codex_lb-0.5.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|