mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
fix: Set IncomingMessage.url to empty string for HTTPS requests to match Node.js
Fixes issue #13820 where https.request() returned "/" for response.url instead of an empty string like Node.js. The issue was that for FetchResponse type IncomingMessage objects, the url property was inheriting from the fetch Response.url which returns the pathname. Changes: - Modified IncomingMessage constructor to explicitly set url to "" for FetchResponse type - Added comprehensive tests covering various request scenarios - Ensures Node.js compatibility for response.url property 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -147,6 +147,11 @@ function IncomingMessage(req, options = defaultIncomingOpts) {
|
||||
if (!assignHeaders(this, req)) {
|
||||
this[fakeSocketSymbol] = req;
|
||||
}
|
||||
|
||||
// For fetch responses, set URL to empty string to match Node.js behavior
|
||||
if (type === NodeHTTPIncomingRequestType.FetchResponse) {
|
||||
this.url = "";
|
||||
}
|
||||
} else {
|
||||
// Node defaults url and method to null.
|
||||
this.url = "";
|
||||
|
||||
130
test/regression/issue/https-request-url-property.test.ts
Normal file
130
test/regression/issue/https-request-url-property.test.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { request as httpsRequest } from "https";
|
||||
import { request as httpRequest } from "http";
|
||||
|
||||
test("https.request URL property should be empty string like Node.js - issue #13820", async () => {
|
||||
const url = await new Promise<string>((resolve, reject) => {
|
||||
const req = httpsRequest("https://google.com", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume(); // Drain response to avoid hanging
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
// Node.js returns empty string, not "/"
|
||||
expect(url).toBe("");
|
||||
});
|
||||
|
||||
test("https.request URL property for root path with explicit slash", async () => {
|
||||
const url = await new Promise<string>((resolve, reject) => {
|
||||
const req = httpsRequest("https://google.com/", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
expect(url).toBe("");
|
||||
});
|
||||
|
||||
test("https.request URL property for path", async () => {
|
||||
const url = await new Promise<string>((resolve, reject) => {
|
||||
const req = httpsRequest("https://httpbin.org/json", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
expect(url).toBe("");
|
||||
});
|
||||
|
||||
test("http.request URL property should also be empty string", async () => {
|
||||
const url = await new Promise<string>((resolve, reject) => {
|
||||
const req = httpRequest("http://httpbin.org/json", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
expect(url).toBe("");
|
||||
});
|
||||
|
||||
test("https.request URL property with redirect", async () => {
|
||||
const url = await new Promise<string>((resolve, reject) => {
|
||||
const req = httpsRequest("https://httpbin.org/redirect/1", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
// Even after redirect, URL should still be empty string (Node.js behavior)
|
||||
expect(url).toBe("");
|
||||
});
|
||||
|
||||
test("https.request URL property consistency across multiple requests", async () => {
|
||||
const urls = await Promise.all([
|
||||
new Promise<string>((resolve, reject) => {
|
||||
const req = httpsRequest("https://httpbin.org/status/200", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
}),
|
||||
new Promise<string>((resolve, reject) => {
|
||||
const req = httpsRequest("https://httpbin.org/status/404", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(urls[0]).toBe("");
|
||||
expect(urls[1]).toBe("");
|
||||
});
|
||||
|
||||
test("https.request URL property type should be string", async () => {
|
||||
const url = await new Promise<any>((resolve, reject) => {
|
||||
const req = httpsRequest("https://httpbin.org/json", (res) => {
|
||||
resolve(res.url);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
expect(typeof url).toBe("string");
|
||||
expect(url).toBe("");
|
||||
});
|
||||
|
||||
test("https.request response object should have url property", async () => {
|
||||
const hasUrlProperty = await new Promise<boolean>((resolve, reject) => {
|
||||
const req = httpsRequest("https://httpbin.org/json", (res) => {
|
||||
resolve("url" in res);
|
||||
res.resume();
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.setTimeout(5000, () => reject(new Error("Timeout")));
|
||||
req.end();
|
||||
});
|
||||
|
||||
expect(hasUrlProperty).toBe(true);
|
||||
});
|
||||
Reference in New Issue
Block a user