Convert every POST off multipart — 21 call sites across 7 tabs

A multipart POST to the plugin API hangs and never completes on this host: no
status code, and no server-side trace of any kind. The correlation was exact —
every page using URLSearchParams worked, every page using FormData hung, which
is why scheduler and partnership appeared fine while docker, rsync, settings,
auth, arrs, fallback and monitor did not. URLSearchParams has the same append
API and fetch sets the urlencoded content type for it, so each site is a
one-token change with the payload logic untouched.
This commit is contained in:
Gmer4Lfe
2026-08-02 18:27:25 -04:00
parent 47110730e6
commit 76ad744581
8 changed files with 48 additions and 21 deletions
+3 -3
View File
@@ -435,7 +435,7 @@ setInterval(vvArrsLoad, 60000);
function vvArrsRefreshRemote(host) {
const btn = document.getElementById('vv-arr-rfsh-' + host);
if (btn) { btn.disabled = true; btn.textContent = '↻…'; }
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'refresh_remote');
fd.append('host', host);
fetch('/plugins/varaverk/api/arrs.php', { method: 'POST', body: fd })
@@ -452,7 +452,7 @@ function vvArrsRefreshRemote(host) {
function vvArrToggle(track, key, file) {
const on = !track.classList.contains('on');
track.classList.toggle('on', on);
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'arrs');
fd.append('changes', JSON.stringify([{ file, key, value: on ? 'true' : 'false', type: 'scalar' }]));
fetch('/plugins/varaverk/api/confform.php', { method: 'POST', body: fd })
@@ -468,7 +468,7 @@ function vvArrSaveAge() {
const fb = document.getElementById('vv-arr-age-fb');
if (!val) return;
btn.disabled = true; btn.textContent = 'Saving…'; fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'arrs');
fd.append('changes', JSON.stringify([{
file: 'master.conf', key: 'ARR_IMPORT_RECOVERY_AGE', value: val, type: 'scalar'
+1 -1
View File
@@ -297,7 +297,7 @@ function _get(action, cb) {
}
function _post(params, cb) {
const fd = new FormData();
const fd = new URLSearchParams();
for (const [k, v] of Object.entries(params)) fd.append(k, v);
fetch(API, { method: 'POST', body: fd })
.then(r => r.json()).then(cb)
+2 -2
View File
@@ -143,7 +143,7 @@ let _popTarget = null;
// ── API ───────────────────────────────────────────────────────────────────────
function _api(params, cb) {
const fd = new FormData();
const fd = new URLSearchParams();
for (const [k,v] of Object.entries(params)) fd.append(k, v);
fetch('/plugins/varaverk/api/docker.php', {method:'POST', body:fd})
.then(r => r.json()).then(cb)
@@ -310,7 +310,7 @@ function _render(data) {
let _activeJobs = {}; // { ctrName: intervalId }
function _actApi(params, cb) {
const fd = new FormData();
const fd = new URLSearchParams();
for (const [k, v] of Object.entries(params)) fd.append(k, v);
fetch('/plugins/varaverk/api/docker_action.php', {method: 'POST', body: fd})
.then(r => r.json()).then(cb)
+2 -2
View File
@@ -398,7 +398,7 @@ function vvFbLoad() {
window.vvFbToggle = function(track, key) {
const on = !track.classList.contains('on');
track.classList.toggle('on', on);
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'fallback');
fd.append('changes', JSON.stringify([{ file: 'master.conf', key, value: on ? 'true' : 'false', type: 'scalar' }]));
fetch('/plugins/varaverk/api/confform.php', { method: 'POST', body: fd })
@@ -423,7 +423,7 @@ window.vvFbSaveSettings = function() {
}
btn.disabled = true; btn.textContent = 'Saving…'; fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'fallback');
fd.append('changes', JSON.stringify([
{ file: 'master.conf', key: 'FALLBACK_CHECK_INTERVAL', value: String(interval), type: 'scalar' },
+2 -2
View File
@@ -612,7 +612,7 @@ function vvWdRsyncToggle(el) {
el.style.color = on ? '#4caf50' : '#333';
el.style.background = on ? '#0f1a0f' : '#111';
el.style.borderColor = on ? '#1a3a1a' : '#222';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('name', flag);
fd.append('enabled', on ? '1' : '0');
fetch('/plugins/varaverk/api/flag_toggle.php', { method: 'POST', body: fd })
@@ -2229,7 +2229,7 @@ function vvDockerAction(action, name, webui) {
encodeURIComponent('/boot/config/plugins/dockerMan/templates-user/my-' + name + '.xml') + '&update=true';
return;
}
const fd = new FormData();
const fd = new URLSearchParams();
fd.set('action', action);
fd.set('name', name);
fetch('/plugins/varaverk/api/docker_action.php', { method: 'POST', body: fd })
+7 -7
View File
@@ -1004,7 +1004,7 @@ function vvRyWinSave(key) {
if (btn) { btn.disabled = true; btn.textContent = 'Saving…'; }
if (fb) fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'save');
fd.append('win_key', key);
fd.append('scripts', JSON.stringify(state.scripts));
@@ -1247,7 +1247,7 @@ function _vvRyLoadProfiles(key) {
function vvRyToggle(trackEl, name) {
const on = !trackEl.classList.contains('on');
trackEl.classList.toggle('on', on);
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('name', name);
fd.append('enabled', on ? '1' : '0');
fetch('/plugins/varaverk/api/flag_toggle.php', { method: 'POST', body: fd })
@@ -1269,7 +1269,7 @@ function vvRySaveDefaults() {
btn.disabled = true;
btn.textContent = 'Saving…';
fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'rsync');
fd.append('changes', JSON.stringify(changes));
fetch('/plugins/varaverk/api/confform.php', { method: 'POST', body: fd })
@@ -1441,7 +1441,7 @@ function vvRpSave() {
const btn = document.querySelector('#vv-rp-card .vv-ry-save-btn');
btn.disabled = true; btn.textContent = 'Saving…'; fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'save');
fd.append('name', name);
fd.append('rsync_opts', document.getElementById('vv-rp-rsync_opts')?.value?.trim() || '');
@@ -1478,7 +1478,7 @@ function vvRpDelete() {
const del = document.getElementById('vv-rp-del-btn');
del.disabled = true; fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'delete');
fd.append('name', name);
@@ -1521,7 +1521,7 @@ function vvMsStop() {
if (!token) return;
const btn = document.getElementById('vv-ms-stop-btn');
btn.textContent = '⟳ Stopping…'; btn.disabled = true;
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'stop');
fd.append('token', token);
fetch('/plugins/varaverk/api/manual_sync.php', { method: 'POST', body: fd })
@@ -1768,7 +1768,7 @@ function vvMsRun() {
badge.style.color = '#4a9eff';
badge.style.border = '1px solid #1a3a5a';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'run');
fd.append('local', local);
fd.append('host', slot);
+4 -4
View File
@@ -286,7 +286,7 @@ function vvStorMigrate() {
if (fb) fb.textContent = '';
if (out) { out.textContent = 'Starting migration…\n'; out.style.display = ''; }
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'migrate');
fd.append('to', to);
@@ -323,7 +323,7 @@ function vvNtfToggle(track, key) {
track.classList.toggle('on', on);
const file = (key === 'NOTIFY_UNRAID' || key === 'ENABLE_LOGGING') ? 'master.conf'
: '<?= htmlspecialchars($_myHost) ?>.conf';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'settings');
fd.append('changes', JSON.stringify([{ file, key, value: on ? 'true' : 'false', type: 'scalar' }]));
fetch('/plugins/varaverk/api/confform.php', { method: 'POST', body: fd })
@@ -337,7 +337,7 @@ function vvNtfSaveWebhook() {
const fb = document.getElementById('vv-ntf-fb');
const btn = document.getElementById('vv-ntf-save');
btn.disabled = true; btn.textContent = 'Saving…'; fb.textContent = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('id', 'settings');
fd.append('changes', JSON.stringify([{
file: '<?= htmlspecialchars($_myHost) ?>.conf',
@@ -400,7 +400,7 @@ function vvApiRenew() {
btn.disabled = true; btn.textContent = 'Renewing…';
fb.textContent = ''; out.textContent = ''; out.style.display = '';
const fd = new FormData();
const fd = new URLSearchParams();
fd.append('action', 'setup_apikeys');
fetch('/plugins/varaverk/api/storage.php', { method: 'POST', body: fd })
.then(r => r.json())