Skip to content
File

Blob: src/worker/dav/runtime.ts

typescript50 lines
1import type { DavPatAuth } from "@/worker/auth/basic";
2import { davError, emptyResponse, methodNotAllowed } from "@/worker/dav/http";
3import type { SubjectRow } from "@/worker/db/d1/schema";
4import type { AppContext } from "@/worker/types";
5 
6export interface DavRequestContext {
7 c: AppContext;
8 subject: SubjectRow;
9 auth: DavPatAuth;
10 pathname: string;
11}
12 
13export interface DavArea {
14 name: "files" | "caldav" | "carddav" | "discovery";
15 allow: string;
16 optionsHeaders: HeadersInit;
17 matches(pathname: string): boolean;
18 canUseMethod(auth: DavPatAuth, method: string): boolean;
19 handle(context: DavRequestContext): Promise<Response>;
20}
21 
22function allowedMethods(allow: string): Set<string> {
23 return new Set(allow.split(",").map((method) => method.trim()));
24}
25 
26export function findDavArea(pathname: string, areas: readonly DavArea[]): DavArea | null {
27 return areas.find((area) => area.matches(pathname)) ?? null;
28}
29 
30export function isMethodAllowed(area: DavArea, method: string): boolean {
31 return allowedMethods(area.allow).has(method);
32}
33 
34export function isExpensiveDavRequest(request: Request): boolean {
35 if (request.method === "REPORT") return true;
36 return request.method === "PROPFIND" && request.headers.get("depth")?.toLowerCase() === "infinity";
37}
38 
39export function expensiveDavRequestArea(pathname: string): string {
40 return pathname === "/files" || pathname.startsWith("/files/") ? "files" : (pathname.split("/")[1] ?? "unknown");
41}
42 
43export async function dispatchDavArea(area: DavArea, context: DavRequestContext): Promise<Response> {
44 const method = context.c.req.method;
45 if (!area.canUseMethod(context.auth, method)) return davError(403, "PAT scope does not allow this method");
46 if (method === "OPTIONS") return emptyResponse(204, area.optionsHeaders);
47 if (!isMethodAllowed(area, method)) return methodNotAllowed(area.allow);
48 return await area.handle(context);
49}