123456789101112const BUCKET = "kohbucket";13const objects = new Map<string, Uint8Array>();1415async function handle(request: Request): Promise<Response> {16 const url = new URL(request.url);17 const [, bucket = "", ...rest] = url.pathname.split("/");18 if (bucket !== BUCKET) return new Response("", { status: 404 });19 if (url.searchParams.get("list-type") === "2") {20 const prefix = url.searchParams.get("prefix") ?? "";21 const keys = [...objects.keys()].filter((key) => key.startsWith(prefix)).sort();22 const contents = keys23 .map(24 (key) =>25 `<Contents><Key>${key}</Key><Size>${objects.get(key)?.length ?? 0}</Size></Contents>`,26 )27 .join("");28 return new Response(29 `<?xml version="1.0" encoding="UTF-8"?><ListBucketResult><IsTruncated>false</IsTruncated>${contents}</ListBucketResult>`,30 { headers: { "content-type": "application/xml" } },31 );32 }33 const key = rest.join("/");34 if (request.method === "PUT") {35 const body = new Uint8Array(await request.arrayBuffer());36 if (request.headers.get("if-none-match") === "*" && objects.has(key)) {37 return new Response("", { status: 412 });38 }39 objects.set(key, body);40 return new Response("", { status: 200, headers: { etag: `"${body.length}"` } });41 }42 if (request.method === "GET" || request.method === "HEAD") {43 const body = objects.get(key);44 if (!body) return new Response("", { status: 404 });45 return new Response(request.method === "HEAD" ? null : body, {46 status: 200,47 headers: { etag: `"${body.length}"`, "content-length": String(body.length) },48 });49 }50 if (request.method === "DELETE") {51 objects.delete(key);52 return new Response("", { status: 204 });53 }54 return new Response("", { status: 404 });55}5657const server = Bun.serve({ port: 0, fetch: handle });58console.log(`http://127.0.0.1:${server.port}`);