Fix server rebuilds on editing content with Chinese terms

Fixes #14240
This commit is contained in:
Bjørn Erik Pedersen
2025-12-05 11:33:55 +01:00
parent 9e7182e9e6
commit e2e64aeec5
5 changed files with 79 additions and 2 deletions

View File

@@ -49,6 +49,7 @@ import (
"github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/tpl/tplimpl"
@@ -370,6 +371,12 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
if f.c.fastRenderMode && f.c.errState.buildErr() == nil {
if isNavigation(requestURI, r) {
// See issue 14240.
// Hugo escapes the URL paths when generating them,
// that may not be the case when we receive it back from the browser.
// PathEscape will escape if it is not already escaped.
requestURI = paths.PathEscape(requestURI)
if !f.c.visitedURLs.Contains(requestURI) {
// If not already on stack, re-render that single page.
if err := f.c.partialReRender(requestURI); err != nil {

View File

@@ -347,3 +347,25 @@ func BenchmarkAddLeadingSlash(b *testing.B) {
}
})
}
func TestPathEscape(t *testing.T) {
c := qt.New(t)
for _, this := range []struct {
input string
expected string
}{
{"/tags/欢迎", "/tags/%E6%AC%A2%E8%BF%8E"},
{"/path with spaces", "/path%20with%20spaces"},
{"/simple-path", "/simple-path"},
{"/path/with/slash", "/path/with/slash"},
{"/path/with special&chars", "/path/with%20special&chars"},
} {
in := this.input
for range 2 {
result := PathEscape(in)
c.Assert(result, qt.Equals, this.expected, qt.Commentf("input: %q", this.input))
in = result // test idempotency
}
}
}

View File

@@ -2051,6 +2051,29 @@ tags: ["tag1"]
b.AssertFileContent("public/tags/index.html", "All. Tag1|$")
}
func TestRebuildPageWithChineseTag14240(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.com"
disableLiveReload = true
-- layouts/all.html --
All. {{ range .Pages }}{{ .RelPermalink }}: {{ .Title }}|{{ end }}$
-- content/p1.md --
---
title: "P1"
tags: ["欢迎"]
---
`
b := TestRunning(t, files)
b.AssertFileContent("public/tags/欢迎/index.html", "All. /p1/: P1|$")
b.EditFileReplaceAll("content/p1.md", "P1", "P1 edit").Build()
b.AssertFileContent("public/tags/欢迎/index.html", "All. /p1/: P1 edit|$")
}
func TestRebuildEditNonReferencedResourceIssue13748(t *testing.T) {
t.Parallel()

View File

@@ -248,7 +248,7 @@ var commonTestScriptsParam = testscript.Params{
// httpget checks that a HTTP resource's body matches (if it compiles as a regexp) or contains all of the strings given as arguments.
"httpget": func(ts *testscript.TestScript, neg bool, args []string) {
if len(args) < 2 {
ts.Fatalf("usage: httpgrep URL STRING...")
ts.Fatalf("usage: httpget URL STRING...")
}
tryget := func() error {
@@ -375,7 +375,7 @@ var commonTestScriptsParam = testscript.Params{
// The server will write a .ready file when ready.
// We wait for that.
readyFilename := ts.MkAbs(".ready")
limit := time.Now().Add(5 * time.Second)
limit := time.Now().Add(10 * time.Second)
for {
_, err := os.Stat(readyFilename)
if err != nil {

View File

@@ -0,0 +1,25 @@
# Issue 14240.
hugo server &
waitServer
httpget ${HUGOTEST_BASEURL_0}tags/%E6%AC%A2%E8%BF%8E/ '_P1_'
replace $WORK/content/p1.md 'P1' 'P1 New'
httpget ${HUGOTEST_BASEURL_0}tags/%E6%AC%A2%E8%BF%8E/ '_P1 New_'
stopServer
! stderr .
-- hugo.toml --
baseURL = "https://example.com"
disableLiveReload = true
-- layouts/all.html --
All. {{ range .Pages }}_{{ .Title }}_{{ end }}$
-- content/p1.md --
---
title: "P1"
tags: ["欢迎"]
---