import { davError } from "@/worker/dav/http"; import { parseIfHeader, positiveLockTokens, type ParsedIfHeader } from "@/worker/dav/if-header"; export interface FileDavWriteRequest { ifMatch: string | null; ifNoneMatch: string | null; ifHeader: ParsedIfHeader; lockTokens: string[]; nowMs: number; } export function parseContentLength(request: Request): number | null { const value = request.headers.get("content-length"); if (!value) return null; const parsed = Number.parseInt(value, 10); return Number.isFinite(parsed) && parsed >= 0 ? parsed : null; } export function requestIfHeader(request: Request): { ok: true; header: ParsedIfHeader } | Response { const parsed = parseIfHeader(request.headers.get("if")); if (!parsed.ok) return davError(400, parsed.message); return parsed; } export function readFileDavWriteRequest(request: Request, nowMs = Date.now()): FileDavWriteRequest | Response { const parsedIf = requestIfHeader(request); if (parsedIf instanceof Response) return parsedIf; return { ifMatch: request.headers.get("if-match"), ifNoneMatch: request.headers.get("if-none-match"), ifHeader: parsedIf.header, lockTokens: positiveLockTokens(parsedIf.header), nowMs, }; } export function validateDeleteDepth(value: string | null): Response | null { // RFC 4918 9.6.1: DELETE on a collection is Depth: infinity; other values are invalid. const normalized = value?.trim().toLowerCase() ?? null; return normalized !== null && normalized !== "infinity" ? davError(400, "DELETE Depth must be infinity") : null; } export function readCopyDepth(value: string | null): "0" | "infinity" | Response { // RFC 4918 9.8.3: COPY Depth must be absent, "0", or "infinity". const normalized = value?.trim().toLowerCase() ?? null; if (normalized !== null && normalized !== "0" && normalized !== "infinity") { return davError(400, "COPY Depth must be 0 or infinity"); } return normalized === "0" ? "0" : "infinity"; } export function validateMoveDepth(value: string | null): Response | null { // RFC 4918 9.9.3: MOVE on a collection is Depth: infinity; Depth: 0 is not permitted. const normalized = value?.trim().toLowerCase() ?? null; return normalized !== null && normalized !== "infinity" ? davError(400, "MOVE Depth must be infinity") : null; }