Skip to content
File

Blob: tests/worker/protocol/webdav/files-limits.workers.test.ts

typescript92 lines
1import { describe, expect, it } from "vitest";
2 
3import { createDavFixture, davRequest } from "@tests/worker/helpers/dav";
4import { fetchWorker } from "@tests/worker/helpers/http";
5import { withEnvBinding } from "@tests/worker/helpers/env";
6import { name } from "./files-helpers";
7 
8describe("WebDAV file limits", () => {
9 it("rejects over-limit XML request bodies", async () => {
10 const fixture = await createDavFixture();
11 const body = `<?xml version="1.0"?><D:propfind xmlns:D="DAV:"><D:prop><D:displayname>${"x".repeat(
12 1_049_000,
13 )}</D:displayname></D:prop></D:propfind>`;
14 const response = await fetchWorker(
15 davRequest(fixture, "/files/", {
16 method: "PROPFIND",
17 headers: { depth: "0", "content-type": "application/xml" },
18 body,
19 }),
20 );
21 
22 expect(response.status).toBe(400);
23 await expect(response.text()).resolves.toContain("XML body exceeds");
24 });
25 
26 it("bounds Depth infinity PROPFIND by the configured maximum nodes", async () => {
27 const fixture = await createDavFixture();
28 const directory = name("depth-bound");
29 expect(await fetchWorker(davRequest(fixture, `/files/${directory}/`, { method: "MKCOL" }))).toMatchObject({
30 status: 201,
31 });
32 expect(
33 await fetchWorker(davRequest(fixture, `/files/${directory}/a.txt`, { method: "PUT", body: "a" })),
34 ).toHaveProperty("status", 201);
35 expect(
36 await fetchWorker(davRequest(fixture, `/files/${directory}/b.txt`, { method: "PUT", body: "b" })),
37 ).toHaveProperty("status", 201);
38 
39 await withEnvBinding("MAX_DAV_DEPTH_INFINITY_NODES", "2", async () => {
40 const response = await fetchWorker(
41 davRequest(fixture, "/files/", {
42 method: "PROPFIND",
43 headers: { depth: "infinity", "content-type": "application/xml" },
44 body: `<?xml version="1.0"?><D:propfind xmlns:D="DAV:"><D:prop><D:displayname/></D:prop></D:propfind>`,
45 }),
46 );
47 expect(response.status).toBe(403);
48 await expect(response.text()).resolves.toContain("configured maximum");
49 });
50 });
51 
52 it("fails recursive DELETE, COPY, and MOVE before mutation when the subtree exceeds the configured node limit", async () => {
53 const fixture = await createDavFixture();
54 const directory = name("recursive-bound");
55 expect(await fetchWorker(davRequest(fixture, `/files/${directory}/`, { method: "MKCOL" }))).toHaveProperty(
56 "status",
57 201,
58 );
59 expect(
60 await fetchWorker(davRequest(fixture, `/files/${directory}/a.txt`, { method: "PUT", body: "a" })),
61 ).toHaveProperty("status", 201);
62 expect(
63 await fetchWorker(davRequest(fixture, `/files/${directory}/b.txt`, { method: "PUT", body: "b" })),
64 ).toHaveProperty("status", 201);
65 
66 await withEnvBinding("MAX_DAV_DEPTH_INFINITY_NODES", "2", async () => {
67 const deleted = await fetchWorker(davRequest(fixture, `/files/${directory}/`, { method: "DELETE" }));
68 expect(deleted.status).toBe(403);
69 expect(await fetchWorker(davRequest(fixture, `/files/${directory}/a.txt`))).toHaveProperty("status", 200);
70 
71 const copied = await fetchWorker(
72 davRequest(fixture, `/files/${directory}/`, {
73 method: "COPY",
74 headers: { destination: `https://${fixture.hostLabel}.dav.example.com/files/${directory}-copy/` },
75 }),
76 );
77 expect(copied.status).toBe(403);
78 expect(await fetchWorker(davRequest(fixture, `/files/${directory}-copy/a.txt`))).toHaveProperty("status", 404);
79 
80 const moved = await fetchWorker(
81 davRequest(fixture, `/files/${directory}/`, {
82 method: "MOVE",
83 headers: { destination: `https://${fixture.hostLabel}.dav.example.com/files/${directory}-moved/` },
84 }),
85 );
86 expect(moved.status).toBe(403);
87 expect(await fetchWorker(davRequest(fixture, `/files/${directory}/a.txt`))).toHaveProperty("status", 200);
88 expect(await fetchWorker(davRequest(fixture, `/files/${directory}-moved/a.txt`))).toHaveProperty("status", 404);
89 });
90 });
91});