diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/core/module-loader.js | 2 | ||||
| -rw-r--r-- | modules/ext/webdav.js | 24 |
2 files changed, 21 insertions, 5 deletions
diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index 16723ad..ef3e2ee 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -4,7 +4,7 @@ // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. - const LATEST_VER = 'v4.6.16'; + const LATEST_VER = 'v4.6.18'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { diff --git a/modules/ext/webdav.js b/modules/ext/webdav.js index 5bcc4ee..e989ac9 100644 --- a/modules/ext/webdav.js +++ b/modules/ext/webdav.js @@ -194,14 +194,19 @@ class WebDAVModule { } p = p.split('?')[0].split('#')[0]; if (!p.startsWith('/')) p = '/' + p; - // Collapse duplicate slashes and resolve '..' / '.' segments + // Collapse duplicate slashes and resolve '..' / '.' segments. + // PRESERVE a trailing slash — nginx's dav module needs it for + // collection operations (MKCOL/DELETE on directories). + const trailing = /\/+$/.test(p); const out = []; for (const seg of p.split('/')) { if (seg === '' || seg === '.') continue; if (seg === '..') { out.pop(); continue; } out.push(seg); } - return '/' + out.join('/'); + let res = '/' + out.join('/'); + if (trailing && res !== '/') res += '/'; + return res; } _absoluteUrl(remotePath) { @@ -414,7 +419,10 @@ class WebDAVModule { for (let i = deepest; i < segments.length; i++) { current += '/' + segments[i]; try { - const attempt = await this._webdavRequest('MKCOL', current); + // nginx dav requires a TRAILING SLASH on MKCOL for the + // collection itself (no-slash → 409 'conflict'). Verified + // live 2026-10-02: no-slash 409, with-slash 201. + const attempt = await this._webdavRequest('MKCOL', current + '/'); if (attempt.ok || attempt.status === 405 || attempt.status === 301 || attempt.status === 302) created = true; } catch (e) { /* ignore — component may exist */ } } @@ -422,8 +430,16 @@ class WebDAVModule { } async _deleteFile(remotePath) { + const p = this._normalizeRemotePath(remotePath); const resp = await this._webdavRequest('DELETE', remotePath); - return resp.ok || resp.status === 204 || resp.status === 404; + if (resp.ok || resp.status === 204 || resp.status === 404) return true; + // nginx dav needs a trailing slash to delete a COLLECTION; a no-slash + // DELETE on a directory returns 409/404. Retry with slash. + if ((resp.status === 409 || resp.status === 404) && !p.endsWith('/')) { + const retry = await this._webdavRequest('DELETE', p + '/'); + return retry.ok || retry.status === 204 || retry.status === 404; + } + return false; } async _cleanupRetention() { |