@@ -439,6 +439,131 @@ describe('node', () => {
439439 ) ;
440440 assert . equal ( result . url , 'https://example.com/' ) ;
441441 } ) ;
442+ it ( 'accepts x-forwarded-proto when allowedDomains has protocol and hostname' , ( ) => {
443+ const result = createRequest (
444+ {
445+ ...mockNodeRequest ,
446+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
447+ headers : {
448+ host : 'myapp.example.com' ,
449+ 'x-forwarded-host' : 'myapp.example.com' ,
450+ 'x-forwarded-proto' : 'https' ,
451+ } ,
452+ } ,
453+ { allowedDomains : [ { protocol : 'https' , hostname : 'myapp.example.com' } ] } ,
454+ ) ;
455+ // Without the fix, protocol validation fails due to hostname mismatch
456+ // and falls back to socket.encrypted (false → http)
457+ assert . equal ( result . url , 'https://myapp.example.com/' ) ;
458+ } ) ;
459+
460+ it ( 'rejects x-forwarded-proto when it does not match protocol in allowedDomains' , ( ) => {
461+ const result = createRequest (
462+ {
463+ ...mockNodeRequest ,
464+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
465+ headers : {
466+ host : 'myapp.example.com' ,
467+ 'x-forwarded-proto' : 'http' ,
468+ } ,
469+ } ,
470+ { allowedDomains : [ { protocol : 'https' , hostname : 'myapp.example.com' } ] } ,
471+ ) ;
472+ // http is not in allowedDomains (only https), protocol falls back to socket (false → http)
473+ // Host validation also fails because http doesn't match the pattern's protocol: 'https'
474+ assert . equal ( result . url , 'http://localhost/' ) ;
475+ } ) ;
476+
477+ it ( 'accepts x-forwarded-proto with wildcard hostname pattern in allowedDomains' , ( ) => {
478+ const result = createRequest (
479+ {
480+ ...mockNodeRequest ,
481+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
482+ headers : {
483+ 'x-forwarded-host' : 'joel.example.com' ,
484+ 'x-forwarded-proto' : 'https' ,
485+ } ,
486+ } ,
487+ { allowedDomains : [ { protocol : 'https' , hostname : '**.example.com' } ] } ,
488+ ) ;
489+ assert . equal ( result . url , 'https://joel.example.com/' ) ;
490+ } ) ;
491+
492+ it ( 'constructs correct URL behind reverse proxy with all forwarded headers' , ( ) => {
493+ // Simulates: Reverse proxy terminates TLS, connects to Astro via HTTP,
494+ // forwards original protocol/host/port via X-Forwarded-* headers
495+ const result = createRequest (
496+ {
497+ ...mockNodeRequest ,
498+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
499+ headers : {
500+ host : 'myapp.example.com' ,
501+ 'x-forwarded-proto' : 'https' ,
502+ 'x-forwarded-host' : 'myapp.example.com' ,
503+ } ,
504+ } ,
505+ { allowedDomains : [ { protocol : 'https' , hostname : 'myapp.example.com' } ] } ,
506+ ) ;
507+ assert . equal ( result . url , 'https://myapp.example.com/' ) ;
508+ } ) ;
509+
510+ it ( 'hmmm' , ( ) => {
511+ const result = createRequest (
512+ {
513+ ...mockNodeRequest ,
514+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
515+ headers : {
516+ host : 'something-other.com' ,
517+ 'x-forwarded-proto' : 'https' ,
518+ 'x-forwarded-host' : 'myapp.example.com' ,
519+ } ,
520+ } ,
521+ { allowedDomains : [ { protocol : 'https' , hostname : 'another.example.com' } ] } ,
522+ ) ;
523+ // should be 'http://something-other.com/' no?
524+ assert . equal ( result . url , 'http://localhost/' ) ;
525+ } ) ;
526+
527+ it ( 'trick validate-headers' , ( ) => {
528+ const result = createRequest (
529+ {
530+ ...mockNodeRequest ,
531+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
532+ headers : {
533+ host : 'this-header-does-nothing.com' ,
534+ 'x-forwarded-host' : 'myapp.example.com' ,
535+ } ,
536+ } ,
537+ {
538+ allowedDomains : [
539+ { protocol : 'http' , hostname : 'local.domain' } ,
540+ { protocol : 'https' , hostname : 'myapp.example.com' }
541+ ]
542+ } ,
543+ ) ;
544+
545+ assert . equal ( result . url , 'http://localhost/' ) ;
546+ } ) ;
547+
548+ it ( 'trick validate-headers 2' , ( ) => {
549+ const result = createRequest (
550+ {
551+ ...mockNodeRequest ,
552+ socket : { encrypted : false , remoteAddress : '2.2.2.2' } ,
553+ headers : {
554+ 'x-forwarded-proto' : 'https' ,
555+ } ,
556+ } ,
557+ {
558+ allowedDomains : [
559+ { protocol : 'https' , hostname : 'myapp.example.com' }
560+ ]
561+ } ,
562+ ) ;
563+
564+ assert . equal ( result . url , 'http://localhost/' ) ;
565+ } ) ;
566+
442567 } ) ;
443568
444569 describe ( 'x-forwarded-port' , ( ) => {
0 commit comments