From 438c2198923022a3e4d299b06a7df18268041dd8 Mon Sep 17 00:00:00 2001 From: Phil Pennock Date: Fri, 3 Jan 2014 18:36:53 -0500 Subject: [PATCH] Add `canonifyurls` config option. Be able to inhibit AbsURL canonicalization of content, on a site configuration basis. Advantages of being able to inhibit this include making it easier to rendering on other hostnames, and being able to include resources on http or https depending on how this page was retrieved, avoiding mixed-mode client complaints without adding latency for plain http. --- docs/content/extras/urls.md | 21 +++++++ docs/content/overview/configuration.md | 3 + hugolib/config.go | 2 + hugolib/site.go | 14 +++-- hugolib/site_test.go | 83 +++++++++++++++----------- transform/chain.go | 4 ++ 6 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 docs/content/extras/urls.md diff --git a/docs/content/extras/urls.md b/docs/content/extras/urls.md new file mode 100644 index 000000000..b386effba --- /dev/null +++ b/docs/content/extras/urls.md @@ -0,0 +1,21 @@ +--- +title: "URLs" +date: "2014-01-03" +aliases: + - "/doc/urls/" +groups: ["extras"] +groups_weight: 40 +--- +By default, all relative URLs encountered in the input will be canonicalized +using `baseurl`, so that a link `/css/foo.css` becomes +`http://yoursite.example.com/css/foo.css`. + +Setting `canonifyurls` to `false` will prevent this canonicalization. + +Benefits of canonicalization include fixing all URLs to be absolute, which may +aid with some parsing tasks. Note though that all real browsers handle this +client-side without issues. + +Benefits of non-canonicalization include being able to have resource inclusion +be scheme-relative, so that http vs https can be decided based on how this +page was retrieved. diff --git a/docs/content/overview/configuration.md b/docs/content/overview/configuration.md index 5721df133..30a33a7c7 100644 --- a/docs/content/overview/configuration.md +++ b/docs/content/overview/configuration.md @@ -30,6 +30,7 @@ indexes: category: "categories" tag: "tags" baseurl: "http://yoursite.example.com/" +canonifyurls: true ... {{% /highlight %}} @@ -46,6 +47,7 @@ The following is an example of a json config file with the default values: "tag": "tags" }, "baseurl": "http://yoursite.example.com/" + "canonifyurls": true } {{% /highlight %}} @@ -56,6 +58,7 @@ The following is an example of a toml config file with the default values: publishdir = "public" builddrafts = false baseurl = "http://yoursite.example.com/" + canonifyurls = true [indexes] category = "categories" tag = "tags" diff --git a/hugolib/config.go b/hugolib/config.go index e2d304937..f3e1d3ec9 100644 --- a/hugolib/config.go +++ b/hugolib/config.go @@ -36,6 +36,7 @@ type Config struct { Params map[string]interface{} Permalinks PermalinkOverrides BuildDrafts, UglyUrls, Verbose bool + CanonifyUrls bool } var c Config @@ -61,6 +62,7 @@ func SetupConfig(cfgfile *string, path *string) *Config { c.BuildDrafts = false c.UglyUrls = false c.Verbose = false + c.CanonifyUrls = true c.readInConfig() diff --git a/hugolib/site.go b/hugolib/site.go index 3bc122e0a..3fd5b3d58 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -573,11 +573,17 @@ func (s *Site) render(d interface{}, out string, layouts ...string) (err error) return } - absURL, err := transform.AbsURL(s.Config.BaseUrl) - if err != nil { - return + transformLinks := transform.NewEmptyTransforms() + + if s.Config.CanonifyUrls { + absURL, err := transform.AbsURL(s.Config.BaseUrl) + if err != nil { + return err + } + transformLinks = append(transformLinks, absURL...) } - transformer := transform.NewChain(absURL...) + + transformer := transform.NewChain(transformLinks...) var renderBuffer *bytes.Buffer diff --git a/hugolib/site_test.go b/hugolib/site_test.go index 5f6fe6e7f..a13ddec24 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -234,7 +234,11 @@ func TestSkipRender(t *testing.T) { s := &Site{ Target: target, - Config: Config{Verbose: true, BaseUrl: "http://auth/bub"}, + Config: Config{ + Verbose: true, + BaseUrl: "http://auth/bub", + CanonifyUrls: true, + }, Source: &source.InMemorySource{sources}, } @@ -290,43 +294,52 @@ func TestAbsUrlify(t *testing.T) { {"sect/doc1.html", []byte("link"), "sect"}, {"content/blue/doc2.html", []byte("---\nf: t\n---\nmore content"), "blue"}, } - s := &Site{ - Target: target, - Config: Config{BaseUrl: "http://auth/bub"}, - Source: &source.InMemorySource{sources}, - } - s.initializeSiteInfo() - s.prepTemplates() - must(s.addTemplate("blue/single.html", TEMPLATE_WITH_URL_ABS)) + for _, canonify := range []bool{true, false} { + s := &Site{ + Target: target, + Config: Config{ + BaseUrl: "http://auth/bub", + CanonifyUrls: canonify, + }, + Source: &source.InMemorySource{sources}, + } + t.Logf("Rendering with BaseUrl %q and CanonifyUrls set %v", s.Config.BaseUrl, canonify) + s.initializeSiteInfo() + s.prepTemplates() + must(s.addTemplate("blue/single.html", TEMPLATE_WITH_URL_ABS)) - if err := s.CreatePages(); err != nil { - t.Fatalf("Unable to create pages: %s", err) - } - - if err := s.BuildSiteMeta(); err != nil { - t.Fatalf("Unable to build site metadata: %s", err) - } - - if err := s.RenderPages(); err != nil { - t.Fatalf("Unable to render pages. %s", err) - } - - tests := []struct { - file, expected string - }{ - {"content/blue/doc2.html", "Going"}, - {"sect/doc1.html", "link"}, - } - - for _, test := range tests { - content, ok := target.Files[test.file] - if !ok { - t.Fatalf("Unable to locate rendered content: %s", test.file) + if err := s.CreatePages(); err != nil { + t.Fatalf("Unable to create pages: %s", err) } - expected := test.expected - if string(content) != expected { - t.Errorf("AbsUrlify content expected:\n%q\ngot\n%q", expected, string(content)) + if err := s.BuildSiteMeta(); err != nil { + t.Fatalf("Unable to build site metadata: %s", err) + } + + if err := s.RenderPages(); err != nil { + t.Fatalf("Unable to render pages. %s", err) + } + + tests := []struct { + file, expected string + }{ + {"content/blue/doc2.html", "Going"}, + {"sect/doc1.html", "link"}, + } + + for _, test := range tests { + content, ok := target.Files[test.file] + if !ok { + t.Fatalf("Unable to locate rendered content: %s", test.file) + } + + expected := test.expected + if !canonify { + expected = strings.Replace(expected, s.Config.BaseUrl, "", -1) + } + if string(content) != expected { + t.Errorf("AbsUrlify content expected:\n%q\ngot\n%q", expected, string(content)) + } } } } diff --git a/transform/chain.go b/transform/chain.go index fb3c2985c..c673c5d6a 100644 --- a/transform/chain.go +++ b/transform/chain.go @@ -15,6 +15,10 @@ func NewChain(trs ...link) chain { return trs } +func NewEmptyTransforms() []link { + return make([]link, 0, 20) +} + func (c *chain) Apply(w io.Writer, r io.Reader) (err error) { buffer := new(bytes.Buffer)