v1.0.120: fix ZIP — use FormData on client, parse multipart on VM
This commit is contained in:
@@ -280,12 +280,34 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
def _handle_unzip_upload(self):
|
def _handle_unzip_upload(self):
|
||||||
"""Распаковать ZIP и загрузить каждый файл в Lucee. Только файлы из корня архива."""
|
"""Распаковать ZIP и загрузить каждый файл в Lucee. Только файлы из корня архива."""
|
||||||
import zipfile, io
|
import zipfile, io
|
||||||
|
|
||||||
|
# Читаем multipart form data
|
||||||
|
content_type = self.headers.get("Content-Type", "")
|
||||||
length = int(self.headers.get("Content-Length", 0))
|
length = int(self.headers.get("Content-Length", 0))
|
||||||
data = self.rfile.read(length)
|
body = self.rfile.read(length)
|
||||||
|
|
||||||
|
# Извлекаем ZIP из multipart
|
||||||
|
boundary = content_type.split("boundary=")[1].strip()
|
||||||
|
parts = body.split(b"--" + boundary.encode())
|
||||||
|
zip_data = None
|
||||||
|
for part in parts:
|
||||||
|
if b"filename=" in part:
|
||||||
|
# Отделяем заголовки от тела
|
||||||
|
header_end = part.find(b"\r\n\r\n")
|
||||||
|
if header_end > 0:
|
||||||
|
zip_data = part[header_end+4:]
|
||||||
|
# Убираем trailing \r\n и boundary
|
||||||
|
if zip_data.endswith(b"\r\n"):
|
||||||
|
zip_data = zip_data[:-2]
|
||||||
|
break
|
||||||
|
|
||||||
|
if not zip_data:
|
||||||
|
self.send_error(400, "no file in request")
|
||||||
|
return
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
try:
|
try:
|
||||||
with zipfile.ZipFile(io.BytesIO(data)) as zf:
|
with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
||||||
for name in zf.namelist():
|
for name in zf.namelist():
|
||||||
# Только файлы из корня (без папок), пропускаем директории
|
# Только файлы из корня (без папок), пропускаем директории
|
||||||
if name.endswith('/') or '/' in name:
|
if name.endswith('/') or '/' in name:
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<img src="/nubes-logo.svg" alt="Nubes">
|
<img src="/nubes-logo.svg" alt="Nubes">
|
||||||
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.119 — Lucee</span></span>
|
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.120 — Lucee</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -261,8 +261,7 @@ fileInput.addEventListener('change', async function() {
|
|||||||
try {
|
try {
|
||||||
var zipResp = await fetch(UNZIP_URL, {
|
var zipResp = await fetch(UNZIP_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: f,
|
body: (function() { var fd = new FormData(); fd.append('file', f); return fd; })()
|
||||||
headers: {'Content-Type': 'application/zip'}
|
|
||||||
});
|
});
|
||||||
var zipData = await zipResp.json();
|
var zipData = await zipResp.json();
|
||||||
if (!zipData.ok || !zipData.files) throw new Error('unzip failed');
|
if (!zipData.ok || !zipData.files) throw new Error('unzip failed');
|
||||||
|
|||||||
Reference in New Issue
Block a user