From e98bac278ec81b91cc7b1b6a7faf64296157351c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Mon, 29 Jun 2026 18:08:34 +0400 Subject: [PATCH] fix: manual multipart parser (reliable) --- deploy/convert_server.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/deploy/convert_server.py b/deploy/convert_server.py index 2658625..59d016d 100755 --- a/deploy/convert_server.py +++ b/deploy/convert_server.py @@ -223,24 +223,34 @@ class Handler(BaseHTTPRequestHandler): raw = self.rfile.read(length) ctype = self.headers.get("Content-Type", "") - # Простой multipart приём (как в upload.py) - import cgi, io as io_mod + # Простой multipart приём + import cgi, re, io as io_mod _, params = cgi.parse_header(ctype) - fs = cgi.FieldStorage( - fp=io_mod.BytesIO(raw), - environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': ctype}, - keep_blank_values=True - ) - items = fs.getlist("files") if hasattr(fs, 'getlist') else ([fs["files"]] if "files" in fs else []) + boundary = params.get("boundary", "") + if not boundary: + self._json({"ok": False, "error": "No boundary"}, 400) + return + # Ручной разбор multipart (надёжнее чем cgi.FieldStorage) + parts = raw.split(b"--" + boundary.encode()) files = [] - for item in items: - if not getattr(item, 'filename', None): + for part in parts: + if b"Content-Disposition" not in part: continue - name = os.path.basename(item.filename) + try: + hdr_end = part.index(b"\r\n\r\n") + except ValueError: + continue + hdrs = part[:hdr_end].decode("latin-1", errors="replace") + body = part[hdr_end + 4:] + if body.endswith(b"\r\n"): + body = body[:-2] + m = re.search(r'filename="([^"]*)"', hdrs) + if not m: + continue + name = os.path.basename(m.group(1)) if not name or ".." in name or "/" in name or "\\" in name: continue - data = item.file.read() - files.append((name, data, "")) + files.append((name, body, "")) if not files: self._json({"ok": False, "error": "Нет файлов"}, 400)