Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 210d57d

Browse files
committed
Include additional Cloudflare headers in HTML error page
1 parent d0ba6fe commit 210d57d

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

packages/http-server/src/index.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ export async function convertNodeRequest(
6565
}
6666
}
6767

68+
// Add additional Cloudflare specific headers:
69+
// https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
70+
const proto = meta?.forwardedProto ?? "https";
71+
let ip = meta?.realIp ?? req.socket.remoteAddress ?? "";
72+
// Convert IPv6 loopback address to IPv4 address
73+
if (ip === "::1") ip = "127.0.0.1";
74+
// Remove IPv6 prefix for IPv4 addresses
75+
if (ip.startsWith("::ffff:")) ip = ip.substring("::ffff:".length);
76+
// We're a bit naughty here mutating the incoming request, but this ensures
77+
// the headers are included in the pretty-error page. If we used the new
78+
// converted Request instance's headers, we wouldn't have connection, keep-
79+
// alive, etc as we strip those
80+
req.headers["x-forwarded-proto"] ??= proto;
81+
req.headers["x-real-ip"] ??= ip;
82+
req.headers["cf-connecting-ip"] ??= ip;
83+
req.headers["cf-ipcountry"] ??= meta?.cf?.country ?? "US";
84+
req.headers["cf-ray"] ??= randomHex(16);
85+
req.headers["cf-visitor"] ??= `{"scheme":"${proto}"}`;
86+
6887
// Build Headers object from request
6988
const headers = new Headers();
7089
for (const [name, values] of Object.entries(req.headers)) {
@@ -85,21 +104,6 @@ export async function convertNodeRequest(
85104
}
86105
}
87106

88-
// Add additional Cloudflare specific headers:
89-
// https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
90-
const proto = meta?.forwardedProto ?? "https";
91-
let ip = meta?.realIp ?? req.socket.remoteAddress ?? "";
92-
// Convert IPv6 loopback address to IPv4 address
93-
if (ip === "::1") ip = "127.0.0.1";
94-
// Remove IPv6 prefix for IPv4 addresses
95-
if (ip.startsWith("::ffff:")) ip = ip.substring("::ffff:".length);
96-
headers.set("x-forwarded-proto", proto);
97-
headers.set("x-real-ip", ip);
98-
headers.set("cf-connecting-ip", ip);
99-
headers.set("cf-ipcountry", meta?.cf?.country ?? "US");
100-
headers.set("cf-ray", randomHex(16));
101-
headers.set("cf-visitor", `{"scheme":"${proto}"}`);
102-
103107
// Create Request with additional Cloudflare specific properties:
104108
// https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties
105109
const request = new Request(url, {

packages/http-server/test/index.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,21 @@ test("createRequestListener: includes live reload script in html error responses
374374
[body] = await request(port, "/", { accept: "text/html" });
375375
t.regex(body, /Miniflare Live Reload/);
376376
});
377+
test("createRequestListener: includes CF-* headers in html error response", async (t) => {
378+
const log = new TestLog();
379+
log.error = () => {};
380+
const mf = useMiniflareWithHandler(
381+
{ HTTPPlugin },
382+
{},
383+
() => {
384+
throw new Error();
385+
},
386+
log
387+
);
388+
const port = await listen(t, http.createServer(createRequestListener(mf)));
389+
const [body] = await request(port, "/", { accept: "text/html" });
390+
t.regex(body, /CF-CONNECTING-IP/);
391+
});
377392

378393
test("createServer: handles regular requests", async (t) => {
379394
const mf = useMiniflareWithHandler({ HTTPPlugin }, {}, (globals) => {

0 commit comments

Comments
 (0)