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.
This commit is contained in:
Phil Pennock 2014-01-03 18:36:53 -05:00
parent 247db151fa
commit c1bae45dfa
6 changed files with 89 additions and 40 deletions

View file

@ -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.

View file

@ -30,6 +30,7 @@ The following is an example of a yaml config file with the default values:
category: "categories" category: "categories"
tag: "tags" tag: "tags"
baseurl: "http://yoursite.example.com/" 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", "category": "categories",
"tag": "tags" "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" publishdir = "public"
builddrafts = false builddrafts = false
baseurl = "http://yoursite.example.com/" baseurl = "http://yoursite.example.com/"
canonifyurls = true
[indexes] [indexes]
category = "categories" category = "categories"
tag = "tags" tag = "tags"

View file

@ -36,6 +36,7 @@ type Config struct {
Params map[string]interface{} Params map[string]interface{}
Permalinks PermalinkOverrides Permalinks PermalinkOverrides
BuildDrafts, UglyUrls, Verbose bool BuildDrafts, UglyUrls, Verbose bool
CanonifyUrls bool
} }
var c Config var c Config
@ -61,6 +62,7 @@ func SetupConfig(cfgfile *string, path *string) *Config {
c.BuildDrafts = false c.BuildDrafts = false
c.UglyUrls = false c.UglyUrls = false
c.Verbose = false c.Verbose = false
c.CanonifyUrls = true
c.readInConfig() c.readInConfig()

View file

@ -573,11 +573,17 @@ func (s *Site) render(d interface{}, out string, layouts ...string) (err error)
return return
} }
absURL, err := transform.AbsURL(s.Config.BaseUrl) transformLinks := transform.NewEmptyTransforms()
if err != nil {
return 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 var renderBuffer *bytes.Buffer

View file

@ -234,7 +234,11 @@ func TestSkipRender(t *testing.T) {
s := &Site{ s := &Site{
Target: target, Target: target,
Config: Config{Verbose: true, BaseUrl: "http://auth/bub"}, Config: Config{
Verbose: true,
BaseUrl: "http://auth/bub",
CanonifyUrls: true,
},
Source: &source.InMemorySource{sources}, Source: &source.InMemorySource{sources},
} }
@ -290,43 +294,52 @@ func TestAbsUrlify(t *testing.T) {
{"sect/doc1.html", []byte("<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"), "sect"}, {"sect/doc1.html", []byte("<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"), "sect"},
{"content/blue/doc2.html", []byte("---\nf: t\n---\n<!doctype html><html><body>more content</body></html>"), "blue"}, {"content/blue/doc2.html", []byte("---\nf: t\n---\n<!doctype html><html><body>more content</body></html>"), "blue"},
} }
s := &Site{ for _, canonify := range []bool{true, false} {
Target: target, s := &Site{
Config: Config{BaseUrl: "http://auth/bub"}, Target: target,
Source: &source.InMemorySource{sources}, Config: Config{
} BaseUrl: "http://auth/bub",
s.initializeSiteInfo() CanonifyUrls: canonify,
s.prepTemplates() },
must(s.addTemplate("blue/single.html", TEMPLATE_WITH_URL_ABS)) 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 { if err := s.CreatePages(); err != nil {
t.Fatalf("Unable to create pages: %s", err) 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", "<a href=\"http://auth/bub/foobar.jpg\">Going</a>"},
{"sect/doc1.html", "<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"},
}
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 err := s.BuildSiteMeta(); err != nil {
if string(content) != expected { t.Fatalf("Unable to build site metadata: %s", err)
t.Errorf("AbsUrlify content expected:\n%q\ngot\n%q", expected, string(content)) }
if err := s.RenderPages(); err != nil {
t.Fatalf("Unable to render pages. %s", err)
}
tests := []struct {
file, expected string
}{
{"content/blue/doc2.html", "<a href=\"http://auth/bub/foobar.jpg\">Going</a>"},
{"sect/doc1.html", "<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"},
}
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))
}
} }
} }
} }

View file

@ -15,6 +15,10 @@ func NewChain(trs ...link) chain {
return trs return trs
} }
func NewEmptyTransforms() []link {
return make([]link, 0, 20)
}
func (c *chain) Apply(w io.Writer, r io.Reader) (err error) { func (c *chain) Apply(w io.Writer, r io.Reader) (err error) {
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)