mirror of
https://github.com/masterking32/MasterHttpRelayVPN.git
synced 2026-05-17 21:24:37 +03:00
Enhance error handling and add size limits for request and response bodies
This commit is contained in:
+10
-1
@@ -1107,7 +1107,10 @@ class DomainFronter:
|
||||
data = json.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
m = re.search(r'\{.*\}', text, re.DOTALL)
|
||||
data = json.loads(m.group()) if m else None
|
||||
try:
|
||||
data = json.loads(m.group()) if m else None
|
||||
except json.JSONDecodeError:
|
||||
data = None
|
||||
if not data:
|
||||
raise RuntimeError(f"Bad batch response: {text[:200]}")
|
||||
|
||||
@@ -1131,6 +1134,8 @@ class DomainFronter:
|
||||
"""Read one HTTP response. Keep-alive safe (no read-until-EOF)."""
|
||||
raw = b""
|
||||
while b"\r\n\r\n" not in raw:
|
||||
if len(raw) > 65536: # 64 KB header size limit
|
||||
return 0, {}, b""
|
||||
chunk = await asyncio.wait_for(reader.read(8192), timeout=8)
|
||||
if not chunk:
|
||||
break
|
||||
@@ -1190,6 +1195,7 @@ class DomainFronter:
|
||||
async def _read_chunked(self, reader, buf=b""):
|
||||
"""Incrementally read chunked transfer-encoding."""
|
||||
result = b""
|
||||
_MAX_BODY = 200 * 1024 * 1024 # 200 MB total body cap
|
||||
while True:
|
||||
while b"\r\n" not in buf:
|
||||
data = await asyncio.wait_for(reader.read(8192), timeout=20)
|
||||
@@ -1209,6 +1215,9 @@ class DomainFronter:
|
||||
break
|
||||
if size == 0:
|
||||
break
|
||||
if size > _MAX_BODY or len(result) + size > _MAX_BODY:
|
||||
log.warning("Chunked body exceeds %d MB cap — truncating", _MAX_BODY // (1024 * 1024))
|
||||
break
|
||||
|
||||
while len(buf) < size + 2:
|
||||
data = await asyncio.wait_for(reader.read(65536), timeout=20)
|
||||
|
||||
+14
-4
@@ -385,8 +385,14 @@ class ProxyServer:
|
||||
# ── CONNECT (HTTPS tunnelling) ────────────────────────────────
|
||||
|
||||
async def _do_connect(self, target: str, reader, writer):
|
||||
host, _, port = target.rpartition(":")
|
||||
port = int(port) if port else 443
|
||||
host, _, port_str = target.rpartition(":")
|
||||
try:
|
||||
port = int(port_str) if port_str else 443
|
||||
except ValueError:
|
||||
log.warning("CONNECT invalid target: %r", target)
|
||||
writer.write(b"HTTP/1.1 400 Bad Request\r\n\r\n")
|
||||
await writer.drain()
|
||||
return
|
||||
if not host:
|
||||
host, port = target, 443
|
||||
|
||||
@@ -801,6 +807,8 @@ class ProxyServer:
|
||||
for raw_line in header_block.split(b"\r\n"):
|
||||
if raw_line.lower().startswith(b"content-length:"):
|
||||
length = int(raw_line.split(b":", 1)[1].strip())
|
||||
if length > 100 * 1024 * 1024: # 100 MB cap
|
||||
raise ValueError(f"Request body too large: {length} bytes")
|
||||
body = await reader.readexactly(length)
|
||||
break
|
||||
|
||||
@@ -1010,6 +1018,10 @@ class ProxyServer:
|
||||
for raw_line in header_block.split(b"\r\n"):
|
||||
if raw_line.lower().startswith(b"content-length:"):
|
||||
length = int(raw_line.split(b":", 1)[1].strip())
|
||||
if length > 100 * 1024 * 1024: # 100 MB cap
|
||||
writer.write(b"HTTP/1.1 413 Content Too Large\r\n\r\n")
|
||||
await writer.drain()
|
||||
return
|
||||
body = await reader.readexactly(length)
|
||||
break
|
||||
|
||||
@@ -1082,8 +1094,6 @@ class ProxyServer:
|
||||
to the target host and pipes raw HTTP through it.
|
||||
Much faster for rapid-fire requests (e.g., Telegram API).
|
||||
"""
|
||||
import re as _re
|
||||
|
||||
# Parse target host:port from the raw HTTP request
|
||||
host = ""
|
||||
port = 80
|
||||
|
||||
Reference in New Issue
Block a user