Skip to content

[Enhancement]: WebDAV protocol parity and bounded streaming roadmap #421

Description

@AptS-1547

Problem

AsterDrive 当前已经具备一套面向产品存储体系的自研 WebDAV 实现:GET/HEAD 直接使用 StorageDriver::get_stream() / get_range(),PUT 已接入 storage policy、quota、dedup、审计和远端直传,LOCK、PROPFIND、PROPPATCH、COPY、MOVE、DELETE 也有较完整的产品级实现。

但当前实现与历史依赖的 dav-server 0.11.0 在协议完整度、响应内存边界、HTTP 条件请求和自动化合规验证上仍存在差距。当前差距主要集中在:

  • Range 只支持单区间,缺少 If-Range 语义和 multipart/byteranges。
  • PROPFIND 和部分 Multi-Status 响应先构造完整 XML 树再序列化,表面返回 HTTP 响应流,实际内存随目录规模增长。
  • read_dir() 当前先把一个目录的全部 folder/file 记录和 entries 收集到 Vec,下游没有真正的分页/增量读取边界。
  • OPTIONS 固定声明 DAV: 1, 2, version-control 和完整 Allow 集合,但 DeltaV 当前是最小子集,资源级能力也没有动态反映。
  • WebDAV 自动化合规基线已经建立;当前 Litmus 0.18 默认五组仅保留 fragment-bearing mutation target([Bug]: WebDAV accepts fragment-bearing request targets for destructive methods #424)这一项已知差异。Depth: infinity collection lock 的 descendant token propagation([Bug]: Depth-infinity WebDAV collection locks reject valid descendant mutations #425)修复已在本地验证,待合入;locks 40/40 通过。
  • DavFile trait 保留了通用 read/seek 形状,但 AsterDrive GET 已经绕开它,AsterDavFile::read_bytes() 实际上是写路径上的禁止操作,抽象边界已经出现分叉。

这张 issue 作为 umbrella roadmap,目标是达到 dav-server 基础 WebDAV/HTTP 行为的验证水平,同时保留 AsterDrive 对对象存储直连、Range 下推、上传策略、审计和权限作用域的优势。

Goal

完成以下目标:

  1. RFC 4918 基础行为由 Litmus 和真实客户端测试证明,而不是只依赖单元测试。
  2. HTTP 条件请求、Range、锁 token、COPY/MOVE 目标条件的行为有完整矩阵和边界测试。
  3. 大目录 PROPFIND、递归 COPY/MOVE/DELETE、Multi-Status 和多区间下载都有明确资源上界。
  4. 对外 DAV / Allow / live properties 能力声明与实际实现一致。
  5. 保持大文件 GET 走 StorageDriver::get_stream(),Range GET 走原生 StorageDriver::get_range(),不回退到完整对象临时下载。

Proposed work

Phase 0: Establish the conformance baseline

  • 固定 Litmus 0.18、Litmus/neon 源码提交和 SHA-256,通过 scripts/ci/webdav-compat/install-litmus.sh 在 Linux/macOS 使用同一入口构建。
  • 在隔离测试实例中运行 basiccopymovepropslockshttp 五组默认测试,并固定每组预期用例数。
  • 使用双向严格 baseline:未知 FAIL / SKIPPED / WARNING、过期豁免、用例数漂移和进程状态不一致都会使检查失败。
  • 将每个保留差异关联到独立子 issue,不使用无原因的长期 skip。
  • 在 CI 中保存工具版本、stdout/stderr、neon debug trace、请求日志和每组结构化 result.json
  • 把 rclone、curl、cadaver 纳入 scheduled/manual workflow,并固定版本与 SHA-256。
  • 将 WebDAV 集成测试、Litmus、真实客户端和 fixture 集中到单一 tests/webdav/ target。
  • 为 Litmus 0.18 的 largefilelockbomblockbomb-single 增加独立 ignored 测试、用例数断言和分组超时;它们保持在普通 PR 门禁之外。
  • 将 Litmus 0.18 protected 单独归类为安全实现策略探针,固定 TEST_PROTECTED=.DAV 和 25 个用例;当前结果为 10 pass / 15 policy differences,结构化记录但不进入 RFC 合规 baseline。

AsterDrive 适用性说明: dead properties 存放在数据库 entity_properties 表中,并通过解析后的 file/folder entity_type + entity_id 关联;.DAV 没有映射到内部属性数据库。产品语义上 .DAV 是合法的普通用户目录,不需要为了该套件保留或封禁。对 .DAV 的创建、读取、移动或删除只操作普通 file/folder entity,不会触达属性表、锁表或其他可信内部元数据。因此 15 项差异是与 Apache 文件式属性数据库模型的预期差异,本身不代表 dead-property storage 暴露或产品安全漏洞。webdav_block_system_files_* 只负责可配置的客户端垃圾文件策略,不承担内部元数据隔离职责。

当前 Litmus 0.18 默认五组基线:

Group Cases Current result
basic 16 Pass;保留 #424delete_fragment warning
copymove 13 Pass,无已知差异
props 33 Pass,无已知差异
locks 40 #425 修复验证后 Pass,无已知差异
http 4 Pass,无已知差异

Phase 0 期间拆出了 #423#424#425#426。当前验证中 Litmus 0.18 已不再复现 #423 / #425 / #426,其中 #425 的 tagged collection-root token 修复后 locks 40/40 通过,待代码合入;#427 继续跟踪跨 PROPFINDPROPPATCHLOCK 和 DeltaV handler 的统一 XML QName/extensibility/grammar contract,#411 继续负责 bounded XML parser/writer 实现。

Phase 1: Correct capability advertisement and HTTP preconditions

  • 将 OPTIONS 的 AllowDAVMS-Author-Via 从静态字符串改成与资源类型、启用的扩展和实际方法一致的能力集合。
  • 审计 version-control compliance token。目前 src/webdav/deltav.rs 只实现了 VERSION-CONTROLversion-tree REPORT 的最小子集;需要补齐对应 live properties / report metadata,或者在完整语义准备好前调整对外声明。
  • 实现 If-Range:支持强 ETag 和 HTTP date;匹配时保留 Range 并返回 206,不匹配时忽略 Range 并返回完整 200
  • 建立统一的条件请求矩阵,覆盖 If-MatchIf-None-MatchIf-Modified-SinceIf-Unmodified-SinceIf header 的 tagged/untagged list,以及 GET/PUT/DELETE/COPY/MOVE/LOCK refresh 的优先级。
  • 验证 ETag 的强弱比较、引号规范、304/412 响应头和错误响应的 Cache-Control 行为。

Phase 2: Range and download contract parity

  • 实现受限的 multipart multi-range:解析、规范化、合并重叠区间并生成 multipart/byteranges
  • 为 multi-range 增加最大区间数、最大合计响应大小、最大 header 长度和每个请求的后端 Range 调用数限制。
  • 每个合并区间最多打开一次 StorageDriver::get_range();原生 Range 驱动和默认从完整流跳过前缀的驱动分别建立性能断言。
  • 在下载边界限制 reader 最大输出长度,避免底层驱动返回超出声明 Content-Length 的数据。
  • 增加短读、提前 EOF、底层读取错误、客户端取消、Range stream 中途失败的行为测试和指标。
  • 保持当前异常 EOF 不补零的完整性策略:响应长度异常时让客户端观察到传输失败,而不是生成内容被伪造的文件。
  • 将 reader capacity、Range 上限和后端读取 batch size 配置化或至少集中管理,使用 local/S3-compatible/OneDrive/remote driver 建立吞吐、首字节延迟和请求数基线。

Phase 3: Bounded and streaming PROPFIND/Multi-Status

  • 将 PROPFIND 从完整 xmltree::Element 聚合改为增量 XML writer,逐个资源输出 <D:response>
  • 让客户端断开能够停止后续目录读取、dead property preload、lock discovery 和 XML 渲染。
  • read_dir() 增加稳定排序、批量查询和游标/分页能力;当前返回 FsStream,但实现内部仍先构造完整 entries Vec
  • 为 PROPFIND 配置最大资源数、最大响应字节数、最大单目录条目数和单请求执行时间。
  • 对递归 COPY/MOVE/DELETE 的 207 Multi-Status 改用有界 failure collection 或流式输出,避免锁冲突数量随目录规模无限增长。
  • 增加十万条目目录、超长 dead property、超大 lock discovery 和客户端中断的内存/取消测试。

Phase 4: Live properties and client compatibility

  • 接通已有 DavFileSystem::get_quota(),为 quota-used-bytes / quota-available-bytes 提供真实 scope-aware 值,并避免每个资源重复查询 quota。
  • 明确 getcontentlanguage 的返回策略;只有在真实客户端需要时再补 Microsoft Win32 properties 和其他厂商扩展。
  • PROPFIND propname、空 body allprop、指定 namespace、未知 live property、dead property 和锁属性建立标准化快照测试。
  • 使用 rclone、curl、cadaver 覆盖上传、覆盖写、空文件、chunked PUT、Expected-Length PUT、特殊文件名、锁刷新、Range、递归 COPY/MOVE 和同步删除。
  • 将兼容测试分为提交门禁和 scheduled/manual 外部工具测试,避免工具安装失败掩盖产品失败。

Phase 5: Optional write parity

  • 评估 PUT + Content-RangePATCH + X-Update-Range 的实际客户端需求。
  • 若实施,必须使用 staging file 或 provider-native upload session,完成后原子提交;不要把每个 partial write 直接翻译成对象存储随机覆盖。
  • 按 storage driver capability 显式启用 partial write,给不具备安全合并能力的后端返回稳定错误。
  • 补充并发 partial upload、断线、重试、覆盖、quota、checksum、审计和清理测试。

Phase 6: Boundary cleanup

  • 将下载能力抽象为 DownloadSource / open_full / open_range,将写入能力单独抽象为 DavWriteHandle,不再让 GET 依赖一个实际只用于写入的 DavFile::read_bytes()
  • 保持协议层、AsterDrive scope/权限层和 StorageDriver 层的边界;协议层不重新硬编码 storage policy 或 provider capability。
  • 为下载、上传、PROPFIND、递归 mutation 和 lock discovery 统一记录 duration、bytes、backend calls、failure class、cancellation 和 resource count。

Acceptance criteria

  • WebDAV Litmus basiccopymovepropslockshttp 在 CI 中通过,或每个剩余差异都有独立 issue、标准依据和明确的产品决策。
  • rclone、curl、cadaver 客户端兼容测试有自动化运行入口,并覆盖当前已写的场景。
  • If-Range、single-range、multi-range、HEAD with Range、304/412、short read、client cancellation 均有回归测试。
  • 大目录 PROPFIND 和递归 mutation 的内存、响应字节、节点数和执行时间有硬边界;客户端取消后不会继续遍历整个资源树。
  • Full GET 仍只使用 get_stream(),Range GET 仍只使用目标区间的 get_range();性能测试证明没有退化成完整对象下载。
  • OPTIONS、DAV compliance tokens、Allow、live properties 和实际方法集合一致。
  • 所有新行为都保留 storage policy、quota、审计、权限 scope、锁 token 和失败清理语义。

Non-goals

  • 暂不为了协议对齐引入 CalDAV/CardDAV。
  • 暂不引入 Hyper/Warp 兼容层;当前产品运行时仍以 Actix 为边界。
  • 暂不默认启用目录 HTML autoindex/indexfile。
  • 暂不采用“后端文件截断时补零”的传输策略。
  • 暂不把对象存储强行包装成频繁远端 seek() 的本地文件模型。
  • Depth: infinity 是否开放继续以资源上界和实际客户端需求为前提,不为通过单个测试而移除限制。

Suggested child issues

Filed from Phase 0

Remaining child scopes

  1. Honest OPTIONS/DAV/DeltaV capability advertisement
  2. Implement HTTP If-Range and complete conditional request matrix
  3. Bounded multipart multi-range downloads
  4. Streaming PROPFIND and 207 Multi-Status responses
  5. Paginated WebDAV directory enumeration
  6. Resource limits and cancellation for recursive COPY/MOVE/DELETE
  7. WebDAV quota and client interoperability properties
  8. Partial PUT/PATCH backed by staging or upload sessions
  9. Split WebDAV download and write abstractions

Category

Performance, protocol compatibility, storage backends, and Rust maintenance.

Checklist

  • Existing WebDAV implementation and historical dav-server 0.11.0 behavior were compared.
  • Current direct streaming and efficient Range behavior are explicitly preserved.
  • Litmus 0.18、真实客户端 workflow、严格 known-difference baseline 和 CI artifacts 已建立。
  • WebDAV 测试已集中到 Cargo 自动发现的 tests/webdav/main.rs target;普通 PR 默认只运行 Litmus 五组,不混入大文件或锁压力套件。
  • This issue is intended as an umbrella roadmap; individual implementation PRs should use child issues.
  • No secrets, tokens, private hostnames, or deployment credentials are included.

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions