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 6ac0035de..508924565 100644 --- a/docs/content/overview/configuration.md +++ b/docs/content/overview/configuration.md @@ -30,6 +30,7 @@ The following is an example of a yaml config file with the default values: category: "categories" tag: "tags" baseurl: "http://yoursite.example.com/" + canonifyurls: true ... @@ -44,7 +45,8 @@ The following is an example of a json config file with the default values: "category": "categories", "tag": "tags" }, - "baseurl": "http://yoursite.example.com/" + "baseurl": "http://yoursite.example.com/", + "canonifyurls": true } @@ -55,6 +57,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)