# 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/`), хранящий данные в 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`.