Sign in

    q2316367743/webdav/client does not have a README file

    WebdavClient

    pub struct WebdavClient {
    // private fields
    }

    WebDAV 客户端:全部操作以方法形式挂在本类型上。 通过 create_webdav_client 构造(根包重导出)。

    WebdavClient::cleanup_lock_null

    async fn WebdavClient::cleanup_lock_null(self : WebdavClient, path~ : String, token~ : String, signal? :
    AbortSignal
    ) -> Bool raise
    WebdavError

    释放锁并清掉因这次锁而创建的空资源(lock-null,RFC 4918 §7.3)。

    顺序与判定:
    1. unlock:404 / 409 说明锁已经不在了(已过期或已被释放),继续收尾; 其他错误照抛,交给调用方决定;
    2. 探测资源:**只删「仍存在且长度恰为 0」**的;长度未知(服务端没给 Content-Length,或不支持 HEAD)一律不碰,宁可留垃圾也不误删内容;
    3. 删除时带上探测到的 ETag(If-Match),避免误删并发写入的新内容。

    返回 true 表示确实删掉了这个空资源,false 表示没删。

    WebdavClient::copy_path

    复制(COPY)。参数语义与 move_path 一致,另加 Depth: 省略为服务端默认(集合通常递归),Zero 做浅拷贝 (只建目标集合并复制属性,不复制子项,RFC 4918 §9.8.3)。

    WebdavClient::delete

    删除文件或目录(DELETE,目录要求为空或服务端支持递归)。

    放行 207:部分服务端对批量 / 递归删除返回 Multi-Status, 只要有资源没删成功就抛 Partial(failures 列出失败条目)。

    WebdavClient::download_file

    async fn WebdavClient::download_file(self : WebdavClient, path~ : String, on_chunk~ : (Bytes) -> Unit, chunk_size? : Int, range? :
    ByteRange
    , conditions? :
    Conditions
    , on_progress? : (
    Progress
    ) -> Unit, signal? :
    AbortSignal
    ) -> Unit raise
    WebdavError

    流式下载(GET 分块消费):每个分块交给 on_chunk(如逐块写文件), 读完即止,内存占用与文件大小无关。

    • chunk_size:单次读取上限,默认 64 KiB;
    • range:区间下载(RFC 7233),只消费服务端返回的区间内容; 进度按本次响应计(total 取响应 Content-Length,206 时是区间长度);
    • on_progress:按已接收字节累计触发,total 来自 Content-Length (服务端未返回长度时为 None);
    • on_chunk 是同步回调:只适合内存消费(拼接 Buffer、算哈希、 喂同步通道)。要落盘或做别的 async 副作用,用 download_to_path。

    WebdavClient::download_to_path

    async fn WebdavClient::download_to_path(self : WebdavClient, path~ : String, local_path~ : String, chunk_size? : Int, range? :
    ByteRange
    , conditions? :
    Conditions
    , on_progress? : (
    Progress
    ) -> Unit, signal? :
    AbortSignal
    ) -> Unit raise
    WebdavError

    流式下载到本地文件:边收边写盘,内存占用与文件大小无关。 与 put_file_from_path 对称,是「下载到磁盘」的正路—— 同步 on_chunk 回调里没法 await 写文件。

    • path:服务端源路径;local_path:本地目标文件(已存在则截断覆盖);
    • chunk_size:单次读取 / 写入上限,默认 64 KiB;
    • range:区间下载(RFC 7233),服务端接受时只写区间内容, 进度按本次响应计(206 时 total 是区间长度);
    • 顺序上先发请求、拿到 200 / 206 才建本地文件:404 等失败不会 清空本地已存在的同名文件;
    • 本地文件创建 / 写入失败抛 WebdavError::Io;读流失败经统一映射 (取消 → Cancelled,其余 → Http);
    • 失败或取消时可能留下部分内容的本地文件(不自动删除)—— 需要从中断处继续时用 download_to_path_resume;
    • on_progress:按已写入字节累计触发,total 来自 Content-Length (服务端未返回长度时为 None)。

    WebdavClient::download_to_path_resume

    async fn WebdavClient::download_to_path_resume(self : WebdavClient, path~ : String, local_path~ : String, etag? : String, chunk_size? : Int, on_progress? : (
    Progress
    ) -> Unit, signal? :
    AbortSignal
    ) -> Unit raise
    WebdavError

    断点续传下载到本地文件:本地已有前 N 字节(上次中断的残留)时发 Range: bytes=N- 续传,只拉取剩余部分追加到文件尾;本地不存在 / 为空时等同于 download_to_path 全量下载。

    • etag:上次响应的 ETag(get_file / put_file 的结果里都有)。 提供则随请求发 If-Range:服务端资源仍是这一版才回 206 续传, 已被修改则回 200 全文,本方法自动截断重写,保证不拼出损坏文件; 省略则裸续传(服务端文件在两次下载之间被整体替换时可能得到 拼接损坏的结果,调用方自行权衡);
    • 206 的 Content-Range 缺失、或区间起点与本地字节数不符时抛 Api(此时继续追加不安全);
    • 416(区间不满足)且本地字节数恰为服务端告知的资源总长时, 视为「本地已完整」直接成功返回;否则抛 Api(416);
    • 下载完成后校验本地文件大小与服务端总长一致(总长已知时), 不一致抛 Api,保证「成功返回 = 文件完整」;
    • on_progress 报告绝对进度:loaded 从本地已有字节起累计, total 为资源总长(Content-Range / Content-Length 均未给出 时为 None)。

    WebdavClient::exists

    资源是否存在。

    优先用 HEAD(比 PROPFIND 轻,不返回响应体):200 / 204 存在、404 不存在、 304 表示条件命中(资源存在且未变)。若服务端不支持 HEAD(405 / 501, 部分对象存储与精简实现如此),回落到 PROPFIND Depth:0:207 存在、 404 不存在。

    WebdavClient::get_file

    下载文件到内存(GET),返回内容与响应元数据 (Content-Type / Content-Length / ETag / Last-Modified)。 on_progress 由 moonhttp 在读响应体过程中触发。

    • range:区间下载(RFC 7233)。提供则发 Range 头,服务端支持时 回 206、content 只是区间内容,content_range 携带解析结果; 服务端忽略 Range 回 200 时返回全量(调用方以 status 区分)。

    WebdavClient::get_locks

    读资源上的活动锁(PROPFIND lockdiscovery,Depth 0)。

    返回活动锁列表;没有锁时是空数组。部分服务端(如 hacdias/webdav) 不回 lockdiscovery 的值,此时同样得到空数组。

    WebdavClient::get_properties

    async fn WebdavClient::get_properties(self : WebdavClient, path~ : String, names~ : Array[String], ns_uri? : String, conditions? :
    Conditions
    , signal? :
    AbortSignal
    ) -> Map[String, String] raise
    WebdavError

    读取自定义属性(PROPFIND 按名请求):返回 属性名 → 值, 服务端没有的属性(404 propstat)不出现在结果中。 需要区分「没有该属性」与「值为空」时用 get_properties_with_status。

    WebdavClient::get_properties_with_status

    读取自定义属性并保留每个属性的状态码:404 表示服务端没有这个属性, 与「属性值为空串」区分开(部分服务端对未存储的死属性回 404 propstat)。

    WebdavClient::list

    列目录(PROPFIND allprop):默认 Depth:1 返回直接子项,不含目录自身。

    • depth:One(默认,直接子项)/ Infinity(整棵子树,见 list_recursive)/ Zero(只有目录自身,结果通常为空);
    • href 与服务端路径的对齐统一走 @types.href_to_path (剥绝对 URL 前缀、丢 query / fragment、percent 解码、去尾斜杠)。

    WebdavClient::list_recursive

    递归列出整棵子树(PROPFIND Depth:infinity)。 服务端可能限制深度并返回 403,调用方可自行降级为逐层 list。

    WebdavClient::lock

    申请独占写锁(LOCK,RFC 4918 §9.10)。

    • path:要锁定的资源路径;
    • owner:持有者标识,写进请求体 <D:owner> 的文本,省略则不写该元素;
    • timeout:Timeout 头原文,如 "Second-300" / "Infinite", 省略则用服务端默认值;
    • depth:只支持 Depth::Zero 与 Depth::Infinity;Depth::One 对 LOCK 非法,发请求前抛 Api 400。省略时不发 Depth 头;
    • scope:锁作用域,省略时按独占写锁(LockScope::Exclusive); 共享锁传 LockScope::Shared,可与别的共享锁共存;
    • signal:取消信号。

    返回服务端确认的锁:令牌优先取 Lock-Token 响应头,其次取响应体的 首个 activelock;两者都没有时抛 Api。响应体 XML 非法但带 Lock-Token 头时仍算成功,元数据退化为默认值。成功后这把锁会记进 客户端本地注册表,供写请求被 423 拒绝时自动补令牌重试。

    WebdavClient::mkdir

    创建目录(MKCOL)。单级创建:父目录不存在时服务端通常返回 409, 需要 mkdir -p 语义时用 mkdir_all(见 mkdir_all.mbt)。 conditions 可用于 If-None-Match: *(父目录已存在时不要覆盖) 或携带锁令牌。

    WebdavClient::mkdir_all

    递归创建目录(mkdir -p 语义):对 path 的每一级依次发 MKCOL, 父级先于子级。

    • 某级已存在时跳过:服务端按 RFC 4918 §9.3.1 回 405(Method Not Allowed), 因此对已存在的目录重复调用是幂等的,末级已存在也不算失败;
    • 回 409(Conflict,父目录不存在)时用 PROPFIND Depth:0 复核该级是否 真的存在(并发创建 / 他人刚建好):存在则跳过,不存在则原样抛出 409—— 避免父级不是集合时「逐级跳过、最后假装成功」;
    • path 为 /、空串或只有斜杠时(基地址自身,视作已存在)不发任何请求;
    • 重复斜杠与结尾斜杠会折叠 / 忽略,每级都拼成以 / 开头的绝对路径;
    • conditions 逐级生效(等价于逐级调用 mkdir),若带 If-None-Match: * 则已存在的层级会先回 412 而不是 405,需要幂等时不要传该条件。

    WebdavClient::move_path

    移动 / 重命名(MOVE)。

    • src / dst:相对 base_url 的源与目标路径;
    • overwrite:目标已存在时是否覆盖,默认 true;为 false 且目标 存在时服务端返回 412(抛 Api 错误);
    • depth:省略则不发 Depth 头(对已存在的集合服务端默认递归); 显式给 Zero 可对目录做浅移动(支持该语义的服务端较少);
    • 207:服务端逐资源返回结果,有失败条目时抛 Partial。

    WebdavClient::options

    探测服务端能力(OPTIONS):返回 DAV 合规等级、Allow 方法列表与 Server 标识,便于在 LOCK / MKCOL / MOVE 等操作前判断服务端支持面, 而不是靠失败状态码猜。

    path 省略时探测根路径(服务端通常会回全局能力)。

    WebdavClient::put_file

    上传文件(PUT 整体写入),返回响应元数据(ETag / Last-Modified / Location),可直接用于后续的条件请求。

    这是全量字节形态:data 契约是「完整内容已在内存」。上传过程 本身是流式的(不额外整份拷贝),但内容要先在调用方内存里;内容在磁盘、 或大到不想整块驻留时,用 put_file_from_path / put_file_stream。

    • data:完整文件内容,包装成流式请求体发送;
    • content_type:可选 MIME 类型;
    • conditions:可选 If-Match / If-None-Match(乐观并发控制, 如 If-None-Match: "*" 表示「仅当资源不存在时才创建」);
    • on_progress:上传进度,按传输层 64 KiB 分块节奏触发, total 为声明的请求体长度。

    内容整份在内存,因此这条路径可重放:写请求被 423 拒绝、且客户端 开启 retry_on_423 并持有覆盖锁时,会自动补锁令牌重试一次 (put_file_stream / put_file_from_path 的一次性流不重试)。

    WebdavClient::put_file_from_path

    从本地文件路径流式上传:内部打开文件、用文件长度声明 Content-Length、把文件句柄当读取流交给传输层,边读边发, 成功或失败都关闭句柄——内容不整份读进内存。

    • path:服务端目标路径;local_path:本地待上传文件的绝对 / 相对路径;
    • 本地文件打不开、路径是目录时抛 WebdavError::Io,此时不会发出任何请求;
    • 其余参数语义与 put_file 一致(on_progress 的 total 为文件长度)。

    注意:长度在打开时取快照,传输过程中文件被改写会导致 「写出字节数与声明不符」,传输层报 Http 错误;大文件的整跳超时见 WebdavConfig::timeout_ms(覆盖「建连 → 写完整个请求体 → 响应头」)。

    WebdavClient::put_file_stream

    流式上传:数据源是任意读取流(&@io.Reader),传输层边读边写, 请求体不再需要整块驻留内存。

    • reader:拉取式读取流。read_some 返回 None(EOF)即请求体收尾。 @fs.File(本地文件)、@io.MemoryReader(边生成边推)、 @io.pipe() 的读端(生产者协程)都能直接接;
    • content_length:请求体长度。给了走定长 Content-Length(进度 total 已知,兼容 HTTP/1.0 目标);不给走 Transfer-Encoding: chunked。 写出字节数与声明不符时传输层报错(本地数据与声明对不上);
    • 其余参数语义与 put_file 一致。

    流是一次性资源:同一条流不要发两次请求;遇到 307/308 这类要求 原样重放请求体的重定向时,moonhttp 会直接报错而不是静默发空体。 同理,这条路径不参与 423 自动重试(拨不回起点), 需要重试能力请在内存里用 put_file。

    WebdavClient::refresh_lock

    刷新锁(LOCK 无请求体 + If 头,RFC 4918 §9.10.2)。

    刷新不换令牌:响应里没有令牌时沿用传入的 token。 timeout 与 signal 含义同 lock;Depth 不参与刷新,一律不发。

    WebdavClient::set_properties

    async fn WebdavClient::set_properties(self : WebdavClient, path~ : String, props~ : Array[(String, String)], ns_uri? : String, conditions? :
    Conditions
    , signal? :
    AbortSignal
    ) -> Unit raise
    WebdavError

    写入自定义属性(PROPPATCH set)。

    • props:(属性名, 值) 列表;
    • ns_uri:属性命名空间,默认 DEFAULT_PROP_NS; 属性名需为合法 XML 名(非法时抛 Api 400)。

    WebdavClient::stat

    获取单个资源的属性(PROPFIND Depth:0 allprop)。 资源不存在时服务端返回 404(抛 Api 错误)。

    WebdavClient::unlock

    async fn WebdavClient::unlock(self : WebdavClient, path~ : String, token~ : String, signal? :
    AbortSignal
    ) -> Unit raise
    WebdavError

    释放锁(UNLOCK,RFC 4918 §9.11)。Lock-Token 头按 <令牌> 形态发送。

    200 / 204 表示已释放;409 通常表示令牌与资源上的锁不匹配。 释放成功后这把锁从本地注册表里去掉,之后写请求不会再自动带它。

    DEFAULT_PROP_NS

    let DEFAULT_PROP_NS : String

    自定义属性(死属性)的默认命名空间。

    create_webdav_client

    创建 WebDAV 客户端(moonhttp 自研 HTTP/1.1 传输层)。

    create_webdav_client_with_transport

    创建使用指定传输层的客户端:测试注入 MockTransport, 或自定义连接 / 代理行为。