From e6b2fed2fcd23e7d5428eeed6ea4fffef9954b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Mon, 13 Jun 2022 09:52:02 +0200 Subject: [PATCH] Fix relURL with leading slash when baseURL includes a subdirectory Fixes #9994 --- helpers/pathspec_test.go | 7 +++++-- helpers/url.go | 25 ++++++++++++++----------- helpers/url_test.go | 24 +++++++++++++++++------- hugolib/paths/paths.go | 15 ++++++++++++--- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/helpers/pathspec_test.go b/helpers/pathspec_test.go index c1129951671..84448050d5e 100644 --- a/helpers/pathspec_test.go +++ b/helpers/pathspec_test.go @@ -32,7 +32,7 @@ func TestNewPathSpecFromConfig(t *testing.T) { v.Set("uglyURLs", true) v.Set("canonifyURLs", true) v.Set("paginatePath", "side") - v.Set("baseURL", "http://base.com") + v.Set("baseURL", "http://base.com/foo") v.Set("themesDir", "thethemes") v.Set("layoutDir", "thelayouts") v.Set("workingDir", "thework") @@ -53,7 +53,10 @@ func TestNewPathSpecFromConfig(t *testing.T) { c.Assert(p.Language.Lang, qt.Equals, "no") c.Assert(p.PaginatePath, qt.Equals, "side") - c.Assert(p.BaseURL.String(), qt.Equals, "http://base.com") + c.Assert(p.BaseURL.String(), qt.Equals, "http://base.com/foo") + c.Assert(p.BaseURLString, qt.Equals, "http://base.com/foo") + c.Assert(p.BaseURLNoPathString, qt.Equals, "http://base.com") + c.Assert(p.ThemesDir, qt.Equals, "thethemes") c.Assert(p.WorkingDir, qt.Equals, "thework") } diff --git a/helpers/url.go b/helpers/url.go index 193dd3c8641..7cb998ca25b 100644 --- a/helpers/url.go +++ b/helpers/url.go @@ -103,17 +103,11 @@ func (p *PathSpec) AbsURL(in string, addLanguage bool) string { } if url.IsAbs() || strings.HasPrefix(in, "//") { + // It is already absolute, return it as is. return in } - var baseURL string - if strings.HasPrefix(in, "/") { - u := p.BaseURL.URL() - u.Path = "" - baseURL = u.String() - } else { - baseURL = p.BaseURL.String() - } + baseURL := p.getBaseURLRoot(in) if addLanguage { prefix := p.GetLanguagePrefix() @@ -140,13 +134,22 @@ func (p *PathSpec) AbsURL(in string, addLanguage bool) string { } } } + return paths.MakePermalink(baseURL, in).String() } -// RelURL creates a URL relative to the BaseURL root. -// Note: The result URL will not include the context root if canonifyURLs is enabled. +func (p *PathSpec) getBaseURLRoot(path string) string { + if strings.HasPrefix(path, "/") { + // Treat it as relative to the server root. + return p.BaseURLNoPathString + } else { + // Treat it as relative to the baseURL. + return p.BaseURLString + } +} + func (p *PathSpec) RelURL(in string, addLanguage bool) string { - baseURL := p.BaseURL.String() + baseURL := p.getBaseURLRoot(in) canonifyURLs := p.CanonifyURLs if (!strings.HasPrefix(in, baseURL) && strings.HasPrefix(in, "http")) || strings.HasPrefix(in, "//") { return in diff --git a/helpers/url_test.go b/helpers/url_test.go index f899e1cdbb9..e248036aee9 100644 --- a/helpers/url_test.go +++ b/helpers/url_test.go @@ -17,6 +17,7 @@ import ( "strings" "testing" + qt "github.com/frankban/quicktest" "github.com/gohugoio/hugo/hugofs" "github.com/gohugoio/hugo/langs" ) @@ -59,6 +60,7 @@ func TestAbsURL(t *testing.T) { } func doTestAbsURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, lang string) { + c := qt.New(t) v := newTestCfg() v.Set("multilingual", multilingual) v.Set("defaultContentLanguage", "en") @@ -69,6 +71,10 @@ func doTestAbsURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, baseURL string expected string }{ + // Issue 9994 + {"foo/bar", "https://example.org/foo/", "https://example.org/foo/MULTIfoo/bar"}, + {"/foo/bar", "https://example.org/foo/", "https://example.org/MULTIfoo/bar"}, + {"/test/foo", "http://base/", "http://base/MULTItest/foo"}, {"/" + lang + "/test/foo", "http://base/", "http://base/" + lang + "/test/foo"}, {"", "http://base/ace/", "http://base/ace/MULTI"}, @@ -113,9 +119,8 @@ func doTestAbsURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, } else { expected = strings.Replace(expected, "MULTI", "", 1) } - if output != expected { - t.Fatalf("Expected %#v, got %#v\n", expected, output) - } + + c.Assert(output, qt.Equals, expected) } } @@ -132,6 +137,7 @@ func TestRelURL(t *testing.T) { } func doTestRelURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, lang string) { + c := qt.New(t) v := newTestCfg() v.Set("multilingual", multilingual) v.Set("defaultContentLanguage", "en") @@ -143,13 +149,18 @@ func doTestRelURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, canonify bool expected string }{ + + // Issue 9994 + {"/foo/bar", "https://example.org/foo/", false, "MULTI/foo/bar"}, + {"foo/bar", "https://example.org/foo/", false, "/fooMULTI/foo/bar"}, + {"/test/foo", "http://base/", false, "MULTI/test/foo"}, {"/" + lang + "/test/foo", "http://base/", false, "/" + lang + "/test/foo"}, {lang + "/test/foo", "http://base/", false, "/" + lang + "/test/foo"}, {"test.css", "http://base/sub", false, "/subMULTI/test.css"}, {"test.css", "http://base/sub", true, "MULTI/test.css"}, {"/test/", "http://base/", false, "MULTI/test/"}, - {"/test/", "http://base/sub/", false, "/subMULTI/test/"}, + {"test/", "http://base/sub/", false, "/subMULTI/test/"}, {"/test/", "http://base/sub/", true, "MULTI/test/"}, {"", "http://base/ace/", false, "/aceMULTI/"}, {"", "http://base/ace", false, "/aceMULTI"}, @@ -189,9 +200,8 @@ func doTestRelURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, expected = strings.Replace(expected, "MULTI", "", 1) } - if output != expected { - t.Errorf("[%d][%t] Expected %#v, got %#v\n", i, test.canonify, expected, output) - } + c.Assert(output, qt.Equals, expected, qt.Commentf("[%d] %s", i, test.input)) + } } diff --git a/hugolib/paths/paths.go b/hugolib/paths/paths.go index 501665676c2..e80215b92a0 100644 --- a/hugolib/paths/paths.go +++ b/hugolib/paths/paths.go @@ -34,6 +34,8 @@ type Paths struct { Cfg config.Provider BaseURL + BaseURLString string + BaseURLNoPathString string // If the baseURL contains a base path, e.g. https://example.com/docs, then "/docs" will be the BasePath. BasePath string @@ -145,10 +147,17 @@ func New(fs *hugofs.Fs, cfg config.Provider) (*Paths, error) { } } + var baseURLString = baseURL.String() + var baseURLNoPath = baseURL.URL() + baseURLNoPath.Path = "" + var baseURLNoPathString = baseURLNoPath.String() + p := &Paths{ - Fs: fs, - Cfg: cfg, - BaseURL: baseURL, + Fs: fs, + Cfg: cfg, + BaseURL: baseURL, + BaseURLString: baseURLString, + BaseURLNoPathString: baseURLNoPathString, DisablePathToLower: cfg.GetBool("disablePathToLower"), RemovePathAccents: cfg.GetBool("removePathAccents"),