v45b 修复:Thunderbird「找不到日历/联系人」的真根因
用户 2026-10-12 晚:「dav 还是不行,thunderbird 提示找不到日历,联系人也没有。」
真根因(一个由两半无缝衔接构成的 bug):
TB 添加账号 → GET /.well-known/caldav → 我们 301 到 /dav/
→ TB **跟随这个 GET 跳转** → GET /dav/
→ 我们回 **404「没有这本日历」**
→ TB 判定"这里没有日历" ⇒ 报「找不到日历」。
CardDAV 完全同型(/.well-known/carddav → GET /carddav/ → 404)
⇒ 所以日历和联系人是**同一个 bug**。
修法(对齐参照 DAViCal 的状态码语义):
· GET 打到 home 容器(bookId=0)→ **405**(原来 404)
404 = "资源不存在" ⇒ 客户端放弃;405 = "资源在、方法不行" ⇒ 客户端改用 PROPFIND。
· REPORT 打到容器 → **403**(参照实测也是 403)。
· dav.php 与 carddav.php **两处同修**(同型孪生 bug)。
顺带对齐参照(「完全按参照返回」口径):
· 每个 XML 响应都带两行 `DAV:` 头(原来只有 OPTIONS 带)——
CalDav::xmlHeader / CardDav::multis(所有 XML 响应的必经处)。
· Content-Type 改 `text/xml`(参照的字面形态)。
探针补齐(这类 bug 长期漏网的三个原因):
· 原 TB 探针只发 PROPFIND/REPORT,**从不发 GET /dav/**;
· curl 默认不跟随跳转(要 -L);
· 得先 GET .well-known 再跟到 /dav/ 才显形。
⇒ _fb_dav_tb.py 新增 ①c(follow=True 真跟跳转,断言跟随后不能 404、应为 405);
_fb_dav_tb.py 支持 FB_SITE(供反向验证指向注入副本)。
验证:
· TB 探针 35 → **39/0**(新增 4 条 ①c 全过)
· v45b DAV 反向验证 **7/0**(新增 2 个注入:dav/carddav 容器 GET 改回 404
—— 都已证明会让断言变红)
· 全流水线 PUSH_RC=0
· 线上真机复验:跟随 well-known 的 GET 跳转 → CalDAV 405 / CardDAV 405
(修复前都是 404);PROPFIND 带两行 DAV 头 + text/xml;
发现链 207、8 个日历本、1 个通讯录。
This commit is contained in:
+17
-1
@@ -154,7 +154,23 @@ final class CalDav
|
||||
|
||||
public static function xmlHeader(): void
|
||||
{
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
/* 🔴🔴 v45b(2026-10-12 用户「TB 还是找不到日历」)——**关键对齐**。
|
||||
抓参照(DAViCal)发现:它**每一个响应**(不只 OPTIONS)都带两行 `DAV:` 头:
|
||||
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
|
||||
DAV: extended-mkcol, bind, addressbook, calendar-auto-schedule
|
||||
而我们原来**只有 OPTIONS 带**。Thunderbird 的 CalDAV 探测里会读
|
||||
`DAV:` 头来确认"这确实是个 DAV 服务"(它把 `calendar-access` 当作
|
||||
"支持 CalDAV" 的判据)。PROPFIND/REPORT 的响应缺这个头时,
|
||||
部分 TB 版本会认为"服务器没声明 CalDAV 能力"。
|
||||
⇒ 照参照,在这个**所有 XML 响应都必经**的地方补上。
|
||||
|
||||
⚠️ Content-Type 也用**参照的字面形态** `text/xml`(原来 `application/xml`)。
|
||||
两者都能被解析,但参照是 `text/xml`,用户要求「完全按参照返回」;
|
||||
且个别老解析器对 `application/xml` 的处理路径不同,对齐更稳。
|
||||
⚠️ 第二个 `DAV:` 头必须 `false` 追加 —— PHP 同名 header 默认**覆盖**。 */
|
||||
header('Content-Type: text/xml; charset="utf-8"');
|
||||
header('DAV: 1, 2, 3, calendar-access, calendar-schedule', false);
|
||||
header('DAV: extended-mkcol', false);
|
||||
}
|
||||
|
||||
/** 多状态应答(207)—— PROPFIND / REPORT 都用它 */
|
||||
|
||||
Reference in New Issue
Block a user