diff --git a/gno.land/pkg/gnoweb/gnoweb.go b/gno.land/pkg/gnoweb/gnoweb.go index 714ad12dbdd..0ccdc0b5d53 100644 --- a/gno.land/pkg/gnoweb/gnoweb.go +++ b/gno.land/pkg/gnoweb/gnoweb.go @@ -9,6 +9,7 @@ import ( "io/fs" "log/slog" "net/http" + "net/url" "os" "path/filepath" "runtime" @@ -125,7 +126,7 @@ func MakeApp(logger *slog.Logger, cfg Config) gotuna.App { app.Router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { path := r.RequestURI - handleNotFound(app, &cfg, path, w, r) + handleNotFound(logger, app, &cfg, path, w, r) }) return app } @@ -451,12 +452,12 @@ func handlerStaticFile(logger *slog.Logger, app gotuna.App, cfg *Config) http.Ha fpath := filepath.Clean(vars["path"]) f, err := fs.Open(fpath) if os.IsNotExist(err) { - handleNotFound(app, cfg, fpath, w, r) + handleNotFound(logger, app, cfg, fpath, w, r) return } stat, err := f.Stat() if err != nil || stat.IsDir() { - handleNotFound(app, cfg, fpath, w, r) + handleNotFound(logger, app, cfg, fpath, w, r) return } @@ -474,7 +475,7 @@ func handlerFavicon(logger *slog.Logger, app gotuna.App, cfg *Config) http.Handl fpath := "img/favicon.ico" f, err := fs.Open(fpath) if os.IsNotExist(err) { - handleNotFound(app, cfg, fpath, w, r) + handleNotFound(logger, app, cfg, fpath, w, r) return } w.Header().Set("Content-Type", "image/x-icon") @@ -483,11 +484,17 @@ func handlerFavicon(logger *slog.Logger, app gotuna.App, cfg *Config) http.Handl }) } -func handleNotFound(app gotuna.App, cfg *Config, path string, w http.ResponseWriter, r *http.Request) { +func handleNotFound(logger *slog.Logger, app gotuna.App, cfg *Config, path string, w http.ResponseWriter, r *http.Request) { + // decode path for non-ascii characters + decodedPath, err := url.PathUnescape(path) + if err != nil { + logger.Error("failed to decode path", err) + decodedPath = path + } w.WriteHeader(http.StatusNotFound) app.NewTemplatingEngine(). Set("title", "Not found"). - Set("path", path). + Set("path", decodedPath). Set("Config", cfg). Render(w, r, "404.html", "funcs.html") } @@ -508,7 +515,7 @@ func pathOf(diruri string) string { parts := strings.Split(diruri, "/") if parts[0] == "gno.land" { return "/" + strings.Join(parts[1:], "/") - } else { - panic(fmt.Sprintf("invalid dir-URI %q", diruri)) } + + panic(fmt.Sprintf("invalid dir-URI %q", diruri)) } diff --git a/gno.land/pkg/gnoweb/gnoweb_test.go b/gno.land/pkg/gnoweb/gnoweb_test.go index 86a739b4a36..55434e3b9fc 100644 --- a/gno.land/pkg/gnoweb/gnoweb_test.go +++ b/gno.land/pkg/gnoweb/gnoweb_test.go @@ -42,6 +42,10 @@ func TestRoutes(t *testing.T) { {"/gor", found, "/game-of-realms"}, {"/blog", found, "/r/gnoland/blog"}, {"/404-not-found", notFound, "/404-not-found"}, + {"/아스키문자가아닌경로", notFound, "/아스키문자가아닌경로"}, + {"/%ED%85%8C%EC%8A%A4%ED%8A%B8", notFound, "/테스트"}, + {"/グノー", notFound, "/グノー"}, + {"/⚛️", notFound, "/⚛️"}, } config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) @@ -65,7 +69,6 @@ func TestRoutes(t *testing.T) { assert.Equal(t, r.status, response.Code) assert.Contains(t, response.Body.String(), r.substring) - // println(response.Body.String()) }) } }