diff --git a/site/templates/index.html b/site/templates/index.html index bd7f151..b04bb93 100644 --- a/site/templates/index.html +++ b/site/templates/index.html @@ -363,6 +363,7 @@ async function uploadFiles() { session: currentSid, onStatus(k, html) { ss(sendIdx[k], html); }, onUploadStatus(text) { st.className = 'status progress'; st.textContent = text; }, + onXHR(xhr) { activeXHR = xhr; }, }); if (!res.ok) { st.className = 'status error'; diff --git a/upload/frontend/test_upload_frontend.mjs b/upload/frontend/test_upload_frontend.mjs index bf4b1d4..389cef5 100644 --- a/upload/frontend/test_upload_frontend.mjs +++ b/upload/frontend/test_upload_frontend.mjs @@ -18,6 +18,10 @@ import { listZipFiles } from './zip/list_zip_files.js'; import { parseZip } from './zip/parse_zip.js'; import { decodeZipName } from './zip/decode_zip_name.js'; import { addFileWithDedup } from './table/add_file_with_dedup.js'; +import { esc } from './table/esc.js'; +import { fs } from './table/fs.js'; +import { fmtSec } from './table/fmt_sec.js'; +import { estForFile } from './table/est_for_file.js'; const ALLOWED = ['.pdf', '.doc', '.docx', '.txt', '.md']; @@ -194,6 +198,33 @@ function testSuffixes() { console.log(' суффиксы _2/_3: ok'); } +function testEsc() { + assert.equal(esc('&\''), '<a href="x">&'</a>'); + console.log(' esc (XSS-экранирование): ok'); +} + +function testFs() { + assert.equal(fs(0), '0 B'); + assert.equal(fs(1023), '1023 B'); + assert.equal(fs(1024), '1.0 KB'); + assert.equal(fs(1048576), '1.0 MB'); + console.log(' fs (размер): ok'); +} + +function testFmtSec() { + assert.equal(fmtSec(0), '0с'); + assert.equal(fmtSec(59), '59с'); + assert.equal(fmtSec(60), '1м 0с'); + assert.equal(fmtSec(125), '2м 5с'); + console.log(' fmtSec: ok'); +} + +function testEstForFile() { + assert.equal(estForFile({ size: 1048576 }, 12), 12); // 1 МБ × 12 = 12с + assert.equal(estForFile(null, 12), 0); + console.log(' estForFile: ok'); +} + // ── Прогон ── const TESTS = [ ['decodeZipName', testDecodeZipName], @@ -204,6 +235,10 @@ const TESTS = [ ['дедуп/суффиксы', testDedup], ['лимиты over', testLimits], ['суффиксы _2/_3', testSuffixes], + ['esc XSS', testEsc], + ['fs размер', testFs], + ['fmtSec', testFmtSec], + ['estForFile', testEstForFile], ]; let failed = 0; diff --git a/upload/frontend/test_upload_layer2.mjs b/upload/frontend/test_upload_layer2.mjs index f7d0409..e8a4347 100644 --- a/upload/frontend/test_upload_layer2.mjs +++ b/upload/frontend/test_upload_layer2.mjs @@ -87,6 +87,16 @@ async function testPutToVmTimeout() { console.log(' putToVm timeout: ok'); } +async function testPutToVmOnXHR() { + let registered = null; + const p = putToVm(new File(['abc'], 'a.txt'), 'https://vm/tok_0', { onXHR(x) { registered = x; } }); + assert.ok(registered, 'onXHR должен получить XHR для отмены'); + registered.status = 200; + registered.onload(); + await p; + console.log(' putToVm onXHR регистрация: ok'); +} + // ── uploadViaVM ── async function testUploadViaVMSuccess() { installFetch(() => ({ ok: true, json: async () => ({ ok: true, session: 'sid123', count: 2 }) })); @@ -172,6 +182,7 @@ const TESTS = [ ['putToVm HTTP error', testPutToVmHttpError], ['putToVm network error', testPutToVmNetworkError], ['putToVm timeout', testPutToVmTimeout], + ['putToVm onXHR', testPutToVmOnXHR], ['uploadViaVM success', testUploadViaVMSuccess], ['uploadViaVM PUT error', testUploadViaVMPutError], ['uploadViaVM POST error', testUploadViaVMPostError], diff --git a/upload/frontend/upload/put_to_vm.js b/upload/frontend/upload/put_to_vm.js index c4c3b36..5a23329 100644 --- a/upload/frontend/upload/put_to_vm.js +++ b/upload/frontend/upload/put_to_vm.js @@ -4,6 +4,7 @@ export function putToVm(file, url, options = {}) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); + if (options.onXHR) options.onXHR(xhr); // регистрация для отмены (abort) xhr.open('PUT', url); xhr.timeout = options.timeoutMs || 300000; // 300с: большие файлы xhr.upload.onprogress = function(e) { diff --git a/upload/frontend/upload/upload_via_vm.js b/upload/frontend/upload/upload_via_vm.js index b7c9b2e..f687c07 100644 --- a/upload/frontend/upload/upload_via_vm.js +++ b/upload/frontend/upload/upload_via_vm.js @@ -30,6 +30,7 @@ export async function uploadViaVM(files, vmUploadUrl, options = {}) { onProgress(pct) { if (options.onStatus) options.onStatus(k, '⏳ ' + pct + '%'); }, + onXHR: options.onXHR, }); const elapsed = (performance.now() - t0) / 1000; const speed = f.size / elapsed;