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