aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/core/module-loader.js2
-rw-r--r--modules/ext/webdav.js24
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() {