- Introduced a new `webdav-component` package for WebDAV protocol handling. - Implemented `webdav.ts` with functions for managing WebDAV operations such as listing directories, checking file existence, creating folders, deleting paths, moving files, and handling file uploads/downloads. - Added path normalization and utility functions for handling WebDAV paths. - Enhanced the `Tag` class in `webdav3.py` to correctly register XML namespaces, improving compatibility with WebDAV responses.
76 lines
2.9 KiB
JavaScript
76 lines
2.9 KiB
JavaScript
import { stripHostPrefix } from '../utils/url.js';
|
|
/**
|
|
* Parse a PROPFIND `multistatus` XML document into a listing keyed by name.
|
|
* The entry whose URI matches the requested URL is keyed as `.` (the current
|
|
* collection).
|
|
*/
|
|
export function parsePropfindListing(xml, ctx) {
|
|
const files = {};
|
|
const compareUrl = ctx.url.replace(/\/+$/, '');
|
|
xml.querySelectorAll('response').forEach((node) => {
|
|
const href = node.querySelector('href');
|
|
if (!href || !href.textContent) {
|
|
return;
|
|
}
|
|
const itemUri = href.textContent;
|
|
const compareItemUri = itemUri.replace(/\/+$/, '');
|
|
// Find the first 200 propstat; ignore 404s etc.
|
|
let propsNode = null;
|
|
node.querySelectorAll('propstat').forEach((propstat) => {
|
|
if (propsNode) {
|
|
return;
|
|
}
|
|
const status = propstat.querySelector('status');
|
|
if (status && /200/.test(status.textContent || '')) {
|
|
propsNode = propstat;
|
|
}
|
|
});
|
|
if (!propsNode) {
|
|
console.error('Cannot find properties for: ' + itemUri);
|
|
return;
|
|
}
|
|
// Alias for narrow-friendly access below.
|
|
const props = propsNode;
|
|
// Displayname falls back to the last path segment.
|
|
let name = itemUri.replace(/\/$/, '').split('/').pop() || '';
|
|
try {
|
|
name = decodeURIComponent(name);
|
|
}
|
|
catch {
|
|
// leave name as-is on malformed encoding
|
|
}
|
|
const displayname = props.querySelector('displayname');
|
|
if (displayname && displayname.textContent) {
|
|
name = displayname.textContent;
|
|
}
|
|
// Some servers (e.g. lighttpd) prefix each name with the hostname.
|
|
let host = null;
|
|
try {
|
|
host = new URL(ctx.baseUrl).hostname;
|
|
}
|
|
catch {
|
|
host = null;
|
|
}
|
|
name = stripHostPrefix(name, host);
|
|
const isDir = !!node.querySelector('resourcetype collection');
|
|
const lengthEl = props.querySelector('getcontentlength');
|
|
const mimeEl = props.querySelector('getcontenttype');
|
|
const modifiedEl = props.querySelector('getlastmodified');
|
|
const permsEl = props.querySelector('permissions');
|
|
const entry = {
|
|
uri: itemUri,
|
|
url: itemUri,
|
|
path: itemUri.substring(ctx.baseUrl.length),
|
|
name,
|
|
size: !isDir && lengthEl?.textContent ? parseInt(lengthEl.textContent, 10) : null,
|
|
mime: !isDir && mimeEl?.textContent ? mimeEl.textContent : null,
|
|
modified: modifiedEl?.textContent ? new Date(modifiedEl.textContent) : null,
|
|
isDir,
|
|
permissions: permsEl?.textContent ? permsEl.textContent : null,
|
|
};
|
|
const key = compareItemUri === compareUrl ? '.' : name;
|
|
files[key] = entry;
|
|
});
|
|
return files;
|
|
}
|
|
//# sourceMappingURL=parse.js.map
|