import { describe, expect, it } from "vitest";
import { createDavFixture, davRequest } from "@tests/worker/helpers/dav";
import { fetchWorker } from "@tests/worker/helpers/http";
describe("WebDAV If header preconditions", () => {
it("rejects false If entity-tag preconditions on mutating WebDAV methods", async () => {
const fixture = await createDavFixture();
const file = `if-${crypto.randomUUID()}.txt`;
const source = `if-source-${crypto.randomUUID()}.txt`;
const prop = `if-prop-${crypto.randomUUID()}.txt`;
const falseIf = '(["definitely-not-the-current-etag"])';
expect(await fetchWorker(davRequest(fixture, `/files/${file}`, { method: "PUT", body: "x" }))).toHaveProperty(
"status",
201,
);
expect(await fetchWorker(davRequest(fixture, `/files/${source}`, { method: "PUT", body: "x" }))).toHaveProperty(
"status",
201,
);
expect(await fetchWorker(davRequest(fixture, `/files/${prop}`, { method: "PUT", body: "x" }))).toHaveProperty(
"status",
201,
);
expect(
await fetchWorker(davRequest(fixture, `/files/${file}`, { method: "DELETE", headers: { if: falseIf } })),
).toHaveProperty("status", 412);
expect(
await fetchWorker(
davRequest(fixture, `/files/${source}`, {
method: "COPY",
headers: { if: falseIf, destination: `https://${fixture.hostLabel}.dav.example.com/files/copied.txt` },
}),
),
).toHaveProperty("status", 412);
expect(
await fetchWorker(
davRequest(fixture, `/files/${source}`, {
method: "MOVE",
headers: { if: falseIf, destination: `https://${fixture.hostLabel}.dav.example.com/files/moved.txt` },
}),
),
).toHaveProperty("status", 412);
expect(
await fetchWorker(
davRequest(fixture, `/files/${prop}`, {
method: "PROPPATCH",
headers: { if: falseIf, "content-type": "application/xml" },
body: `y`,
}),
),
).toHaveProperty("status", 412);
expect(
await fetchWorker(davRequest(fixture, `/files/new-if-dir/`, { method: "MKCOL", headers: { if: falseIf } })),
).toHaveProperty("status", 412);
});
it("honors HTTP If-Match on DELETE, COPY, MOVE, and PROPPATCH", async () => {
const fixture = await createDavFixture();
const file = `if-match-${crypto.randomUUID()}.txt`;
const copySource = `if-match-copy-${crypto.randomUUID()}.txt`;
const moveSource = `if-match-move-${crypto.randomUUID()}.txt`;
const propSource = `if-match-prop-${crypto.randomUUID()}.txt`;
const stale = '"definitely-stale"';
for (const name of [file, copySource, moveSource, propSource]) {
expect(await fetchWorker(davRequest(fixture, `/files/${name}`, { method: "PUT", body: "x" }))).toHaveProperty(
"status",
201,
);
}
expect(
await fetchWorker(davRequest(fixture, `/files/${file}`, { method: "DELETE", headers: { "if-match": stale } })),
).toHaveProperty("status", 412);
expect(await fetchWorker(davRequest(fixture, `/files/${file}`))).toHaveProperty("status", 200);
expect(
await fetchWorker(
davRequest(fixture, `/files/${copySource}`, {
method: "COPY",
headers: {
"if-match": stale,
destination: `https://${fixture.hostLabel}.dav.example.com/files/if-match-copy-dest.txt`,
},
}),
),
).toHaveProperty("status", 412);
expect(await fetchWorker(davRequest(fixture, "/files/if-match-copy-dest.txt"))).toHaveProperty("status", 404);
expect(
await fetchWorker(
davRequest(fixture, `/files/${moveSource}`, {
method: "MOVE",
headers: {
"if-match": stale,
destination: `https://${fixture.hostLabel}.dav.example.com/files/if-match-move-dest.txt`,
},
}),
),
).toHaveProperty("status", 412);
expect(await fetchWorker(davRequest(fixture, `/files/${moveSource}`))).toHaveProperty("status", 200);
expect(
await fetchWorker(
davRequest(fixture, `/files/${propSource}`, {
method: "PROPPATCH",
headers: { "if-match": stale, "content-type": "application/xml" },
body: `y`,
}),
),
).toHaveProperty("status", 412);
});
it("applies tagged If entity-tag conditions to the tagged resource", async () => {
const fixture = await createDavFixture();
const target = `tag-target-${crypto.randomUUID()}.txt`;
const tagged = `tagged-${crypto.randomUUID()}.txt`;
expect(
await fetchWorker(davRequest(fixture, `/files/${target}`, { method: "PUT", body: "target" })),
).toHaveProperty("status", 201);
const taggedPut = await fetchWorker(davRequest(fixture, `/files/${tagged}`, { method: "PUT", body: "tagged" }));
expect(taggedPut.status).toBe(201);
const etag = taggedPut.headers.get("etag");
expect(etag).toMatch(/^"[0-9a-f]+"$/);
const response = await fetchWorker(
davRequest(fixture, `/files/${target}`, {
method: "PROPPATCH",
headers: {
if: ` ([${etag}])`,
"content-type": "application/xml",
},
body: `y`,
}),
);
expect(response.status).toBe(207);
});
it("rejects false If preconditions on LOCK refresh", async () => {
const fixture = await createDavFixture();
const file = `refresh-${crypto.randomUUID()}.txt`;
expect(await fetchWorker(davRequest(fixture, `/files/${file}`, { method: "PUT", body: "x" }))).toHaveProperty(
"status",
201,
);
const locked = await fetchWorker(
davRequest(fixture, `/files/${file}`, {
method: "LOCK",
headers: { depth: "0", timeout: "Second-600", "content-type": "application/xml" },
body: ``,
}),
);
expect(locked.status).toBe(200);
const token = locked.headers.get("lock-token");
expect(token).toMatch(/^]+>$/);
expect(
await fetchWorker(
davRequest(fixture, `/files/${file}`, {
method: "LOCK",
headers: { if: `(${token} ["definitely-not-the-current-etag"])` },
}),
),
).toHaveProperty("status", 412);
});
});