import { parseDestination, overwriteAllowed } from "@/worker/dav/destination"; import { davError, emptyResponse } from "@/worker/dav/http"; import { maxDavDepthInfinityNodes } from "@/worker/dav/limits"; import type { SubjectRow } from "@/worker/db/d1/schema"; import type { AppContext } from "@/worker/types"; import { enqueueGc } from "@/worker/webdav/gc"; import { fileDavObject, resultError, type NormalizedFilesRequestPath } from "@/worker/webdav/object"; import { readCopyDepth, readFileDavWriteRequest, validateMoveDepth } from "@/worker/webdav/request"; export async function handleCopyMove(c: AppContext, subject: SubjectRow, path: NormalizedFilesRequestPath) { const destination = parseDestination(c.req.header("destination") ?? null, new URL(c.req.url)); if (!destination.ok) return davError(destination.status, destination.message); const overwrite = overwriteAllowed(c.req.header("overwrite") ?? null); if (overwrite === null) return davError(400, "Invalid Overwrite header"); const writeRequest = readFileDavWriteRequest(c.req.raw); if (writeRequest instanceof Response) return writeRequest; const rawDepth = c.req.header("depth") ?? null; let copyDepth: "0" | "infinity" = "infinity"; if (c.req.method === "COPY") { const depth = readCopyDepth(rawDepth); if (depth instanceof Response) return depth; copyDepth = depth; } else { const depthError = validateMoveDepth(rawDepth); if (depthError) return depthError; } const object = fileDavObject(c.env, subject.storageId); const maxNodes = maxDavDepthInfinityNodes(c.env); const result = c.req.method === "COPY" ? await object.copy({ subjectId: subject.id, storageId: subject.storageId, from: path.path, to: destination.path, depth: copyDepth, overwrite, ...writeRequest, maxNodes, }) : await object.move({ subjectId: subject.id, storageId: subject.storageId, from: path.path, to: destination.path, overwrite, ...writeRequest, maxNodes, }); if (!result.ok) return resultError(result); await enqueueGc(c, subject, result.blobGc); return emptyResponse(result.created ? 201 : 204); }