Skip to content

Commit 3115ac8

Browse files
cursoragentkitsonk
andcommitted
Add tests for x-forwarded headers parsing and validation
Co-authored-by: me <[email protected]>
1 parent f9b5f04 commit 3115ac8

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

request.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,80 @@ Deno.test({
287287
);
288288
},
289289
});
290+
291+
Deno.test({
292+
name: "request.x-forwarded-for - splits, trims, and orders correctly",
293+
fn() {
294+
const request = new Request(
295+
createMockNativeRequest("https://example.com/index.html", {
296+
headers: {
297+
"x-forwarded-host": "example.com",
298+
"x-forwarded-proto": "http",
299+
"x-forwarded-for": " 10.10.10.10 , 192.168.1.1 , [::1] ",
300+
},
301+
}),
302+
{ proxy: true, secure: true },
303+
);
304+
assertEquals(request.ips, ["10.10.10.10", "192.168.1.1", "[::1]"]);
305+
assertEquals(request.ip, "10.10.10.10");
306+
},
307+
});
308+
309+
Deno.test({
310+
name: "request.x-forwarded-for - caps entries and is performant",
311+
fn() {
312+
const manyIps = Array.from({ length: 1000 }, (_, i) => `10.0.0.${i}`).join(", ");
313+
const request = new Request(
314+
createMockNativeRequest("https://example.com/index.html", {
315+
headers: {
316+
"x-forwarded-host": "example.com",
317+
"x-forwarded-proto": "http",
318+
// also prepend some whitespace noise to mimic worst-case patterns
319+
"x-forwarded-for": ` \t ${manyIps} \t `,
320+
},
321+
}),
322+
{ proxy: true, secure: true },
323+
);
324+
performance.mark("start-xff");
325+
const ips = request.ips;
326+
const measure = performance.measure("xff", { start: "start-xff" });
327+
// Hard upper bound; the operation should be very fast
328+
assert(measure.duration < 20);
329+
// Ensure we cap the number of parsed IPs (implementation caps at 100)
330+
assertEquals(ips.length, 100);
331+
assertEquals(ips[0], "10.0.0.0");
332+
},
333+
});
334+
335+
Deno.test({
336+
name: "request.x-forwarded-proto - normalizes and allowlists http/https",
337+
fn() {
338+
const request = new Request(
339+
createMockNativeRequest("http://example.com/index.html", {
340+
headers: {
341+
"x-forwarded-host": "example.com",
342+
"x-forwarded-proto": " HTTPS , http ",
343+
},
344+
}),
345+
{ proxy: true },
346+
);
347+
assertEquals(request.url.protocol, "https:");
348+
},
349+
});
350+
351+
Deno.test({
352+
name: "request.x-forwarded-proto - invalid values fall back to http",
353+
fn() {
354+
const request = new Request(
355+
createMockNativeRequest("http://example.com/index.html", {
356+
headers: {
357+
"x-forwarded-host": "example.com",
358+
// first token invalid, second valid, we only honor the first
359+
"x-forwarded-proto": "javascript, https",
360+
},
361+
}),
362+
{ proxy: true },
363+
);
364+
assertEquals(request.url.protocol, "http:");
365+
},
366+
});

0 commit comments

Comments
 (0)