mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
test: break up node-http.test.ts (#23125)
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
# Thread::initializePlatformThreading() in ThreadingPOSIX.cpp) to the JS thread to suspend or resume
|
||||
# it. So stopping the process would just create noise when debugging any long-running script.
|
||||
process handle -p true -s false -n false SIGPWR
|
||||
process handle -p true -s false -n false SIGUSR1
|
||||
process handle -p true -s false -n false SIGUSR2
|
||||
|
||||
command script import -c lldb_pretty_printers.py
|
||||
type category enable zig.lang
|
||||
|
||||
@@ -579,8 +579,11 @@ async function runTests() {
|
||||
const title = relative(cwd, absoluteTestPath).replaceAll(sep, "/");
|
||||
if (isNodeTest(testPath)) {
|
||||
const testContent = readFileSync(absoluteTestPath, "utf-8");
|
||||
const runWithBunTest =
|
||||
title.includes("needs-test") || testContent.includes("bun:test") || testContent.includes("node:test");
|
||||
let runWithBunTest = title.includes("needs-test") || testContent.includes("node:test");
|
||||
// don't wanna have a filter for includes("bun:test") but these need our mocks
|
||||
runWithBunTest ||= title === "test/js/node/test/parallel/test-fs-append-file-flush.js";
|
||||
runWithBunTest ||= title === "test/js/node/test/parallel/test-fs-write-file-flush.js";
|
||||
runWithBunTest ||= title === "test/js/node/test/parallel/test-fs-write-stream-flush.js";
|
||||
const subcommand = runWithBunTest ? "test" : "run";
|
||||
const env = {
|
||||
FORCE_COLOR: "0",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { Server } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = Server((req, res) => {
|
||||
res.end();
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const res = await fetch(`http://localhost:${server.address().port}`, {
|
||||
method: "POST",
|
||||
body: new Uint8Array(1024 * 1024 * 200),
|
||||
});
|
||||
expect(res.status).toBe(200);
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer().listen(0);
|
||||
await once(server, "listening");
|
||||
fetch(`http://localhost:${server.address().port}`)
|
||||
.then(res => res.text())
|
||||
.catch(() => {});
|
||||
|
||||
const [req, res] = await once(server, "request");
|
||||
expect(req.complete).toBe(false);
|
||||
console.log("ok 1");
|
||||
const closeEvent = once(req, "close");
|
||||
res.end("hi");
|
||||
|
||||
await closeEvent;
|
||||
expect(req.complete).toBe(true);
|
||||
@@ -0,0 +1,14 @@
|
||||
import { once } from "node:events";
|
||||
import { createServer } from "node:http";
|
||||
import { createTest } from "node-harness";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer().listen(0);
|
||||
await once(server, "listening");
|
||||
fetch(`http://localhost:${server.address()!.port}`).then(res => res.text());
|
||||
const [req, res] = await once(server, "request");
|
||||
expect(res.headersSent).toBe(false);
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
res.end("OK", resolve);
|
||||
await promise;
|
||||
expect(res.headersSent).toBe(true);
|
||||
@@ -0,0 +1,32 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { IncomingMessage, Server } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
// This matches Node.js:
|
||||
const im = Object.create(IncomingMessage.prototype);
|
||||
IncomingMessage.call(im, { url: "/foo" });
|
||||
expect(im.url).toBe("");
|
||||
|
||||
let didCall = false;
|
||||
function Subclass(...args) {
|
||||
IncomingMessage.apply(this, args);
|
||||
didCall = true;
|
||||
}
|
||||
Object.setPrototypeOf(Subclass.prototype, IncomingMessage.prototype);
|
||||
Object.setPrototypeOf(Subclass, IncomingMessage);
|
||||
|
||||
await using server = new Server({ IncomingMessage: Subclass }, (req, res) => {
|
||||
if (req instanceof Subclass && didCall) {
|
||||
expect(req.url).toBe("/foo");
|
||||
res.writeHead(200, { "Content-Type": "text/plain" });
|
||||
res.end("hello");
|
||||
} else {
|
||||
res.writeHead(500, { "Content-Type": "text/plain" });
|
||||
res.end("bye");
|
||||
}
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const response = await fetch(`http://localhost:${server.address().port}/foo`, { method: "GET" });
|
||||
expect(response.status).toBe(200);
|
||||
12
test/js/bun/test/parallel/test-http-4415-Server-es5.ts
Normal file
12
test/js/bun/test/parallel/test-http-4415-Server-es5.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { Server } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = Server((req, res) => {
|
||||
res.end();
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const res = await fetch(`http://localhost:${server.address().port}`);
|
||||
expect(res.status).toBe(200);
|
||||
@@ -0,0 +1,11 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { ServerResponse } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
function Response(req) {
|
||||
ServerResponse.call(this, req);
|
||||
}
|
||||
Response.prototype = Object.create(ServerResponse.prototype);
|
||||
const req = {};
|
||||
const res = new Response(req);
|
||||
expect(res.req).toBe(req);
|
||||
@@ -0,0 +1,12 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { ServerResponse } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
class Response extends ServerResponse {
|
||||
constructor(req) {
|
||||
super(req);
|
||||
}
|
||||
}
|
||||
const req = {};
|
||||
const res = new Response(req);
|
||||
expect(res.req).toBe(req);
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createTest } from "node-harness";
|
||||
import https from "node:https";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
// TODO: today we use a workaround to continue event, we need to fix it in the future.
|
||||
|
||||
let receivedContinue = false;
|
||||
const req = https.request(
|
||||
"https://example.com",
|
||||
{ headers: { "accept-encoding": "identity", "expect": "100-continue" } },
|
||||
res => {
|
||||
let data = "";
|
||||
res.setEncoding("utf8");
|
||||
res.on("data", chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
res.on("end", () => {
|
||||
expect(receivedContinue).toBe(true);
|
||||
expect(data).toContain("This domain is for use in illustrative examples in documents");
|
||||
process.exit();
|
||||
});
|
||||
},
|
||||
);
|
||||
req.on("continue", () => {
|
||||
receivedContinue = true;
|
||||
});
|
||||
req.end();
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createTest } from "node-harness";
|
||||
import https from "node:https";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
let receivedContinue = false;
|
||||
const req = https.request("https://example.com", { headers: { "accept-encoding": "identity" } }, res => {
|
||||
let data = "";
|
||||
res.setEncoding("utf8");
|
||||
res.on("data", chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
res.on("end", () => {
|
||||
expect(receivedContinue).toBe(false);
|
||||
expect(data).toContain("This domain is for use in illustrative examples in documents");
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
req.on("continue", () => {
|
||||
receivedContinue = true;
|
||||
});
|
||||
req.end();
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { IncomingMessage } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const im = new IncomingMessage("http://localhost");
|
||||
expect(im.constructor).toBe(IncomingMessage);
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { OutgoingMessage } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const om = new OutgoingMessage();
|
||||
expect(om.constructor).toBe(OutgoingMessage);
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { Server } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const s = new Server();
|
||||
expect(s.constructor).toBe(Server);
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { ServerResponse } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const sr = new ServerResponse({});
|
||||
expect(sr.constructor).toBe(ServerResponse);
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const agent = new http.Agent();
|
||||
expect(agent.defaultPort).toBe(80);
|
||||
expect(agent.protocol).toBe("http:");
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http, { createServer } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer((req, res) => {
|
||||
expect(req.url).toBe("/hello");
|
||||
res.writeHead(200);
|
||||
res.end("world");
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const url = new URL(`http://127.0.0.1:${server.address().port}`);
|
||||
const { resolve, reject, promise } = Promise.withResolvers();
|
||||
http.get(new URL("/hello", url), res => {
|
||||
try {
|
||||
expect(res.req.agent.protocol).toBe("http:");
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
await promise;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const server = http.createServer();
|
||||
await once(server.listen(0), "listening");
|
||||
expect(server.listening).toBe(true);
|
||||
await server[Symbol.asyncDispose]();
|
||||
expect(server.listening).toBe(false);
|
||||
@@ -0,0 +1,45 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http, { createServer } from "node:http";
|
||||
import * as stream from "node:stream";
|
||||
import * as zlib from "node:zlib";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer((req, res) => {
|
||||
expect(req.url).toBe("/hello");
|
||||
res.writeHead(200);
|
||||
res.setHeader("content-encoding", "br");
|
||||
|
||||
const inputStream = new stream.Readable();
|
||||
inputStream.push("Hello World");
|
||||
inputStream.push(null);
|
||||
|
||||
const passthrough = new stream.PassThrough();
|
||||
passthrough.on("data", data => res.write(data));
|
||||
passthrough.on("end", () => res.end());
|
||||
|
||||
inputStream.pipe(zlib.createBrotliCompress()).pipe(passthrough);
|
||||
});
|
||||
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const url = new URL(`http://127.0.0.1:${server.address().port}`);
|
||||
|
||||
const { resolve, reject, promise } = Promise.withResolvers();
|
||||
http.get(new URL("/hello", url), res => {
|
||||
let rawData = "";
|
||||
const passthrough = stream.PassThrough();
|
||||
passthrough.on("data", chunk => {
|
||||
rawData += chunk;
|
||||
});
|
||||
passthrough.on("end", () => {
|
||||
try {
|
||||
expect(Buffer.from(rawData)).toEqual(Buffer.from("Hello World"));
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
res.pipe(zlib.createBrotliDecompress()).pipe(passthrough);
|
||||
});
|
||||
await promise;
|
||||
@@ -0,0 +1,24 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { createServer } from "node:http";
|
||||
import * as stream from "node:stream";
|
||||
import * as zlib from "node:zlib";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer((req, res) => {
|
||||
expect(req.url).toBe("/hello");
|
||||
res.writeHead(200);
|
||||
res.setHeader("content-encoding", "br");
|
||||
|
||||
const inputStream = new stream.Readable();
|
||||
inputStream.push("Hello World");
|
||||
inputStream.push(null);
|
||||
|
||||
inputStream.pipe(zlib.createBrotliCompress()).pipe(res);
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const url = new URL(`http://127.0.0.1:${server.address().port}`);
|
||||
|
||||
const res = await fetch(new URL("/hello", url));
|
||||
expect(await res.text()).toBe("Hello World");
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { createServer } from "node:http";
|
||||
import * as stream from "node:stream";
|
||||
import * as zlib from "node:zlib";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer((req, res) => {
|
||||
expect(req.url).toBe("/hello");
|
||||
res.writeHead(200);
|
||||
res.setHeader("content-encoding", "deflate");
|
||||
|
||||
const inputStream = new stream.Readable();
|
||||
inputStream.push("Hello World");
|
||||
inputStream.push(null);
|
||||
|
||||
inputStream.pipe(zlib.createDeflate()).pipe(res);
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const url = new URL(`http://127.0.0.1:${server.address().port}`);
|
||||
const res = await fetch(new URL("/hello", url));
|
||||
expect(await res.text()).toBe("Hello World");
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { createServer } from "node:http";
|
||||
import * as stream from "node:stream";
|
||||
import * as zlib from "node:zlib";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer((req, res) => {
|
||||
expect(req.url).toBe("/hello");
|
||||
res.writeHead(200);
|
||||
res.setHeader("content-encoding", "gzip");
|
||||
|
||||
const inputStream = new stream.Readable();
|
||||
inputStream.push("Hello World");
|
||||
inputStream.push(null);
|
||||
|
||||
inputStream.pipe(zlib.createGzip()).pipe(res);
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const url = new URL(`http://127.0.0.1:${server.address().port}`);
|
||||
const res = await fetch(new URL("/hello", url));
|
||||
expect(await res.text()).toBe("Hello World");
|
||||
@@ -0,0 +1,92 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import { connect } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer(async (req, res) => {
|
||||
res.writeHead(200, { "Content-Type": "text/plain", "Transfer-Encoding": "chunked" });
|
||||
// send some chunks at once
|
||||
res.write("chunk 1");
|
||||
res.write("chunk 2");
|
||||
res.write("chunk 3");
|
||||
res.write("chunk 4");
|
||||
res.write("chunk 5");
|
||||
await Bun.sleep(10);
|
||||
// send some more chunk
|
||||
res.write("chunk 6");
|
||||
res.write("chunk 7");
|
||||
await Bun.sleep(10);
|
||||
// send the last chunk
|
||||
res.end();
|
||||
});
|
||||
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const socket = connect(server.address().port, () => {
|
||||
socket.write(`GET / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: close\r\n\r\n`);
|
||||
});
|
||||
|
||||
const chunks = [];
|
||||
socket.on("data", data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
function parseChunkedData(buffer) {
|
||||
let offset = 0;
|
||||
let result = Buffer.alloc(0);
|
||||
|
||||
while (offset < buffer.length) {
|
||||
// Find the CRLF that terminates the chunk size line
|
||||
let lineEnd = buffer.indexOf("\r\n", offset);
|
||||
if (lineEnd === -1) break;
|
||||
|
||||
// Parse the chunk size (in hex)
|
||||
const chunkSizeHex = buffer.toString("ascii", offset, lineEnd);
|
||||
const chunkSize = parseInt(chunkSizeHex, 16);
|
||||
expect(isNaN(chunkSize)).toBe(false);
|
||||
// If chunk size is 0, we've reached the end
|
||||
if (chunkSize === 0) {
|
||||
// Skip the final CRLF after the 0-size chunk
|
||||
offset = lineEnd + 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move past the chunk size line's CRLF
|
||||
offset = lineEnd + 2;
|
||||
|
||||
// Extract the chunk data
|
||||
const chunkData = buffer.slice(offset, offset + chunkSize);
|
||||
|
||||
// Concatenate this chunk to our result
|
||||
result = Buffer.concat([result, chunkData]);
|
||||
|
||||
// Move past this chunk's data and its terminating CRLF
|
||||
offset += chunkSize + 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
socket.on("end", () => {
|
||||
try {
|
||||
const data = Buffer.concat(chunks);
|
||||
|
||||
const headersEnd = data.indexOf("\r\n\r\n");
|
||||
const headers = data.toString("utf-8", 0, headersEnd).split("\r\n");
|
||||
expect(headers[0]).toBe("HTTP/1.1 200 OK");
|
||||
expect(headers[1]).toBe("Content-Type: text/plain");
|
||||
expect(headers[2]).toBe("Transfer-Encoding: chunked");
|
||||
expect(headers[3].startsWith("Date:")).toBe(true);
|
||||
const body = parseChunkedData(data.slice(headersEnd + 4));
|
||||
expect(body.toString("utf-8")).toBe("chunk 1chunk 2chunk 3chunk 4chunk 5chunk 6chunk 7");
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
} finally {
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
await promise;
|
||||
@@ -0,0 +1,100 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import { connect } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer(async (req, res) => {
|
||||
res.writeHead(200, { "Content-Type": "text/plain", "Transfer-Encoding": "chunked" });
|
||||
res.flushHeaders();
|
||||
// make sure headers are flushed
|
||||
await Bun.sleep(10);
|
||||
// send some chunks at once
|
||||
res.write("chunk 1");
|
||||
res.write("chunk 2");
|
||||
res.write("chunk 3");
|
||||
res.write("chunk 4");
|
||||
res.write("chunk 5");
|
||||
await Bun.sleep(10);
|
||||
// send some more chunk
|
||||
res.write("chunk 6");
|
||||
res.write("chunk 7");
|
||||
await Bun.sleep(10);
|
||||
// send the last chunk
|
||||
res.end();
|
||||
});
|
||||
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const socket = connect(server.address().port, () => {
|
||||
socket.write(`GET / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: close\r\n\r\n`);
|
||||
});
|
||||
|
||||
const chunks = [];
|
||||
let received_headers = false;
|
||||
socket.on("data", data => {
|
||||
if (!received_headers) {
|
||||
received_headers = true;
|
||||
const headers = data.toString("utf-8").split("\r\n");
|
||||
expect(headers[0]).toBe("HTTP/1.1 200 OK");
|
||||
expect(headers[1]).toBe("Content-Type: text/plain");
|
||||
expect(headers[2]).toBe("Transfer-Encoding: chunked");
|
||||
expect(headers[3].startsWith("Date:")).toBe(true);
|
||||
// empty line for end of headers aka flushHeaders works
|
||||
expect(headers[headers.length - 1]).toBe("");
|
||||
expect(headers[headers.length - 2]).toBe("");
|
||||
} else {
|
||||
chunks.push(data);
|
||||
}
|
||||
});
|
||||
|
||||
function parseChunkedData(buffer) {
|
||||
let offset = 0;
|
||||
let result = Buffer.alloc(0);
|
||||
|
||||
while (offset < buffer.length) {
|
||||
// Find the CRLF that terminates the chunk size line
|
||||
let lineEnd = buffer.indexOf("\r\n", offset);
|
||||
if (lineEnd === -1) break;
|
||||
|
||||
// Parse the chunk size (in hex)
|
||||
const chunkSizeHex = buffer.toString("ascii", offset, lineEnd);
|
||||
const chunkSize = parseInt(chunkSizeHex, 16);
|
||||
expect(isNaN(chunkSize)).toBe(false);
|
||||
// If chunk size is 0, we've reached the end
|
||||
if (chunkSize === 0) {
|
||||
// Skip the final CRLF after the 0-size chunk
|
||||
offset = lineEnd + 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move past the chunk size line's CRLF
|
||||
offset = lineEnd + 2;
|
||||
|
||||
// Extract the chunk data
|
||||
const chunkData = buffer.slice(offset, offset + chunkSize);
|
||||
|
||||
// Concatenate this chunk to our result
|
||||
result = Buffer.concat([result, chunkData]);
|
||||
|
||||
// Move past this chunk's data and its terminating CRLF
|
||||
offset += chunkSize + 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
socket.on("end", () => {
|
||||
try {
|
||||
const body = parseChunkedData(Buffer.concat(chunks));
|
||||
expect(body.toString("utf-8")).toBe("chunk 1chunk 2chunk 3chunk 4chunk 5chunk 6chunk 7");
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
} finally {
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
await promise;
|
||||
@@ -0,0 +1,81 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import { connect } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer(async (req, res) => {
|
||||
res.writeHead(200, { "Content-Type": "text/plain", "Transfer-Encoding": "chunked" });
|
||||
res.write("chunk 1");
|
||||
res.end("chunk 2");
|
||||
});
|
||||
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const socket = connect(server.address().port, () => {
|
||||
socket.write(`GET / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: close\r\n\r\n`);
|
||||
});
|
||||
|
||||
const chunks = [];
|
||||
socket.on("data", data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
function parseChunkedData(buffer) {
|
||||
let offset = 0;
|
||||
let result = Buffer.alloc(0);
|
||||
|
||||
while (offset < buffer.length) {
|
||||
// Find the CRLF that terminates the chunk size line
|
||||
let lineEnd = buffer.indexOf("\r\n", offset);
|
||||
if (lineEnd === -1) break;
|
||||
|
||||
// Parse the chunk size (in hex)
|
||||
const chunkSizeHex = buffer.toString("ascii", offset, lineEnd);
|
||||
const chunkSize = parseInt(chunkSizeHex, 16);
|
||||
expect(isNaN(chunkSize)).toBe(false);
|
||||
// If chunk size is 0, we've reached the end
|
||||
if (chunkSize === 0) {
|
||||
// Skip the final CRLF after the 0-size chunk
|
||||
offset = lineEnd + 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move past the chunk size line's CRLF
|
||||
offset = lineEnd + 2;
|
||||
|
||||
// Extract the chunk data
|
||||
const chunkData = buffer.slice(offset, offset + chunkSize);
|
||||
|
||||
// Concatenate this chunk to our result
|
||||
result = Buffer.concat([result, chunkData]);
|
||||
|
||||
// Move past this chunk's data and its terminating CRLF
|
||||
offset += chunkSize + 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
socket.on("end", () => {
|
||||
try {
|
||||
const data = Buffer.concat(chunks);
|
||||
|
||||
const headersEnd = data.indexOf("\r\n\r\n");
|
||||
const headers = data.toString("utf-8", 0, headersEnd).split("\r\n");
|
||||
expect(headers[0]).toBe("HTTP/1.1 200 OK");
|
||||
expect(headers[1]).toBe("Content-Type: text/plain");
|
||||
expect(headers[2]).toBe("Transfer-Encoding: chunked");
|
||||
expect(headers[3].startsWith("Date:")).toBe(true);
|
||||
const body = parseChunkedData(data.slice(headersEnd + 4));
|
||||
expect(body.toString("utf-8")).toBe("chunk 1chunk 2");
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
} finally {
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
await promise;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
await using server = http.createServer((req, res) => {
|
||||
resolve([req, res]);
|
||||
});
|
||||
await once(server.listen(0), "listening");
|
||||
const address = server.address() as AddressInfo;
|
||||
http.get({
|
||||
host: "127.0.0.1",
|
||||
port: address.port,
|
||||
headers: [
|
||||
["foo", "bar"],
|
||||
["foo", "baz"],
|
||||
["host", "127.0.0.1"],
|
||||
["host", "127.0.0.2"],
|
||||
["host", "127.0.0.3"],
|
||||
],
|
||||
});
|
||||
|
||||
const [req, res] = await promise;
|
||||
expect(req.headers.foo).toBe("bar, baz");
|
||||
expect(req.headers.host).toBe("127.0.0.1");
|
||||
|
||||
res.end();
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
// Bun.serve is used here until #15576 or similar fix is merged
|
||||
using server = Bun.serve({
|
||||
port: 0,
|
||||
hostname: "127.0.0.1",
|
||||
fetch(req) {
|
||||
if (req.headers.get("transfer-encoding") !== "chunked") {
|
||||
return new Response("should be chunked encoding", { status: 500 });
|
||||
}
|
||||
return new Response(req.body);
|
||||
},
|
||||
});
|
||||
|
||||
// Options for the HTTP request
|
||||
const options = {
|
||||
hostname: "127.0.0.1", // Replace with the target server
|
||||
port: server.port,
|
||||
path: "/api/data",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
|
||||
// Create the request
|
||||
const req = http.request(options, res => {
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error("Body should be chunked"));
|
||||
}
|
||||
const chunks = [];
|
||||
// Collect the response data
|
||||
res.on("data", chunk => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
res.on("end", () => {
|
||||
resolve(chunks);
|
||||
});
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
req.on("error", reject);
|
||||
|
||||
// Write chunks to the request body
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
req.write("chunk");
|
||||
await sleep(50);
|
||||
req.write(" ");
|
||||
await sleep(50);
|
||||
}
|
||||
req.write("BUN!");
|
||||
// End the request and signal no more data will be sent
|
||||
req.end();
|
||||
|
||||
const chunks = await promise;
|
||||
expect(chunks.length).toBeGreaterThan(1);
|
||||
expect(chunks[chunks.length - 1]?.toString()).toEndWith("BUN!");
|
||||
expect(Buffer.concat(chunks).toString()).toBe("chunk ".repeat(4) + "BUN!");
|
||||
@@ -0,0 +1,59 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer((req, res) => {
|
||||
if (req.headers["transfer-encoding"] === "chunked") {
|
||||
return res.writeHead(500).end();
|
||||
}
|
||||
res.writeHead(200);
|
||||
req.on("data", data => {
|
||||
res.write(data);
|
||||
});
|
||||
req.on("end", () => {
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
|
||||
await once(server.listen(0, "127.0.0.1"), "listening");
|
||||
|
||||
// Options for the HTTP request
|
||||
const options = {
|
||||
hostname: "127.0.0.1", // Replace with the target server
|
||||
port: server.address().port,
|
||||
path: "/api/data",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
|
||||
// Create the request
|
||||
const req = http.request(options, res => {
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error("Body should not be chunked"));
|
||||
}
|
||||
const chunks = [];
|
||||
// Collect the response data
|
||||
res.on("data", chunk => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
res.on("end", () => {
|
||||
resolve(chunks);
|
||||
});
|
||||
});
|
||||
// Handle errors
|
||||
req.on("error", reject);
|
||||
// Write chunks to the request body
|
||||
req.write("Hello World BUN!");
|
||||
// End the request and signal no more data will be sent
|
||||
req.end();
|
||||
|
||||
const chunks = await promise;
|
||||
expect(chunks.length).toBe(1);
|
||||
expect(chunks[0]?.toString()).toBe("Hello World BUN!");
|
||||
expect(Buffer.concat(chunks).toString()).toBe("Hello World BUN!");
|
||||
@@ -0,0 +1,24 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
await using server = http.createServer((req, res) => {
|
||||
resolve(req.headers);
|
||||
res.end();
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const address = server.address() as AddressInfo;
|
||||
const req = http.request({
|
||||
method: "GET",
|
||||
host: "127.0.0.1",
|
||||
port: address.port,
|
||||
});
|
||||
req.setHeader("foo", "bar");
|
||||
req.flushHeaders();
|
||||
const headers = await promise;
|
||||
expect(headers).toBeDefined();
|
||||
expect(headers.foo).toEqual("bar");
|
||||
@@ -0,0 +1,24 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { createConnection } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer((req, res) => {
|
||||
res.end();
|
||||
});
|
||||
let socket;
|
||||
server.on("clientError", err => {
|
||||
expect(err.code).toBe("HPE_INVALID_METHOD");
|
||||
expect(err.rawPacket.toString()).toBe("*");
|
||||
|
||||
socket.end();
|
||||
});
|
||||
await once(server.listen(0), "listening");
|
||||
const address = server.address() as AddressInfo;
|
||||
socket = createConnection({ port: address.port });
|
||||
|
||||
await once(socket, "connect");
|
||||
socket.write("*");
|
||||
await once(socket, "close");
|
||||
@@ -0,0 +1,54 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { request } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
// just simulate some file that will take forever to download
|
||||
const payload = Buffer.alloc(128 * 1024, "X");
|
||||
for (let i = 0; i < 5; i++) {
|
||||
let sendedByteLength = 0;
|
||||
using server = Bun.serve({
|
||||
port: 0,
|
||||
async fetch(req) {
|
||||
let running = true;
|
||||
req.signal.onabort = () => (running = false);
|
||||
return new Response(async function* () {
|
||||
while (running) {
|
||||
sendedByteLength += payload.byteLength;
|
||||
yield payload;
|
||||
await Bun.sleep(10);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
async function run() {
|
||||
let receivedByteLength = 0;
|
||||
let { promise, resolve } = Promise.withResolvers();
|
||||
const req = request(server.url, res => {
|
||||
res.on("data", data => {
|
||||
receivedByteLength += data.length;
|
||||
if (resolve) {
|
||||
resolve();
|
||||
resolve = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
req.end();
|
||||
await promise;
|
||||
req.destroy();
|
||||
await Bun.sleep(10);
|
||||
const initialByteLength = receivedByteLength;
|
||||
// we should receive the same amount of data we sent
|
||||
expect(initialByteLength).toBeLessThanOrEqual(sendedByteLength);
|
||||
await Bun.sleep(10);
|
||||
// we should not receive more data after destroy
|
||||
expect(initialByteLength).toBe(receivedByteLength);
|
||||
await Bun.sleep(10);
|
||||
}
|
||||
|
||||
const runCount = 50;
|
||||
const runs = Array.from({ length: runCount }, run);
|
||||
await Promise.all(runs);
|
||||
Bun.gc(true);
|
||||
await Bun.sleep(10);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
expect(() => http.request("https://example.com")).toThrow(TypeError);
|
||||
expect(() => http.request("https://example.com")).toThrow({
|
||||
code: "ERR_INVALID_PROTOCOL",
|
||||
message: `Protocol "https:" not supported. Expected "http:"`,
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer((req, res) => {
|
||||
res.end(JSON.stringify(req.headers));
|
||||
});
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
for (let method of ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]) {
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
http
|
||||
.request(
|
||||
url,
|
||||
{
|
||||
method,
|
||||
},
|
||||
res => {
|
||||
const body: Uint8Array[] = [];
|
||||
res.on("data", chunk => {
|
||||
body.push(chunk);
|
||||
});
|
||||
res.on("end", () => {
|
||||
try {
|
||||
resolve(JSON.parse(Buffer.concat(body).toString()));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
.on("error", reject)
|
||||
.end();
|
||||
|
||||
const headers = (await promise) as Record<string, string | undefined>;
|
||||
expect(headers).toBeDefined();
|
||||
expect(headers["transfer-encoding"]).toBeUndefined();
|
||||
switch (method) {
|
||||
case "GET":
|
||||
case "DELETE":
|
||||
case "OPTIONS":
|
||||
// Content-Length will not be present for GET, DELETE, and OPTIONS
|
||||
// aka DELETE in node.js will be undefined and in bun it will be 0
|
||||
// this is not outside the spec but is different between node.js and bun
|
||||
expect(headers["content-length"]).toBeOneOf(["0", undefined]);
|
||||
break;
|
||||
default:
|
||||
expect(headers["content-length"]).toBeDefined();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers<string>();
|
||||
await using server = http.createServer((req, res) => {
|
||||
let body = "";
|
||||
req.setEncoding("utf8");
|
||||
req.on("data", chunk => (body += chunk));
|
||||
req.on("end", () => {
|
||||
resolve(body);
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const address = server.address() as AddressInfo;
|
||||
const req = http.request({
|
||||
method: "POST",
|
||||
host: "127.0.0.1",
|
||||
port: address.port,
|
||||
headers: { "content-type": "text/plain" },
|
||||
});
|
||||
|
||||
req.flushHeaders();
|
||||
req.write("bun");
|
||||
req.end("rocks");
|
||||
|
||||
const body = await promise;
|
||||
expect(body).toBe("bunrocks");
|
||||
10
test/js/bun/test/parallel/test-http-get-can-use-Agent.ts
Normal file
10
test/js/bun/test/parallel/test-http-get-can-use-Agent.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const agent = new http.Agent();
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
http.get({ agent, hostname: "google.com" }, resolve);
|
||||
const response = await promise;
|
||||
expect(response.req.port).toBe(80);
|
||||
expect(response.req.protocol).toBe("http:");
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
expect(() => http.request({ host: [1, 2, 3] })).toThrow(
|
||||
'The "options.host" property must be of type string, undefined, or null. Received an instance of Array',
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { createServer } from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = createServer().listen(0);
|
||||
await once(server, "listening");
|
||||
fetch(`http://localhost:${server.address().port}`).then(res => res.text());
|
||||
const [req, res] = await once(server, "request");
|
||||
expect(res.headersSent).toBe(false);
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
res.write("first", () => {
|
||||
res.write("second", () => {
|
||||
res.end("OK", resolve);
|
||||
});
|
||||
});
|
||||
await promise;
|
||||
expect(res.headersSent).toBe(true);
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http, { Server } from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
await using httpServer = http.createServer(function (req, res) {
|
||||
res.on("finish", () => resolve(req.connection.bytesWritten));
|
||||
res.writeHead(200, { "Content-Type": "text/plain" });
|
||||
|
||||
const chunk = "7".repeat(1024);
|
||||
const bchunk = Buffer.from(chunk);
|
||||
res.write(chunk);
|
||||
res.write(bchunk);
|
||||
|
||||
expect(res.connection.bytesWritten).toBe(1024 * 2);
|
||||
res.end("bunbunbun");
|
||||
});
|
||||
|
||||
await once(httpServer.listen(0), "listening");
|
||||
const address = httpServer.address() as AddressInfo;
|
||||
const req = http.get({ port: address.port });
|
||||
await once(req, "response");
|
||||
const bytesWritten = await promise;
|
||||
expect(typeof bytesWritten).toBe("number");
|
||||
expect(bytesWritten).toBe(1024 * 2 + 9);
|
||||
req.destroy();
|
||||
@@ -0,0 +1,9 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
http.request("http://google.com/", resolve).end();
|
||||
const response = await promise;
|
||||
expect(response.req.port).toBe(80);
|
||||
expect(response.req.protocol).toBe("http:");
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const server = http.createServer();
|
||||
await once(server.listen(0), "listening");
|
||||
expect(server.listening).toBe(true);
|
||||
server.closeAllConnections();
|
||||
expect(server.listening).toBe(false);
|
||||
@@ -0,0 +1,34 @@
|
||||
import { createTest } from "node-harness";
|
||||
import nodefs from "node:fs";
|
||||
import https from "node:https";
|
||||
import { sep } from "node:path";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = https.createServer(
|
||||
{
|
||||
key: nodefs.readFileSync(
|
||||
`${import.meta.dir}/../../../node/http/fixtures/openssl_localhost.key`.replaceAll("/", sep),
|
||||
),
|
||||
cert: nodefs.readFileSync(
|
||||
`${import.meta.dir}/../../../node/http/fixtures/openssl_localhost.crt`.replaceAll("/", sep),
|
||||
),
|
||||
passphrase: "123123123",
|
||||
},
|
||||
(req, res) => {
|
||||
res.write("Hello from https server");
|
||||
res.end();
|
||||
},
|
||||
);
|
||||
server.listen(0, "localhost");
|
||||
const address = server.address();
|
||||
let url_address = address.address;
|
||||
const res = await fetch(`https://localhost:${address.port}`, {
|
||||
tls: {
|
||||
rejectUnauthorized: true,
|
||||
ca: nodefs.readFileSync(
|
||||
`${import.meta.dir}/../../../node/http/fixtures/openssl_localhost_ca.pem`.replaceAll("/", sep),
|
||||
),
|
||||
},
|
||||
});
|
||||
const t = await res.text();
|
||||
expect(t).toEqual("Hello from https server");
|
||||
@@ -0,0 +1,35 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { createConnection } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer(async (req, res) => {
|
||||
expect(req.headers["empty-header"]).toBe("");
|
||||
res.writeHead(200, { "x-test": "test", "empty-header": "" });
|
||||
res.end();
|
||||
});
|
||||
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const socket = createConnection((server.address() as AddressInfo).port, "localhost", () => {
|
||||
socket.write(
|
||||
`GET / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: close\r\nEmpty-Header:\r\n\r\n`,
|
||||
);
|
||||
});
|
||||
|
||||
socket.on("data", data => {
|
||||
const headers = data.toString("utf-8").split("\r\n");
|
||||
expect(headers[0]).toBe("HTTP/1.1 200 OK");
|
||||
expect(headers[1]).toBe("x-test: test");
|
||||
expect(headers[2]).toBe("empty-header: ");
|
||||
socket.end();
|
||||
resolve();
|
||||
});
|
||||
|
||||
socket.on("error", reject);
|
||||
|
||||
await promise;
|
||||
@@ -0,0 +1,14 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer((req, res) => {
|
||||
res.writeHead(200, { "Strict-Transport-Security": "max-age=31536000" });
|
||||
res.end();
|
||||
});
|
||||
server.listen(0, "localhost");
|
||||
await once(server, "listening");
|
||||
const response = await fetch(`http://localhost:${server.address().port}`);
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("strict-transport-security")).toBe("max-age=31536000");
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
let server_headers;
|
||||
await using server = http.createServer((req, res) => {
|
||||
server_headers = req.headers;
|
||||
res.setHeader("x-number", 10);
|
||||
res.appendHeader("x-number-2", 20);
|
||||
res.end();
|
||||
});
|
||||
|
||||
await once(server.listen(0, "localhost"), "listening");
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
|
||||
{
|
||||
const response = http.request(`http://localhost:${server.address().port}`, resolve);
|
||||
response.setHeader("x-number", 30);
|
||||
response.appendHeader("x-number-2", 40);
|
||||
response.end();
|
||||
}
|
||||
const response = (await promise) as Record<string, string>;
|
||||
expect(response.headers["x-number"]).toBe("10");
|
||||
expect(response.headers["x-number-2"]).toBe("20");
|
||||
expect(server_headers["x-number"]).toBe("30");
|
||||
expect(server_headers["x-number-2"]).toBe("40");
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http, { Server } from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer((req, res) => {
|
||||
res.flushHeaders();
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
const address = server.address() as AddressInfo;
|
||||
const req = http.get(
|
||||
{
|
||||
hostname: address.address,
|
||||
port: address.port,
|
||||
},
|
||||
resolve,
|
||||
);
|
||||
|
||||
const { socket } = req;
|
||||
await promise;
|
||||
expect(socket._httpMessage).toBe(req);
|
||||
socket.destroy();
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import { connect } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer(reject);
|
||||
|
||||
server.on("clientError", (err, socket) => {
|
||||
resolve(err);
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const client = connect(server.address().port, () => {
|
||||
// HTTP request with invalid Content-Length
|
||||
// The Content-Length says 10 but the actual body is 20 bytes
|
||||
// Send the request
|
||||
client.write(
|
||||
`POST /test HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nContent-Type: text/plain\r\nContent-Length: invalid\r\n\r\n`,
|
||||
);
|
||||
});
|
||||
|
||||
const err = (await promise) as Error;
|
||||
expect(err.code).toBe("HPE_UNEXPECTED_CONTENT_LENGTH");
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import { connect } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer(reject);
|
||||
|
||||
server.on("clientError", (err, socket) => {
|
||||
resolve(err);
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
|
||||
const client = connect(server.address().port, () => {
|
||||
// HTTP request with invalid Content-Length
|
||||
// The Content-Length says 10 but the actual body is 20 bytes
|
||||
// Send the request
|
||||
client.write(
|
||||
`POST /test HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nContent-Type: text/plain\r\nContent-Length: 5\r\nTransfer-Encoding: chunked\r\n\r\nHello`,
|
||||
);
|
||||
});
|
||||
|
||||
const err = (await promise) as Error;
|
||||
expect(err.code).toBe("HPE_INVALID_TRANSFER_ENCODING");
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer().listen(0);
|
||||
server.unref();
|
||||
await once(server, "listening");
|
||||
const controller = new AbortController();
|
||||
fetch(`http://localhost:${server.address().port}`, { signal: controller.signal })
|
||||
.then(res => res.text())
|
||||
.catch(() => {});
|
||||
|
||||
const [req, res] = await once(server, "request");
|
||||
const closeEvent = Promise.withResolvers();
|
||||
req.once("close", () => {
|
||||
closeEvent.resolve();
|
||||
});
|
||||
controller.abort();
|
||||
await closeEvent.promise;
|
||||
expect(req.aborted).toBe(true);
|
||||
@@ -0,0 +1,33 @@
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
import { createTest } from "node-harness";
|
||||
import * as path from "node:path";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { stdout, exited } = Bun.spawn({
|
||||
cmd: [bunExe(), "run", path.join(import.meta.dir, "../../../node/http/fixtures/log-events.mjs")],
|
||||
stdout: "pipe",
|
||||
stdin: "ignore",
|
||||
stderr: "inherit",
|
||||
env: bunEnv,
|
||||
});
|
||||
const out = await stdout.text();
|
||||
// TODO prefinish and socket are not emitted in the right order
|
||||
expect(
|
||||
out
|
||||
.split("\n")
|
||||
.filter(Boolean)
|
||||
.map(x => JSON.parse(x)),
|
||||
).toStrictEqual([
|
||||
["req", "socket"],
|
||||
["req", "prefinish"],
|
||||
["req", "finish"],
|
||||
["req", "response"],
|
||||
"STATUS: 200",
|
||||
// TODO: not totally right:
|
||||
["res", "resume"],
|
||||
["req", "close"],
|
||||
["res", "readable"],
|
||||
["res", "end"],
|
||||
["res", "close"],
|
||||
]);
|
||||
expect(await exited).toBe(0);
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer().listen(0);
|
||||
await once(server, "listening");
|
||||
let callBackCalled = false;
|
||||
server.setTimeout(100, () => {
|
||||
callBackCalled = true;
|
||||
console.log("Called timeout");
|
||||
});
|
||||
|
||||
fetch(`http://localhost:${server.address().port}`, { verbose: true })
|
||||
.then(res => res.text())
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
const [req, res] = await once(server, "request");
|
||||
expect(req.complete).toBe(false);
|
||||
await once(server, "timeout");
|
||||
expect(callBackCalled).toBe(true);
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer().listen(0);
|
||||
await once(server, "listening");
|
||||
fetch(`http://localhost:${server.address().port}`)
|
||||
.then(res => res.text())
|
||||
.catch(() => {});
|
||||
|
||||
const [req, res] = await once(server, "request");
|
||||
expect(req.complete).toBe(false);
|
||||
let callBackCalled = false;
|
||||
req.setTimeout(100, () => {
|
||||
callBackCalled = true;
|
||||
});
|
||||
await once(req, "timeout");
|
||||
expect(callBackCalled).toBe(true);
|
||||
@@ -0,0 +1,34 @@
|
||||
import { createTest } from "node-harness";
|
||||
import nodefs from "node:fs";
|
||||
import https from "node:https";
|
||||
import * as path from "node:path";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = https.createServer(
|
||||
{
|
||||
key: nodefs.readFileSync(path.join(import.meta.dir, "../../..", "node/http/fixtures", "openssl_localhost.key")),
|
||||
cert: nodefs.readFileSync(path.join(import.meta.dir, "../../..", "node/http/fixtures", "openssl_localhost.crt")),
|
||||
passphrase: "123123123",
|
||||
},
|
||||
(req, res) => {
|
||||
res.write("Hello from https server");
|
||||
res.end();
|
||||
},
|
||||
);
|
||||
server.listen(0, "localhost");
|
||||
const address = server.address();
|
||||
|
||||
try {
|
||||
let url_address = address.address;
|
||||
const res = await fetch(`https://localhost:${address.port}`, {
|
||||
tls: {
|
||||
rejectUnauthorized: true,
|
||||
ca: "some invalid value for a ca",
|
||||
},
|
||||
});
|
||||
await res.text();
|
||||
expect(true).toBe("unreacheable");
|
||||
} catch (err) {
|
||||
expect(err.code).toBe("FailedToOpenSocket");
|
||||
expect(err.message).toBe("Was there a typo in the url or port?");
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
// Create a local server to receive data from
|
||||
await using server = http.createServer();
|
||||
|
||||
// Listen to the request event
|
||||
server.on("request", (request, res) => {
|
||||
setTimeout(() => {
|
||||
const body: Uint8Array[] = [];
|
||||
request.on("data", chunk => {
|
||||
body.push(chunk);
|
||||
});
|
||||
request.on("end", () => {
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(Buffer.concat(body));
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
const payload = "Hello, world!".repeat(10).toString();
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
body: payload,
|
||||
});
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.text()).toBe(payload);
|
||||
@@ -0,0 +1,29 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { createConnection } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer(async (req, res) => {
|
||||
expect.unreachable();
|
||||
});
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
server.on("connection", socket => {
|
||||
socket.on("error", (err: any) => {
|
||||
expect(err.code).toBe("HPE_HEADER_OVERFLOW");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const socket = createConnection((server.address() as AddressInfo).port, "localhost", () => {
|
||||
socket.write(
|
||||
`GET / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: close\r\nBig-Header: ` +
|
||||
"a".repeat(http.maxHeaderSize) + // will overflow because of host and connection headers
|
||||
"\r\n\r\n",
|
||||
);
|
||||
});
|
||||
socket.on("error", reject);
|
||||
await promise;
|
||||
@@ -0,0 +1,30 @@
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { createConnection } from "node:net";
|
||||
import { once } from "node:events";
|
||||
|
||||
import { createTest } from "node-harness";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = http.createServer(async (req, res) => {
|
||||
expect.unreachable();
|
||||
});
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
server.on("connection", socket => {
|
||||
socket.on("error", (err: any) => {
|
||||
expect(err.code).toBe("HPE_INVALID_METHOD");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
|
||||
const socket = createConnection((server.address() as AddressInfo).port, "localhost", () => {
|
||||
socket.write(
|
||||
`BUN / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: close\r\nBig-Header: ` +
|
||||
"a".repeat(http.maxHeaderSize) + // will overflow because of host and connection headers
|
||||
"\r\n\r\n",
|
||||
);
|
||||
});
|
||||
socket.on("error", reject);
|
||||
await promise;
|
||||
@@ -0,0 +1,36 @@
|
||||
import { createTest } from "node-harness";
|
||||
import nodefs from "node:fs";
|
||||
import https from "node:https";
|
||||
import * as path from "node:path";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await using server = https.createServer(
|
||||
{
|
||||
key: nodefs.readFileSync(path.join(import.meta.dir, "../../..", "node/http/fixtures", "openssl.key")),
|
||||
cert: nodefs.readFileSync(path.join(import.meta.dir, "../../..", "node/http/fixtures", "openssl.crt")),
|
||||
passphrase: "123123123",
|
||||
},
|
||||
(req, res) => {
|
||||
res.write("Hello from https server");
|
||||
res.end();
|
||||
},
|
||||
);
|
||||
server.listen(0, "127.0.0.1");
|
||||
const address = server.address();
|
||||
|
||||
try {
|
||||
let url_address = address.address;
|
||||
if (address.family === "IPv6") {
|
||||
url_address = `[${url_address}]`;
|
||||
}
|
||||
const res = await fetch(`https://${url_address}:${address.port}`, {
|
||||
tls: {
|
||||
rejectUnauthorized: true,
|
||||
},
|
||||
});
|
||||
await res.text();
|
||||
expect.unreachable();
|
||||
} catch (err) {
|
||||
expect(err.code).toBe("UNABLE_TO_VERIFY_LEAF_SIGNATURE");
|
||||
expect(err.message).toBe("unable to verify the first certificate");
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
|
||||
await using server = http.createServer((req, res) => {
|
||||
res.writeHead(200, { "Connection": "close" });
|
||||
|
||||
res.socket.end();
|
||||
res.on("error", reject);
|
||||
try {
|
||||
const result = res.write("Hello, world!");
|
||||
resolve(result);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
|
||||
await fetch(url, {
|
||||
method: "POST",
|
||||
body: Buffer.allocUnsafe(1024 * 1024 * 10),
|
||||
})
|
||||
.then(res => res.bytes())
|
||||
.catch(err => {});
|
||||
|
||||
expect(await promise).toBeTrue();
|
||||
@@ -0,0 +1,44 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
let body_not_allowed_on_write;
|
||||
let body_not_allowed_on_end;
|
||||
|
||||
await using server = http.createServer({
|
||||
rejectNonStandardBodyWrites: false,
|
||||
});
|
||||
|
||||
server.on("request", (req, res) => {
|
||||
body_not_allowed_on_write = false;
|
||||
body_not_allowed_on_end = false;
|
||||
res.writeHead(204);
|
||||
|
||||
try {
|
||||
res.write("bun");
|
||||
} catch (e: any) {
|
||||
expect(e?.code).toBe("ERR_HTTP_BODY_NOT_ALLOWED");
|
||||
body_not_allowed_on_write = true;
|
||||
}
|
||||
try {
|
||||
res.end("bun");
|
||||
} catch (e: any) {
|
||||
expect(e?.code).toBe("ERR_HTTP_BODY_NOT_ALLOWED");
|
||||
body_not_allowed_on_end = true;
|
||||
// if we throw here, we need to call end() to actually end the request
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
|
||||
{
|
||||
await fetch(url, {
|
||||
method: "GET",
|
||||
}).then(res => res.text());
|
||||
|
||||
expect(body_not_allowed_on_write).toBe(false);
|
||||
expect(body_not_allowed_on_end).toBe(false);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
let body_not_allowed_on_write;
|
||||
let body_not_allowed_on_end;
|
||||
|
||||
await using server = http.createServer({
|
||||
rejectNonStandardBodyWrites: true,
|
||||
});
|
||||
|
||||
server.on("request", (req, res) => {
|
||||
body_not_allowed_on_write = false;
|
||||
body_not_allowed_on_end = false;
|
||||
res.writeHead(204);
|
||||
|
||||
try {
|
||||
res.write("bun");
|
||||
} catch (e: any) {
|
||||
expect(e?.code).toBe("ERR_HTTP_BODY_NOT_ALLOWED");
|
||||
body_not_allowed_on_write = true;
|
||||
}
|
||||
try {
|
||||
res.end("bun");
|
||||
} catch (e: any) {
|
||||
expect(e?.code).toBe("ERR_HTTP_BODY_NOT_ALLOWED");
|
||||
body_not_allowed_on_end = true;
|
||||
// if we throw here, we need to call end() to actually end the request
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
|
||||
{
|
||||
await fetch(url, {
|
||||
method: "GET",
|
||||
}).then(res => res.text());
|
||||
|
||||
expect(body_not_allowed_on_write).toBe(true);
|
||||
expect(body_not_allowed_on_end).toBe(true);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
let body_not_allowed_on_write;
|
||||
let body_not_allowed_on_end;
|
||||
|
||||
await using server = http.createServer({
|
||||
rejectNonStandardBodyWrites: undefined,
|
||||
});
|
||||
|
||||
server.on("request", (req, res) => {
|
||||
body_not_allowed_on_write = false;
|
||||
body_not_allowed_on_end = false;
|
||||
res.writeHead(204);
|
||||
|
||||
try {
|
||||
res.write("bun");
|
||||
} catch (e: any) {
|
||||
expect(e?.code).toBe("ERR_HTTP_BODY_NOT_ALLOWED");
|
||||
body_not_allowed_on_write = true;
|
||||
}
|
||||
try {
|
||||
res.end("bun");
|
||||
} catch (e: any) {
|
||||
expect(e?.code).toBe("ERR_HTTP_BODY_NOT_ALLOWED");
|
||||
body_not_allowed_on_end = true;
|
||||
// if we throw here, we need to call end() to actually end the request
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
|
||||
{
|
||||
await fetch(url, {
|
||||
method: "GET",
|
||||
}).then(res => res.text());
|
||||
|
||||
expect(body_not_allowed_on_write).toBe(false);
|
||||
expect(body_not_allowed_on_end).toBe(false);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { createTest } from "node-harness";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
await new Promise(resolve => {
|
||||
const server = http.createServer((req, res) => {
|
||||
const { localAddress, localFamily, localPort } = req.socket;
|
||||
res.end();
|
||||
server.close();
|
||||
expect(localAddress).toStartWith("127.");
|
||||
expect(localFamily).toBe("IPv4");
|
||||
expect(localPort).toBeGreaterThan(0);
|
||||
resolve();
|
||||
});
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
http.request(`http://localhost:${server.address().port}`).end();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise(resolve => {
|
||||
const server = http.createServer((req, res) => {
|
||||
const { localAddress, localFamily, localPort } = req.socket;
|
||||
res.end();
|
||||
server.close();
|
||||
expect(localAddress).toStartWith("::");
|
||||
expect(localFamily).toBe("IPv6");
|
||||
expect(localPort).toBeGreaterThan(0);
|
||||
resolve();
|
||||
});
|
||||
server.listen(0, "::1", () => {
|
||||
http.request(`http://[::1]:${server.address().port}`).end();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
await using server = http.createServer((req, res) => {
|
||||
try {
|
||||
res.strictContentLength = true;
|
||||
res.writeHead(200, { "Content-Length": 10 });
|
||||
|
||||
res.write("123456789");
|
||||
|
||||
// Too much data
|
||||
try {
|
||||
res.write("123456789");
|
||||
expect.unreachable();
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
expect(e.code).toBe("ERR_HTTP_CONTENT_LENGTH_MISMATCH");
|
||||
}
|
||||
|
||||
// Too little data
|
||||
try {
|
||||
res.end();
|
||||
expect.unreachable();
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
expect(e.code).toBe("ERR_HTTP_CONTENT_LENGTH_MISMATCH");
|
||||
}
|
||||
|
||||
// Just right
|
||||
res.end("0");
|
||||
resolve();
|
||||
} catch (e: any) {
|
||||
reject(e);
|
||||
} finally {
|
||||
}
|
||||
});
|
||||
|
||||
await once(server.listen(0), "listening");
|
||||
const url = `http://localhost:${server.address().port}`;
|
||||
await fetch(url, { method: "GET" }).catch(() => {});
|
||||
await promise;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { kConnectionsCheckingInterval } = require("_http_server");
|
||||
const server = http.createServer();
|
||||
await once(server.listen(0), "listening");
|
||||
server.closeAllConnections();
|
||||
expect(server[kConnectionsCheckingInterval]._destroyed).toBe(true);
|
||||
27
test/js/bun/test/parallel/test-http-unref-works.ts
Normal file
27
test/js/bun/test/parallel/test-http-unref-works.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { once } from "events";
|
||||
import { isWindows } from "harness";
|
||||
import { createServer } from "http";
|
||||
|
||||
if (isWindows) process.exit(0); // Windows doesnt support SIGUSR1
|
||||
|
||||
const SIGNAL = process.platform === "linux" ? "SIGUSR2" : "SIGUSR1";
|
||||
const server = createServer((req, res) => {
|
||||
res.end();
|
||||
});
|
||||
server.listen(0);
|
||||
await once(server, "listening");
|
||||
const port = server.address().port;
|
||||
process.on(SIGNAL, async () => {
|
||||
server.unref();
|
||||
|
||||
// check that the server is still running
|
||||
const resp = await fetch(`http://localhost:${port}`);
|
||||
await resp.arrayBuffer();
|
||||
console.log("Unref'd & server still running (as expected)");
|
||||
});
|
||||
const resp = await fetch(`http://localhost:${port}`);
|
||||
await resp.arrayBuffer();
|
||||
if (resp.status !== 200) {
|
||||
process.exit(42);
|
||||
}
|
||||
process.kill(process.pid, SIGNAL);
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createTest } from "node-harness";
|
||||
import https from "node:https";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const agent = new https.Agent();
|
||||
expect(agent.defaultPort).toBe(443);
|
||||
expect(agent.protocol).toBe("https:");
|
||||
10
test/js/bun/test/parallel/test-https-get-can-use-Agent.ts
Normal file
10
test/js/bun/test/parallel/test-https-get-can-use-Agent.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { createTest } from "node-harness";
|
||||
import https from "node:https";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const agent = new https.Agent();
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
https.get({ agent, hostname: "google.com" }, resolve);
|
||||
const response = await promise;
|
||||
expect(response.req.port).toBe(443);
|
||||
expect(response.req.protocol).toBe("https:");
|
||||
@@ -0,0 +1,33 @@
|
||||
import { tls as COMMON_TLS_CERT } from "harness";
|
||||
import { createTest } from "node-harness";
|
||||
import { once } from "node:events";
|
||||
import { Server } from "node:http";
|
||||
import https, { createServer as createHttpsServer } from "node:https";
|
||||
import type { AddressInfo } from "node:net";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
await using httpServer = createHttpsServer(COMMON_TLS_CERT, function (req, res) {
|
||||
res.on("finish", () => resolve(req.connection.bytesWritten));
|
||||
res.writeHead(200, { "Content-Type": "text/plain" });
|
||||
|
||||
// Write 1.5mb to cause some requests to buffer
|
||||
// Also, mix up the encodings a bit.
|
||||
const chunk = "7".repeat(1024);
|
||||
const bchunk = Buffer.from(chunk);
|
||||
res.write(chunk);
|
||||
res.write(bchunk);
|
||||
// Get .bytesWritten while buffer is not empty
|
||||
expect(res.connection.bytesWritten).toBe(1024 * 2);
|
||||
|
||||
res.end("bunbunbun");
|
||||
});
|
||||
|
||||
await once(httpServer.listen(0), "listening");
|
||||
const address = httpServer.address() as AddressInfo;
|
||||
const req = https.get({ port: address.port, rejectUnauthorized: false });
|
||||
await once(req, "response");
|
||||
const bytesWritten = await promise;
|
||||
expect(typeof bytesWritten).toBe("number");
|
||||
expect(bytesWritten).toBe(1024 * 2 + 9);
|
||||
req.destroy();
|
||||
@@ -0,0 +1,9 @@
|
||||
import { createTest } from "node-harness";
|
||||
import https from "node:https";
|
||||
const { expect } = createTest(import.meta.path);
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
https.request("https://google.com/", resolve).end();
|
||||
const response = await promise;
|
||||
expect(response.req.port).toBe(443);
|
||||
expect(response.req.protocol).toBe("https:");
|
||||
@@ -0,0 +1,8 @@
|
||||
import https from "node:https";
|
||||
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
const client = https.request("https://example.com/", { agent: false });
|
||||
client.on("error", reject);
|
||||
client.on("close", resolve);
|
||||
client.end();
|
||||
await promise;
|
||||
20
test/js/node/http/node-http-ref-fixture.js
generated
20
test/js/node/http/node-http-ref-fixture.js
generated
@@ -1,20 +0,0 @@
|
||||
import { createServer } from "http";
|
||||
const SIGNAL = process.platform === "linux" ? "SIGUSR2" : "SIGUSR1";
|
||||
var server = createServer((req, res) => {
|
||||
res.end();
|
||||
}).listen(0, async (err, hostname, port) => {
|
||||
process.on(SIGNAL, async () => {
|
||||
server.unref();
|
||||
|
||||
// check that the server is still running
|
||||
const resp = await fetch(`http://localhost:${port}`);
|
||||
await resp.arrayBuffer();
|
||||
console.log("Unref'd & server still running (as expected)");
|
||||
});
|
||||
const resp = await fetch(`http://localhost:${port}`);
|
||||
await resp.arrayBuffer();
|
||||
if (resp.status !== 200) {
|
||||
process.exit(42);
|
||||
}
|
||||
process.kill(process.pid, SIGNAL);
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -145,6 +145,7 @@ test/js/node/test/parallel/test-tls-fast-writing.js
|
||||
test/js/bun/sqlite/sqlite.test.js
|
||||
test/js/workerd/html-rewriter.test.js
|
||||
test/regression/issue/12250.test.ts
|
||||
test/js/bun/test/parallel/test-http-10177-response.write-with-non-ascii-latin1-should-not-cause-duplicated-character-or-segfault.ts
|
||||
|
||||
|
||||
# crash for reasons not related to LSAN
|
||||
|
||||
Reference in New Issue
Block a user