80 lines
2.6 KiB
Markdown
80 lines
2.6 KiB
Markdown
# Sonnet Analysis — ZIP Upload CORS + Multipart
|
|
|
|
Дата: 2026-06-23 | Источник: Sonnet (новый чат)
|
|
Связано: index.cfm, convert_server.py, nginx-contracts.conf
|
|
|
|
---
|
|
|
|
## Текущее состояние
|
|
|
|
- JS на `contractor.luceek8s.dev.nubes.ru` шлёт FormData через fetch на `contracts.kube5s.ru/unzip-upload`
|
|
- VM (Python, 8766) парсит multipart через `email.parser.BytesParser`
|
|
- Nginx проксирует `/unzip-upload` → VM:8766
|
|
- CURL работает, браузер — `Failed to fetch`
|
|
|
|
## Диагноз Sonnet
|
|
|
|
### 1. CORS в nginx — add_header внутри if не работает
|
|
|
|
`add_header` в родительском `location` не применяется к ответу из `if (...) { return 200; }` — это новый контекст.
|
|
|
|
**Исправление:** заголовки внутрь `if`:
|
|
|
|
```nginx
|
|
location /unzip-upload {
|
|
if ($request_method = OPTIONS) {
|
|
add_header Access-Control-Allow-Origin "*";
|
|
add_header Access-Control-Allow-Methods "POST, OPTIONS";
|
|
add_header Access-Control-Allow-Headers "*";
|
|
add_header Content-Length 0;
|
|
return 204;
|
|
}
|
|
add_header Access-Control-Allow-Origin "*";
|
|
proxy_pass http://127.0.0.1:8766;
|
|
client_max_body_size 100m;
|
|
}
|
|
```
|
|
|
|
### 2. Multipart парсинг — filename*= кодировка
|
|
|
|
Браузер для файлов с не-ASCII именами использует `filename*=UTF-8''...` (RFC 5987). `part.get_filename()` может вернуть None.
|
|
|
|
**Решение:** переход на raw binary (п.3) устраняет проблему полностью.
|
|
|
|
### 3. Raw binary — лучший вариант
|
|
|
|
**JS:**
|
|
```javascript
|
|
var zipResp = await fetch(UNZIP_URL, {
|
|
method: 'POST',
|
|
body: f,
|
|
headers: { 'Content-Type': 'application/zip' }
|
|
});
|
|
```
|
|
|
|
**Python:**
|
|
```python
|
|
if "multipart" in content_type:
|
|
# fallback для curl
|
|
...
|
|
else:
|
|
zip_data = self.rfile.read(length)
|
|
```
|
|
|
|
**Плюсы:**
|
|
- Нет multipart overhead
|
|
- Нет проблем с filename-кодировкой
|
|
- Нет проблем с boundary
|
|
|
|
**Минусы:**
|
|
- Нужен правильный CORS preflight (Content-Type: application/zip — не simple)
|
|
- Нужен `client_max_body_size` в nginx
|
|
|
|
## План реализации (когда «делай»)
|
|
|
|
1. nginx: перенести CORS-заголовки внутрь `if`-блока
|
|
2. JS: `fetch(UNZIP_URL, { method: 'POST', body: f, headers: {'Content-Type': 'application/zip'} })`
|
|
3. VM: raw binary как основной путь, multipart как fallback
|
|
4. Убрать FormData из JS
|
|
5. Bump, пуш, синк VM + nginx
|