import { davError, parseDepth } from "@/worker/dav/http"; import { parseIfHeader, type ParsedIfHeader } from "@/worker/dav/if-header"; import { maxXmlBodyBytes } from "@/worker/dav/limits"; import type { AppContext } from "@/worker/types"; import { parsePropfindXml, parseProppatchXml, type PropfindRequest, type ProppatchInstruction, } from "@/worker/xml/dav-request"; export type DavReadResult = { ok: true; value: T } | { ok: false; response: Response }; export interface DavConditionalHeaders { ifMatch: string | null; ifNoneMatch: string | null; ifHeader: ParsedIfHeader; } export function acceptedDavOrigins(c: AppContext): string[] { return [new URL(c.req.url).origin]; } export function readDavConditionalHeaders(c: AppContext): DavReadResult { const parsedIf = parseIfHeader(c.req.header("if") ?? null); if (!parsedIf.ok) return { ok: false, response: davError(400, parsedIf.message) }; return { ok: true, value: { ifMatch: c.req.header("if-match") ?? null, ifNoneMatch: c.req.header("if-none-match") ?? null, ifHeader: parsedIf.header, }, }; } export function readReportDepth( c: AppContext, fallback: "0" | "1" | "infinity", ): DavReadResult<"0" | "1" | "infinity"> { const depth = parseDepth(c.req.header("depth") ?? null, fallback); if (!depth) return { ok: false, response: davError(400, "REPORT Depth must be 0, 1, or infinity") }; return { ok: true, value: depth }; } export async function readCollectionPropfind( c: AppContext, resourceKind: string, ): Promise> { const depth = parseDepth(c.req.header("depth") ?? null, resourceKind === "object" ? "0" : "1"); if (!depth) return { ok: false, response: davError(400, "Invalid Depth header") }; try { return { ok: true, value: { // CalDAV/CardDAV collections are flat in dab. Treat valid Depth infinity // as the same bounded child listing as Depth 1 for client probes. depth: depth === "infinity" ? "1" : depth, request: parsePropfindXml(await c.req.text(), maxXmlBodyBytes(c.env)), }, }; } catch (cause) { return { ok: false, response: davError(400, cause instanceof Error ? cause.message : "Invalid PROPFIND body"), }; } } export async function readCollectionProppatch( c: AppContext, _resourceKind?: unknown, ): Promise> { try { return { ok: true, value: parseProppatchXml(await c.req.text(), maxXmlBodyBytes(c.env)) }; } catch (cause) { return { ok: false, response: davError(400, cause instanceof Error ? cause.message : "Invalid PROPPATCH body"), }; } }