From 69d8d5f73514458b6cc59c96a63e552a05ffebb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sat, 30 Mar 2019 17:08:25 +0100 Subject: [PATCH] hugolib: Allow page-relative aliases Fixes #5757 --- docs/content/en/content-management/urls.md | 8 ++++++-- hugolib/alias.go | 17 ++++++++--------- hugolib/alias_test.go | 19 ++++++++++--------- hugolib/page__meta.go | 6 ++++-- hugolib/site_render.go | 15 ++++++++++++++- hugolib/site_stats_test.go | 2 +- hugolib/site_url_test.go | 2 +- 7 files changed, 44 insertions(+), 25 deletions(-) diff --git a/docs/content/en/content-management/urls.md b/docs/content/en/content-management/urls.md index 25bd0916516..bc6caee9f84 100644 --- a/docs/content/en/content-management/urls.md +++ b/docs/content/en/content-management/urls.md @@ -82,9 +82,13 @@ The following is a list of values that can be used in a `permalink` definition i ## Aliases -For people migrating existing published content to Hugo, there's a good chance you need a mechanism to handle redirecting old URLs. +Aliases can be used to create redirects to your page from other URLs. -Luckily, redirects can be handled easily with **aliases** in Hugo. + +Aliases comes in two forms + +1. They start with a `/` meaning they are relative to the `BaseURL`, e.g. `/posts/my-blogpost/` +2. They are relative to the `Page` they're defined in, e.g. `my-blogpost` or even something like `../blog/my-blogpost` (new in Hugo 0.55). ### Example: Aliases diff --git a/hugolib/alias.go b/hugolib/alias.go index 599821c0ac5..6382d518cc8 100644 --- a/hugolib/alias.go +++ b/hugolib/alias.go @@ -18,7 +18,7 @@ import ( "fmt" "html/template" "io" - "path/filepath" + "path" "runtime" "strings" @@ -28,8 +28,6 @@ import ( "github.com/gohugoio/hugo/publisher" "github.com/gohugoio/hugo/resources/page" "github.com/gohugoio/hugo/tpl" - - "github.com/gohugoio/hugo/helpers" ) const ( @@ -132,13 +130,14 @@ func (a aliasHandler) targetPathAlias(src string) (string, error) { return "", fmt.Errorf("alias \"\" is an empty string") } - alias := filepath.Clean(src) - components := strings.Split(alias, helpers.FilePathSeparator) + alias := path.Clean(src) - if !a.allowRoot && alias == helpers.FilePathSeparator { + if !a.allowRoot && alias == "/" { return "", fmt.Errorf("alias \"%s\" resolves to website root directory", originalAlias) } + components := strings.Split(alias, "/") + // Validate against directory traversal if components[0] == ".." { return "", fmt.Errorf("alias \"%s\" traverses outside the website root directory", originalAlias) @@ -182,11 +181,11 @@ func (a aliasHandler) targetPathAlias(src string) (string, error) { } // Add the final touch - alias = strings.TrimPrefix(alias, helpers.FilePathSeparator) - if strings.HasSuffix(alias, helpers.FilePathSeparator) { + alias = strings.TrimPrefix(alias, "/") + if strings.HasSuffix(alias, "/") { alias = alias + "index.html" } else if !strings.HasSuffix(alias, ".html") { - alias = alias + helpers.FilePathSeparator + "index.html" + alias = alias + "/" + "index.html" } if originalAlias != alias { a.log.INFO.Printf("Alias \"%s\" translated to \"%s\"\n", originalAlias, alias) diff --git a/hugolib/alias_test.go b/hugolib/alias_test.go index f968caf2354..0ceeaf6d4df 100644 --- a/hugolib/alias_test.go +++ b/hugolib/alias_test.go @@ -25,14 +25,14 @@ import ( const pageWithAlias = `--- title: Has Alias -aliases: ["foo/bar/"] +aliases: ["/foo/bar/", "rel"] --- For some moments the old man did not reply. He stood with bowed head, buried in deep thought. But at last he spoke. ` const pageWithAliasMultipleOutputs = `--- title: Has Alias for HTML and AMP -aliases: ["foo/bar/"] +aliases: ["/foo/bar/"] outputs: ["HTML", "AMP", "JSON"] --- For some moments the old man did not reply. He stood with bowed head, buried in deep thought. But at last he spoke. @@ -46,16 +46,17 @@ func TestAlias(t *testing.T) { assert := require.New(t) b := newTestSitesBuilder(t) - b.WithSimpleConfigFile().WithContent("page.md", pageWithAlias) + b.WithSimpleConfigFile().WithContent("blog/page.md", pageWithAlias) b.CreateSites().Build(BuildCfg{}) assert.Equal(1, len(b.H.Sites)) require.Len(t, b.H.Sites[0].RegularPages(), 1) // the real page - b.AssertFileContent("public/page/index.html", "For some moments the old man") - // the alias redirector + b.AssertFileContent("public/blog/page/index.html", "For some moments the old man") + // the alias redirectors b.AssertFileContent("public/foo/bar/index.html", "