v1.0.134: ALL uploads through VM — /upload proxy avoids Lucee multipart crash
This commit is contained in:
@@ -62,6 +62,8 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
self._handle_llm_ops()
|
self._handle_llm_ops()
|
||||||
elif self.path == "/unzip-upload":
|
elif self.path == "/unzip-upload":
|
||||||
self._handle_unzip_upload()
|
self._handle_unzip_upload()
|
||||||
|
elif self.path == "/upload":
|
||||||
|
self._handle_upload()
|
||||||
else:
|
else:
|
||||||
self._handle_doc_convert()
|
self._handle_doc_convert()
|
||||||
|
|
||||||
@@ -277,6 +279,47 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(json.dumps({"error": str(e)}, ensure_ascii=False).encode())
|
self.wfile.write(json.dumps({"error": str(e)}, ensure_ascii=False).encode())
|
||||||
|
|
||||||
|
def _handle_upload(self):
|
||||||
|
"""Принять файл и передать в Lucee через JSON API (обходит multipart-краш Lucee)."""
|
||||||
|
from email.parser import BytesParser
|
||||||
|
|
||||||
|
content_type = self.headers.get("Content-Type", "")
|
||||||
|
length = int(self.headers.get("Content-Length", 0))
|
||||||
|
body = self.rfile.read(length)
|
||||||
|
|
||||||
|
# Парсим multipart
|
||||||
|
msg = BytesParser().parsebytes(
|
||||||
|
b"Content-Type: " + content_type.encode() + b"\r\n\r\n" + body
|
||||||
|
)
|
||||||
|
filename = None
|
||||||
|
file_data = None
|
||||||
|
if msg.is_multipart():
|
||||||
|
for part in msg.get_payload():
|
||||||
|
fn = part.get_filename()
|
||||||
|
if fn:
|
||||||
|
filename = fn
|
||||||
|
file_data = part.get_payload(decode=True)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not filename or not file_data:
|
||||||
|
self._send_error_cors(400, "no file in request")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Шлём в Lucee через JSON API (не multipart!)
|
||||||
|
resp = httpx.post(
|
||||||
|
f"{LUCEE_URL}/upload.cfm",
|
||||||
|
json={"filename": filename, "data": "\\x" + file_data.hex()},
|
||||||
|
timeout=60
|
||||||
|
)
|
||||||
|
self._send_cors()
|
||||||
|
if resp.status_code == 200:
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/json; charset=utf-8")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(resp.content)
|
||||||
|
else:
|
||||||
|
self._send_error_cors(502, f"Lucee error: {resp.status_code}")
|
||||||
|
|
||||||
def _handle_unzip_upload(self):
|
def _handle_unzip_upload(self):
|
||||||
"""Распаковать ZIP и загрузить каждый файл в Lucee. Только файлы из корня архива."""
|
"""Распаковать ZIP и загрузить каждый файл в Lucee. Только файлы из корня архива."""
|
||||||
import zipfile, io
|
import zipfile, io
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ server {
|
|||||||
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
|
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /upload {
|
||||||
|
add_header Access-Control-Allow-Origin "*";
|
||||||
|
add_header Access-Control-Allow-Methods "POST, OPTIONS";
|
||||||
|
add_header Access-Control-Allow-Headers "*";
|
||||||
|
if ($request_method = OPTIONS) { return 204; }
|
||||||
|
proxy_pass http://127.0.0.1:8766;
|
||||||
|
client_max_body_size 100m;
|
||||||
|
}
|
||||||
|
|
||||||
location /unzip-upload {
|
location /unzip-upload {
|
||||||
if ($request_method = OPTIONS) {
|
if ($request_method = OPTIONS) {
|
||||||
add_header Access-Control-Allow-Origin "*";
|
add_header Access-Control-Allow-Origin "*";
|
||||||
|
|||||||
@@ -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.133 — Lucee</span></span>
|
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.134 — Lucee</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
<script>
|
<script>
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
|
|
||||||
var UPLOAD_URL = 'https://contracts.kube5s.ru/lucee/upload.cfm';
|
var UPLOAD_URL = 'https://contracts.kube5s.ru/upload';
|
||||||
var CONVERT_URL = 'https://contracts.kube5s.ru/convert-doc';
|
var CONVERT_URL = 'https://contracts.kube5s.ru/convert-doc';
|
||||||
var UNZIP_URL = 'https://contracts.kube5s.ru/unzip-upload';
|
var UNZIP_URL = 'https://contracts.kube5s.ru/unzip-upload';
|
||||||
var SITE_URL = ''; // same origin for api calls
|
var SITE_URL = ''; // same origin for api calls
|
||||||
|
|||||||
Reference in New Issue
Block a user