From c0c638c91750c8fb1b980c56b47ef5538595e3c1 Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 3 Aug 2026 20:08:19 +0000 Subject: [PATCH] up2k: re-hs if unknown-wark or chunk-exists; previous behavior: * when a chunk already existed on the server, it would unstitch and continue retrying each individual chunk * upon unknown-wark (file already completed), it would upload the remaining scheduled chunks before bailing the unknown-wark behavior was accidental bullshit the chunk-exists behavior was intentional, assumed optimal for preserving tcp window-scaling, just not when running behind a bufferbloating reverseproxy which may disconnect the client on a timeout before the response is delivered, and "some clients" still follow rfc2616-8.2.4 (retries the POST, wtf...) wasting bandwidth + maybe further worsening conditions "some clients" is specifically firefox with the devtools not open another firefox joke is that it doesn't read the server-response if the server does not drain the request-body; we end up in xhr.onerror with no idea why, must assume the worst new behavior: in both scenarios, drop all scheduled chunks to be uploaded and redo handshake, to as far as possible avoid retransmissions; firefox will still eagerly retry 4 times but whatever u2c was/is fine; nothing to be done depending on network conditions and physical distance, this MAY result in lower total speed, but the average case is likely a net-positive, wasting less bandwidth on retransmissions, in exchange for resetting tcp window-scaling --- copyparty/web/up2k.js | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 4ee0883a..28146593 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -998,6 +998,14 @@ function up2k_init(subtle) { }); } + function unqueue_up(t) { + t.postlist = []; + var arr = st.todo.upload; + for (var a = arr.length - 1; a >= 0; a--) + if (arr[a].nfile == t.n) + arr.splice(a, 1); + } + var pvis = new U2pvis("bz", '#u2cards', uc, st), donut = new Donut(uc, st); @@ -2631,7 +2639,7 @@ function up2k_init(subtle) { cbd.push(a == cdr_idx ? cdr_sz : chunksize); } - t.postlist = []; + unqueue_up(t); t.wark = response.wark; var missing = response.hash; for (var a = 0; a < missing.length; a++) { @@ -2920,8 +2928,7 @@ function up2k_init(subtle) { var txt = unpre((xhr.response && xhr.response.err) || xhr.responseText); if (txt.indexOf('upload blocked by x') + 1) { apop(st.busy.upload, upt); - for (var a = pcar; a <= pcdr; a++) - apop(t.postlist, a); + unqueue_up(t); pvis.seth(t.n, 1, "ERROR"); pvis.seth(t.n, 2, txt.split(/\n/)[0]); pvis.move(t.n, 'ng'); @@ -2944,8 +2951,10 @@ function up2k_init(subtle) { st.etac.u++; st.etac.t++; } - else if (txt.indexOf('already got that') + 1 || - txt.indexOf('already being written') + 1) { + else if (txt.indexOf('already got that') + 1) { + unqueue_up(t); + } + else if (txt.indexOf('already being written') + 1) { t.nojoin = t.nojoin || t.postlist.length; console.log("ignoring dupe-segment with backoff", t.nojoin, t.name, t); if (!toast.visible && st.todo.upload.length < 4) @@ -2953,6 +2962,10 @@ function up2k_init(subtle) { } else { xhrchk(xhr, L.u_cuerr2.format(snpart, Math.ceil(t.size / chunksize), esc(t.name)), "404, target folder not found (???)", "warn", t); + if (txt.indexOf('unknown wark') == 0) { + t.cooldown = t.coolmul = 0; + unqueue_up(t); + } chill(t); } orz2(xhr); @@ -2963,8 +2976,10 @@ function up2k_init(subtle) { apop(t.postlist, a); if (!t.postlist.length) { t.t_uploaded = Date.now(); - pvis.seth(t.n, 1, 'verifying'); - st.todo.handshake.unshift(t); + if (!has(st.busy.handshake, t)) { + pvis.seth(t.n, 1, 'verifying'); + st.todo.handshake.unshift(t); + } } tasker(); } @@ -2999,6 +3014,7 @@ function up2k_init(subtle) { if (!toast.visible) toast.warn(9.98, L.u_cuerr.format(snpart, Math.ceil(t.size / chunksize), esc(t.name)), t); + unqueue_up(t); // maybe unknown wark (ff drops undrained rsp) t.nojoin = t.nojoin || t.postlist.length; // maybe rproxy postsize limit console.log('chunkpit onerror,', t.name, t); orz2(xhr);