diff options
| author | Agando <roduccomm@gmail.com> | 2026-10-02 21:25:46 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-10-02 21:25:46 +0200 |
| commit | 6a0cb8cc84ad2cf9bf17d008823d07e5958c6e0a (patch) | |
| tree | 05994acc3e40422157469d06c0108f7b8c136d03 /modules/ext/webdav.js | |
| parent | 9a81c96b5a3941898f99665335ad679ff2105666 (diff) | |
newOS4 v4.6.18: nginx dav trailing-slash semantics
Discovered by dav-health-check.sh E2E (10/10 pass now):
- nginx dav module REQUIRES trailing slash on MKCOL (no-slash → 409)
and on directory DELETE (no-slash → 409/404); existing dir + slash
MKCOL → 405 (the real 'already exists' signal)
- _normalizeRemotePath now PRESERVES trailing slashes (collection ops)
- _ensureDir MKCOLs with trailing slash
- _deleteFile retries with slash on 409/404 (collection delete)
- health-check expectations corrected (405 = existing, slash required)
Diffstat (limited to 'modules/ext/webdav.js')
| -rw-r--r-- | modules/ext/webdav.js | 24 |
1 files changed, 20 insertions, 4 deletions
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() { |