@@ -11,18 +11,22 @@ import {
1111 SeeOtherResponse ,
1212 TemporaryRedirectResponse ,
1313} from "../../utils/responses" ;
14+ import { mockJaegerBinding } from "../../utils/tracing" ;
1415import {
1516 flagIsEnabled ,
1617 SEC_FETCH_MODE_NAVIGATE_HEADER_PREFERS_ASSET_SERVING ,
1718} from "./compatibility-flags" ;
1819import { attachCustomHeaders , getAssetHeaders } from "./utils/headers" ;
19- import { generateRulesMatcher , replacer } from "./utils/rules-engine" ;
20+ import {
21+ generateRedirectsMatcher ,
22+ staticRedirectsMatcher ,
23+ } from "./utils/rules-engine" ;
2024import type { AssetConfig } from "../../utils/types" ;
2125import type { Analytics } from "./analytics" ;
2226import type EntrypointType from "./index" ;
2327import type { Env } from "./index" ;
2428
25- const REDIRECTS_VERSION = 1 ;
29+ export const REDIRECTS_VERSION = 1 ;
2630export const HEADERS_VERSION = 2 ;
2731
2832type AssetIntent = {
@@ -39,77 +43,20 @@ const getResponseOrAssetIntent = async (
3943 exists : typeof EntrypointType . prototype . unstable_exists
4044) : Promise < Response | AssetIntentWithResolver > => {
4145 const url = new URL ( request . url ) ;
42- const { host, search } = url ;
43- let { pathname } = url ;
44-
45- const staticRedirectsMatcher = ( ) => {
46- const withHostMatch =
47- configuration . redirects . staticRules [ `https://${ host } ${ pathname } ` ] ;
48- const withoutHostMatch = configuration . redirects . staticRules [ pathname ] ;
49-
50- if ( withHostMatch && withoutHostMatch ) {
51- if ( withHostMatch . lineNumber < withoutHostMatch . lineNumber ) {
52- return withHostMatch ;
53- } else {
54- return withoutHostMatch ;
55- }
56- }
57-
58- return withHostMatch || withoutHostMatch ;
59- } ;
60-
61- const generateRedirectsMatcher = ( ) =>
62- generateRulesMatcher (
63- configuration . redirects . version === REDIRECTS_VERSION
64- ? configuration . redirects . rules
65- : { } ,
66- ( { status, to } , replacements ) => ( {
67- status,
68- to : replacer ( to , replacements ) ,
69- } )
70- ) ;
46+ const { search } = url ;
7147
72- const redirectMatch =
73- staticRedirectsMatcher ( ) || generateRedirectsMatcher ( ) ( { request } ) [ 0 ] ;
74-
75- let proxied = false ;
76-
77- if ( redirectMatch ) {
78- if ( redirectMatch . status === 200 ) {
79- // A 200 redirect means that we are proxying/rewriting to a different asset, for example,
80- // a request with url /users/12345 could be pointed to /users/id.html. In order to
81- // do this, we overwrite the pathname, and instead match for assets with that url,
82- // and importantly, do not use the regular redirect handler - as the url visible to
83- // the user does not change
84- pathname = new URL ( redirectMatch . to , request . url ) . pathname ;
85- proxied = true ;
86- } else {
87- const { status, to } = redirectMatch ;
88- const destination = new URL ( to , request . url ) ;
89- const location =
90- destination . origin === new URL ( request . url ) . origin
91- ? `${ destination . pathname } ${ destination . search || search } ${
92- destination . hash
93- } `
94- : `${ destination . href . slice ( 0 , destination . href . length - ( destination . search . length + destination . hash . length ) ) } ${
95- destination . search ? destination . search : search
96- } ${ destination . hash } `;
97-
98- switch ( status ) {
99- case MovedPermanentlyResponse . status :
100- return new MovedPermanentlyResponse ( location ) ;
101- case SeeOtherResponse . status :
102- return new SeeOtherResponse ( location ) ;
103- case TemporaryRedirectResponse . status :
104- return new TemporaryRedirectResponse ( location ) ;
105- case PermanentRedirectResponse . status :
106- return new PermanentRedirectResponse ( location ) ;
107- case FoundResponse . status :
108- default :
109- return new FoundResponse ( location ) ;
110- }
111- }
48+ const redirectResult = handleRedirects (
49+ env ,
50+ request ,
51+ configuration ,
52+ url . host ,
53+ url . pathname ,
54+ search
55+ ) ;
56+ if ( redirectResult instanceof Response ) {
57+ return redirectResult ;
11258 }
59+ const { proxied, pathname } = redirectResult ;
11360
11461 const decodedPathname = decodePath ( pathname ) ;
11562
@@ -306,7 +253,7 @@ export const handleRequest = async (
306253 analytics
307254 ) ;
308255
309- return attachCustomHeaders ( request , response , configuration ) ;
256+ return attachCustomHeaders ( request , response , configuration , env ) ;
310257} ;
311258
312259type Resolver = "html-handling" | "not-found" ;
@@ -1048,3 +995,76 @@ const encodePath = (pathname: string) => {
1048995 } )
1049996 . join ( "/" ) ;
1050997} ;
998+
999+ const handleRedirects = (
1000+ env : Env ,
1001+ request : Request ,
1002+ configuration : Required < AssetConfig > ,
1003+ host : string ,
1004+ pathname : string ,
1005+ search : string
1006+ ) : { proxied : boolean ; pathname : string } | Response => {
1007+ const jaeger = env . JAEGER ?? mockJaegerBinding ( ) ;
1008+ return jaeger . enterSpan ( "handle_redirects" , ( span ) => {
1009+ const redirectMatch =
1010+ staticRedirectsMatcher ( configuration , host , pathname ) ||
1011+ generateRedirectsMatcher ( configuration ) ( { request } ) [ 0 ] ;
1012+
1013+ let proxied = false ;
1014+ if ( redirectMatch ) {
1015+ if ( redirectMatch . status === 200 ) {
1016+ // A 200 redirect means that we are proxying/rewriting to a different asset, for example,
1017+ // a request with url /users/12345 could be pointed to /users/id.html. In order to
1018+ // do this, we overwrite the pathname, and instead match for assets with that url,
1019+ // and importantly, do not use the regular redirect handler - as the url visible to
1020+ // the user does not change
1021+ pathname = new URL ( redirectMatch . to , request . url ) . pathname ;
1022+ proxied = true ;
1023+
1024+ span . setTags ( {
1025+ matched : true ,
1026+ proxied : true ,
1027+ new_path : pathname ,
1028+ status : redirectMatch . status ,
1029+ } ) ;
1030+ } else {
1031+ const { status, to } = redirectMatch ;
1032+ const destination = new URL ( to , request . url ) ;
1033+ const location =
1034+ destination . origin === new URL ( request . url ) . origin
1035+ ? `${ destination . pathname } ${ destination . search || search } ${
1036+ destination . hash
1037+ } `
1038+ : `${ destination . href . slice ( 0 , destination . href . length - ( destination . search . length + destination . hash . length ) ) } ${
1039+ destination . search ? destination . search : search
1040+ } ${ destination . hash } `;
1041+
1042+ span . setTags ( {
1043+ matched : true ,
1044+ destination : location ,
1045+ status,
1046+ } ) ;
1047+
1048+ switch ( status ) {
1049+ case MovedPermanentlyResponse . status :
1050+ return new MovedPermanentlyResponse ( location ) ;
1051+ case SeeOtherResponse . status :
1052+ return new SeeOtherResponse ( location ) ;
1053+ case TemporaryRedirectResponse . status :
1054+ return new TemporaryRedirectResponse ( location ) ;
1055+ case PermanentRedirectResponse . status :
1056+ return new PermanentRedirectResponse ( location ) ;
1057+ case FoundResponse . status :
1058+ default :
1059+ return new FoundResponse ( location ) ;
1060+ }
1061+ }
1062+ } else {
1063+ span . setTags ( {
1064+ matched : false ,
1065+ } ) ;
1066+ }
1067+
1068+ return { proxied, pathname } ;
1069+ } ) ;
1070+ } ;
0 commit comments