diff --git a/asset/asset_test.go b/asset/asset_test.go index 672cc64..d347111 100644 --- a/asset/asset_test.go +++ b/asset/asset_test.go @@ -69,6 +69,7 @@ body { background: url(../img/bg.png); } const htmlDoc = ` + @@ -98,6 +99,7 @@ func TestRewriteHTML(t *testing.T) { checks := map[string]bool{ `href="_kage/ex.com/css/main.css"`: true, // stylesheet localised + `href="_kage/ex.com/css/vp.css"`: true, // multi-value "preload stylesheet" rel localised `href="_kage/ex.com/favicon.ico"`: true, // icon localised `href="https://ex.com/canon"`: true, // canonical left alone `href="docs/intro/index.html"`: true, // internal page → local diff --git a/asset/html.go b/asset/html.go index d939327..ddbe040 100644 --- a/asset/html.go +++ b/asset/html.go @@ -9,13 +9,28 @@ import ( "golang.org/x/net/html/atom" ) -// stylesheetRels are values whose href kage downloads as an asset. -var stylesheetRels = map[string]bool{ - "stylesheet": true, "icon": true, "shortcut icon": true, +// assetRels are the individual tokens whose href kage downloads as +// an asset. A rel attribute is a space-separated token list, so a single known +// token in it (for example the "stylesheet" in "preload stylesheet") is enough. +var assetRels = map[string]bool{ + "stylesheet": true, "icon": true, "apple-touch-icon": true, "apple-touch-icon-precomposed": true, "mask-icon": true, "manifest": true, "preload": true, "prefetch": true, } +// linkRelDownloadable reports whether a names a resource kage should +// download. It treats rel as the space-separated token list the HTML spec +// defines, so "preload stylesheet", "shortcut icon", or a bare "stylesheet" all +// match on a single recognised token. +func linkRelDownloadable(rel string) bool { + for _, tok := range strings.Fields(strings.ToLower(rel)) { + if assetRels[tok] { + return true + } + } + return false +} + // RewriteHTML walks the parsed document and rewrites every resource and link // reference through sink, resolving relative URLs against base. It mutates the // tree in place; the caller renders it afterwards. References kage cannot handle @@ -40,8 +55,7 @@ func rewriteElement(n *html.Node, base *url.URL, sink RefSink) { case atom.Iframe, atom.Frame: rewriteAttr(n, "src", base, sink, pageOrAsset) case atom.Link: - rel := strings.ToLower(strings.TrimSpace(attrVal(n, "rel"))) - if stylesheetRels[rel] { + if linkRelDownloadable(attrVal(n, "rel")) { rewriteAttr(n, "href", base, sink, alwaysAsset) } case atom.Img: