Skip to content
File

Blob: test/upload-pack-content-encoding.worker.test.ts

typescript128 lines
1import { it, expect } from "vitest";
2import { env, exports as workerExports } from "cloudflare:workers";
3import { pktLine, delimPkt, flushPkt, concatChunks, decodePktLines } from "@/worker/git";
4import { uniqueRepoId, runDOWithRetry } from "./util/test-helpers";
5import { setupRepoForTests } from "./util/repoSeed";
6import { gzip } from "@/worker/common";
7 
8function buildFetchBody({
9 wants,
10 haves,
11 done,
12}: {
13 wants: string[];
14 haves?: string[];
15 done?: boolean;
16}) {
17 const chunks: Uint8Array[] = [];
18 chunks.push(pktLine("command=fetch\n"));
19 chunks.push(delimPkt());
20 for (const w of wants) chunks.push(pktLine(`want ${w}\n`));
21 for (const h of haves || []) chunks.push(pktLine(`have ${h}\n`));
22 if (done) chunks.push(pktLine("done\n"));
23 chunks.push(flushPkt());
24 return concatChunks(chunks);
25}
26 
27function buildLsRefsBody(args: string[] = []) {
28 const chunks: Uint8Array[] = [];
29 chunks.push(pktLine("command=ls-refs\n"));
30 chunks.push(delimPkt());
31 for (const a of args) chunks.push(pktLine(a + "\n"));
32 chunks.push(flushPkt());
33 return concatChunks(chunks);
34}
35 
36it("upload-pack fetch accepts gzip-encoded request bodies", async () => {
37 const owner = "o";
38 const repo = uniqueRepoId("r-gzip-fetch");
39 await setupRepoForTests(env, owner, repo);
40 const repoId = `${owner}/${repo}`;
41 const id = env.REPO_DO.idFromName(repoId);
42 const { commitOid } = await runDOWithRetry(
43 () => env.REPO_DO.get(id),
44 async (instance) => instance.seedMinimalRepo()
45 );
46 
47 const body = await gzip(buildFetchBody({ wants: [commitOid], done: true }));
48 const url = `https://example.com/${owner}/${repo}/git-upload-pack`;
49 const res = await workerExports.default.fetch(url, {
50 method: "POST",
51 headers: {
52 "Content-Type": "application/x-git-upload-pack-request",
53 "Content-Encoding": "gzip",
54 "Git-Protocol": "version=2",
55 },
56 body,
57 } as any);
58 
59 expect(res.status).toBe(200);
60 expect(res.headers.get("Content-Type") || "").toContain("git-upload-pack-result");
61 const text = new TextDecoder().decode(new Uint8Array(await res.arrayBuffer()));
62 expect(text.includes("packfile\n")).toBe(true);
63});
64 
65it("upload-pack ls-refs accepts gzip-encoded request bodies", async () => {
66 const owner = "o";
67 const repo = uniqueRepoId("r-gzip-lsrefs");
68 await setupRepoForTests(env, owner, repo);
69 const body = await gzip(buildLsRefsBody(["ref-prefix refs/heads/"]));
70 const url = `https://example.com/${owner}/${repo}/git-upload-pack`;
71 const res = await workerExports.default.fetch(url, {
72 method: "POST",
73 headers: {
74 "Content-Type": "application/x-git-upload-pack-request",
75 "Content-Encoding": "gzip",
76 "Git-Protocol": "version=2",
77 },
78 body,
79 } as any);
80 
81 expect(res.status).toBe(200);
82 const bytes = new Uint8Array(await res.arrayBuffer());
83 const lines = decodePktLines(bytes)
84 .filter((i) => i.type === "line")
85 .map((i: any) => i.text);
86 expect(lines[0]).toBe("unborn HEAD symref-target:refs/heads/main\n");
87});
88 
89it("upload-pack rejects unsupported content encodings", async () => {
90 const owner = "o";
91 const repo = uniqueRepoId("r-encoding-unsupported");
92 await setupRepoForTests(env, owner, repo);
93 const body = buildLsRefsBody(["ref-prefix refs/heads/"]);
94 const url = `https://example.com/${owner}/${repo}/git-upload-pack`;
95 const res = await workerExports.default.fetch(url, {
96 method: "POST",
97 headers: {
98 "Content-Type": "application/x-git-upload-pack-request",
99 "Content-Encoding": "br",
100 "Git-Protocol": "version=2",
101 },
102 body,
103 } as any);
104 
105 expect(res.status).toBe(415);
106 expect(await res.text()).toContain("Unsupported Content-Encoding");
107});
108 
109it("upload-pack rejects invalid gzip payloads", async () => {
110 const owner = "o";
111 const repo = uniqueRepoId("r-encoding-invalid");
112 await setupRepoForTests(env, owner, repo);
113 const body = new Uint8Array([0x1f, 0x8b, 0x08, 0x00, 0x00]);
114 const url = `https://example.com/${owner}/${repo}/git-upload-pack`;
115 const res = await workerExports.default.fetch(url, {
116 method: "POST",
117 headers: {
118 "Content-Type": "application/x-git-upload-pack-request",
119 "Content-Encoding": "gzip",
120 "Git-Protocol": "version=2",
121 },
122 body,
123 } as any);
124 
125 expect(res.status).toBe(400);
126 expect(await res.text()).toContain("Invalid gzip request body");
127});