Commit 3640880

Eric Bower  ·  2026-04-04 20:01:33 -0400 EDT
parent 6a3121d
fix(pgs): force redirect from root
3 files changed,  +59, -4
+24, -4
......@@ -112,6 +112,11 @@ func correlatePlaceholder(orig, pattern string) (string, string) {
112112 _type = "variable"
113113 }
114114
115+ // special case: root path matches root path
116+ if orig == "/" && pattern == "/" {
117+ return "/", "match"
118+ }
119+
115120 return filepath.Join(nextList...), _type
116121 }
117122
......@@ -250,10 +255,25 @@ func calcRoutes(projectName, fp string, userRedirects []*RedirectRule) []*HttpRe
250255 userReply := []*HttpReply{}
251256 var rule *HttpReply
252257 if redirect.To != "" {
253- rule = &HttpReply{
254- Filepath: route,
255- Status: redirect.Status,
256- Query: redirect.Query,
258+ // expand redirect target to find actual file (e.g., directory -> index.html)
259+ // but only if Force is true, it's not a full URL, and it's a directory path (ends with / but not just /)
260+ if redirect.Force && !hasProtocol(redirect.To) && strings.HasSuffix(route, "/") && route != "/" {
261+ expanded := expandRoute(projectName, route, redirect.Status)
262+ if len(expanded) > 0 {
263+ rule = expanded[0]
264+ } else {
265+ rule = &HttpReply{
266+ Filepath: route,
267+ Status: redirect.Status,
268+ Query: redirect.Query,
269+ }
270+ }
271+ } else {
272+ rule = &HttpReply{
273+ Filepath: route,
274+ Status: redirect.Status,
275+ Query: redirect.Query,
276+ }
257277 }
258278 userReply = append(userReply, rule)
259279 }
+19, -0
......@@ -663,6 +663,25 @@ func TestCalcRoutes(t *testing.T) {
663663 {Filepath: "public/404.html", Status: 404},
664664 },
665665 },
666+ {
667+ Name: "root-redirect",
668+ Actual: calcRoutes(
669+ "public",
670+ "/",
671+ []*RedirectRule{
672+ {
673+ From: "/",
674+ To: "/dax/cool/wow/",
675+ Status: 302,
676+ Force: true,
677+ },
678+ },
679+ ),
680+ Expected: []*HttpReply{
681+ {Filepath: "public/dax/cool/wow/index.html", Status: 302},
682+ {Filepath: "public/404.html", Status: 404},
683+ },
684+ },
666685 }
667686
668687 for _, fixture := range fixtures {
+16, -0
......@@ -141,6 +141,21 @@ func TestParseRedirectText(t *testing.T) {
141141 },
142142 }
143143
144+ rootRedirect := RedirectFixture{
145+ name: "root-redirect",
146+ input: "/ /dax/cool/wow/ 302!",
147+ expect: []*RedirectRule{
148+ {
149+ From: "/",
150+ To: "/dax/cool/wow/",
151+ Status: 302,
152+ Query: empty,
153+ Conditions: empty,
154+ Force: true,
155+ },
156+ },
157+ }
158+
144159 fixtures := []RedirectFixture{
145160 spa,
146161 rss,
......@@ -153,6 +168,7 @@ func TestParseRedirectText(t *testing.T) {
153168 selfReferentialWithVariables,
154169 externalUrlNotSelfRef,
155170 validPathRedirect,
171+ rootRedirect,
156172 }
157173
158174 for _, fixture := range fixtures {