Files
upload-platform/HISTORY/2026-09-06-layer2-implementation-and-tests.md
T

70 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-09-06: Реализация и верификация Слоя 2 (пофайловый транзит через RAM)
## 1. Контекст задачи
В рамках репозитория `upload-platform` выполнена реализация Слоя 2 (транзитная доставка файлов в сессию бэкенда через внешний буфер) поверх завершённого Слоя 1 (File Picker v0.1.13) с поднятием версии платформы до `0.2.0`.
---
## 2. Ключевые архитектурные решения и реализация
### 1. Пофайловый транзит (Per-File Transit)
Вместо накопления всей пачки файлов на ВМ реализован потоковый пофайловый цикл:
1. Браузер берёт файл $k$ и отправляет его методом `PUT` в буфер на ВМ (`putToVm` через XHR со стримингом прогресса и поддержкой `AbortSignal`).
2. Браузер сразу делает `POST /api/upload_refs` только для этого одного файла $k$.
3. Бэкенд забирает файл исходящим потоковым `GET` (`httpx.stream`) прямо в оперативную память сессии (`upload/backend/session`).
4. Бэкенд немедленно отправляет `DELETE` на буфер ВМ.
5. Файл на ВМ удалён, буфер чист. Браузер переходит к файлу $k+1$.
- **Результат**: в буфере на ВМ в любой момент времени находится максимум один файл; объем потребляемой буфером памяти минимален.
### 2. Хранение строго в оперативной памяти (RAM-only)
- На бэкенде: файлы сессии хранятся в RAM-структуре `_sessions` (`upload/backend/session/state.py`). Никаких временных файлов на диске.
- Защита памяти: настраиваемые лимиты `MAX_FILE_BYTES` (по умолчанию 50 МБ) и `MAX_SESSION_BYTES` (по умолчанию 500 МБ).
- Автоматическая очистка: TTL-таймер (по умолчанию 30 мин), функции `touch`, `pause_ttl`, `resume_ttl`, `cleanup`.
### 3. Защита и параметры (Zero Hardcode & Security)
- **SSRF-защита**: `create_upload_refs_blueprint` валидирует входящие URL по префиксу `vmUploadPrefix` (поддерживаются абсолютные URL для прода и относительные для локального мока). Запросы к сторонним хостам отсекаются.
- **Path Traversal защита**: модуль `safe_name` нормализует пути, запрещает `..` и сохраняет безопасные относительные подпапки.
- **Мягкая отмена**: поддержка `AbortSignal` на фронтенде и `threading.Event` на бэкенде (`request_cancel`, `get_cancel_event`).
- **Слой 3 (эмуляция/интеграция)**: в `create_upload_refs_blueprint` добавлен колбэк `onFileReceived(sid, name, content)`, вызываемый при успешной доставке файла в RAM.
### 4. Автономный mock-буфер и тестовый стенд
- В `site/app.py` встроен in-memory mock WebDAV (`PUT`, `GET`, `DELETE` по пути `/mock-buffer/<key>`), хранящий данные в RAM.
- Позволяет запускать тесты и локальный demo-стенд на 100% автономно без доступа к внешней сети или боевой ВМ.
- В шаблоне `site/templates/index.html` добавлена панель запуска Слоя 2, отображение прогресса пофайловой передачи и просмотр файлов, сохранённых в RAM сессии.
---
## 3. Автоматическое тестирование
Создан полный набор автоматических тестов (19 тестов, 100% PASS):
1. **Бэкенд тесты (`pytest tests/ -v`, 10 тестов, 0.99s)**:
- `test_safe_name_simple` — проверка корректных путей и слэшей.
- `test_safe_name_traversal` — отсечение атак `..`, абсолютных путей, пустых строк.
- `test_session_lifecycle` — полный жизненный цикл сессии (создание, добавление, чтение, TTL, отмена, cleanup).
- `test_session_limits` — проверка ограничения суммарного размера сессии в RAM.
- `test_upload_refs_pull_and_delete` — проверка pull по исходящему GET, удаления из буфера, вызова колбэка Слоя 3.
- `test_upload_refs_ssrf_protection` — блокировка попыток pull с недоверенных хостов (SSRF).
- `test_health` — liveness-проверка платформы.
- `test_index_page` — проверка отдачи UI стенда.
- `test_mock_buffer_crud` — операции PUT, GET, DELETE и статус mock-буфера.
- `test_full_transit_flow_mock` — сквозной тест пофайлового транзита от mock-буфера до сессии Flask.
2. **Фронтенд тесты (`npm test`, `node:test`, 9 тестов, 329ms)**:
- `putToVm: успешная отправка` — проверка корректности HTTP PUT с сырым бинарным телом.
- `putToVm: ошибка HTTP статуса` — обработка ответов 4xx/5xx.
- `putToVm: сетевая ошибка` — обработка XHR onerror.
- `putToVm: таймаут` — обработка XHR ontimeout.
- `putToVm: прерывание через AbortSignal` — мгновенный abort текущего XHR.
- `uploadViaVM: пофайловый транзит` — проверка, что $N$ файлов вызывают $N$ парных запросов PUT + upload_refs последовательно, передавая `session_id`.
- `uploadViaVM: поддержка формата FilePicker.getFiles()` — совместимость со Слой 1.
- `uploadViaVM: обработка ошибки PUT` — остановка конвейера и возврат ошибки.
- `uploadViaVM: прерывание через signal` — отмена всего пофайлового цикла.
---
## 4. Версионирование и сборка
- Версия поднята с `0.1.13` до `0.2.0` в `package.json` и `site/app.py`.
- Собраны актуальные дистрибутивные бандлы `dist/file-picker.esm.js` (40.1 KB) и `dist/file-picker.iife.js` (43.4 KB).
- Документация в `README.md` и `upload/README.md` полностью обновлена с пошаговой инструкцией интеграции в `drhider` и `contractor`.