mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 10:58:56 +00:00
179 lines
4.9 KiB
TypeScript
179 lines
4.9 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { isBroken, isWindows, withoutAggressiveGC } from "harness";
|
|
import { tmpdir } from "os";
|
|
import { join } from "path";
|
|
|
|
test("uploads roundtrip", async () => {
|
|
const body = Bun.file(import.meta.dir + "/fetch.js.txt");
|
|
const bodyText = await body.text();
|
|
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
development: false,
|
|
async fetch(req) {
|
|
const text = await req.text();
|
|
expect(text).toBe(bodyText);
|
|
|
|
return new Response(Bun.file(import.meta.dir + "/fetch.js.txt"));
|
|
},
|
|
});
|
|
|
|
// @ts-ignore
|
|
const reqBody = new Request(`http://${server.hostname}:${server.port}`, {
|
|
body,
|
|
method: "POST",
|
|
});
|
|
const res = await fetch(reqBody);
|
|
expect(res.status).toBe(200);
|
|
|
|
// but it does for Response
|
|
expect(res.headers.get("Content-Type")).toBe("text/plain;charset=utf-8");
|
|
const resText = await res.text();
|
|
expect(resText).toBe(bodyText);
|
|
});
|
|
|
|
// https://github.com/oven-sh/bun/issues/3969
|
|
test("formData uploads roundtrip, with a call to .body", async () => {
|
|
const file = Bun.file(import.meta.dir + "/fetch.js.txt");
|
|
const body = new FormData();
|
|
body.append("file", file, "fetch.js.txt");
|
|
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
development: false,
|
|
async fetch(req) {
|
|
req.body;
|
|
|
|
return new Response(await req.formData());
|
|
},
|
|
});
|
|
|
|
// @ts-ignore
|
|
const reqBody = new Request(`http://${server.hostname}:${server.port}`, {
|
|
body,
|
|
method: "POST",
|
|
});
|
|
const res = await fetch(reqBody);
|
|
expect(res.status).toBe(200);
|
|
|
|
// but it does for Response
|
|
expect(res.headers.get("Content-Type")).toStartWith("multipart/form-data; boundary=");
|
|
res.body;
|
|
const resData = await res.formData();
|
|
expect(await (resData.get("file") as Blob).arrayBuffer()).toEqual(await file.arrayBuffer());
|
|
});
|
|
|
|
test("req.formData throws error when stream is in use", async () => {
|
|
const file = Bun.file(import.meta.dir + "/fetch.js.txt");
|
|
const body = new FormData();
|
|
body.append("file", file, "fetch.js.txt");
|
|
var pass = false;
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
development: false,
|
|
error(fail) {
|
|
pass = true;
|
|
if (fail.toString().includes("already used")) {
|
|
return new Response("pass");
|
|
}
|
|
return new Response("fail");
|
|
},
|
|
async fetch(req) {
|
|
var reader = req.body?.getReader();
|
|
await reader?.read();
|
|
await req.formData();
|
|
throw new Error("should not reach here");
|
|
},
|
|
});
|
|
|
|
// @ts-ignore
|
|
const reqBody = new Request(`http://${server.hostname}:${server.port}`, {
|
|
body,
|
|
method: "POST",
|
|
});
|
|
const res = await fetch(reqBody);
|
|
expect(res.status).toBe(200);
|
|
|
|
// but it does for Response
|
|
expect(await res.text()).toBe("pass");
|
|
expect(pass).toBe(true);
|
|
});
|
|
|
|
test("formData uploads roundtrip, without a call to .body", async () => {
|
|
const file = Bun.file(import.meta.dir + "/fetch.js.txt");
|
|
const body = new FormData();
|
|
body.append("file", file, "fetch.js.txt");
|
|
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
development: false,
|
|
async fetch(req) {
|
|
return new Response(await req.formData());
|
|
},
|
|
});
|
|
|
|
// @ts-ignore
|
|
const reqBody = new Request(`http://${server.hostname}:${server.port}`, {
|
|
body,
|
|
method: "POST",
|
|
});
|
|
const res = await fetch(reqBody);
|
|
expect(res.status).toBe(200);
|
|
|
|
// but it does for Response
|
|
expect(res.headers.get("Content-Type")).toStartWith("multipart/form-data; boundary=");
|
|
const resData = await res.formData();
|
|
expect(await (resData.get("file") as Blob).arrayBuffer()).toEqual(await file.arrayBuffer());
|
|
});
|
|
|
|
test.todoIf(isBroken && isWindows)(
|
|
"uploads roundtrip with sendfile()",
|
|
async () => {
|
|
const hugeTxt = Buffer.allocUnsafe(1024 * 1024 * 32 * "huge".length);
|
|
hugeTxt.fill("huge");
|
|
const hash = Bun.CryptoHasher.hash("sha256", hugeTxt, "hex");
|
|
|
|
const path = join(tmpdir(), "huge.txt");
|
|
require("fs").writeFileSync(path, hugeTxt);
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
development: false,
|
|
maxRequestBodySize: hugeTxt.byteLength * 2,
|
|
async fetch(req) {
|
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
for await (let chunk of req.body!) {
|
|
hasher.update(chunk);
|
|
}
|
|
return new Response(hasher.digest("hex"));
|
|
},
|
|
});
|
|
|
|
const resp = await fetch(server.url, {
|
|
body: Bun.file(path),
|
|
method: "PUT",
|
|
});
|
|
|
|
expect(resp.status).toBe(200);
|
|
expect(await resp.text()).toBe(hash);
|
|
},
|
|
10_000,
|
|
);
|
|
|
|
test("missing file throws the expected error", async () => {
|
|
Bun.gc(true);
|
|
// Run this 1000 times to check for GC bugs
|
|
withoutAggressiveGC(() => {
|
|
const body = Bun.file(import.meta.dir + "/fetch123123231123.js.txt");
|
|
for (let i = 0; i < 1000; i++) {
|
|
const resp = fetch(`http://example.com`, {
|
|
body,
|
|
method: "POST",
|
|
proxy: "http://localhost:3000",
|
|
});
|
|
expect(Bun.peek.status(resp)).toBe("rejected");
|
|
expect(async () => await resp).toThrow("no such file or directory");
|
|
}
|
|
});
|
|
Bun.gc(true);
|
|
});
|