Skip to content

Commit

Permalink
HTML: disable lowercasing attribute values; the effect is almost negl…
Browse files Browse the repository at this point in the history
…igible and problems can arise when combining with CSS or JS, fixes #620
  • Loading branch information
tdewolff committed Oct 31, 2023
1 parent 47e6152 commit 797d80c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 59 deletions.
26 changes: 13 additions & 13 deletions html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,30 +401,30 @@ func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]st
attr.Hash == Action && t.Hash == Form) {
continue // omit empty attribute values
}
if attr.Traits&caselessAttr != 0 {
val = parse.ToLower(val)
}
if rawTagHash != 0 && attr.Hash == Type {
rawTagMediatype = parse.Copy(val)
}

if attr.Hash == Enctype || attr.Hash == Accept || attr.Hash == Type && (t.Hash == A || t.Hash == Link || t.Hash == Embed || t.Hash == Object || t.Hash == Source || t.Hash == Script) {
if attr.Hash == Enctype ||
attr.Hash == Formenctype ||
attr.Hash == Accept ||
attr.Hash == Type && (t.Hash == A || t.Hash == Link || t.Hash == Embed || t.Hash == Object || t.Hash == Source || t.Hash == Script) {
val = minify.Mediatype(val)
}

// default attribute values can be omitted
if !o.KeepDefaultAttrVals && (attr.Hash == Type && (t.Hash == Script && jsMimetypes[string(val)] ||
t.Hash == Style && bytes.Equal(val, cssMimeBytes) ||
t.Hash == Link && bytes.Equal(val, cssMimeBytes) ||
t.Hash == Input && bytes.Equal(val, textBytes) ||
t.Hash == Button && bytes.Equal(val, submitBytes)) ||
attr.Hash == Method && bytes.Equal(val, getBytes) ||
attr.Hash == Enctype && bytes.Equal(val, formMimeBytes) ||
if !o.KeepDefaultAttrVals && (attr.Hash == Type && (t.Hash == Script && jsMimetypes[string(parse.ToLower(parse.Copy(val)))] ||
t.Hash == Style && parse.EqualFold(val, cssMimeBytes) ||
t.Hash == Link && parse.EqualFold(val, cssMimeBytes) ||
t.Hash == Input && parse.EqualFold(val, textBytes) ||
t.Hash == Button && parse.EqualFold(val, submitBytes)) ||
attr.Hash == Method && parse.EqualFold(val, getBytes) ||
attr.Hash == Enctype && parse.EqualFold(val, formMimeBytes) ||
attr.Hash == Colspan && bytes.Equal(val, oneBytes) ||
attr.Hash == Rowspan && bytes.Equal(val, oneBytes) ||
attr.Hash == Shape && bytes.Equal(val, rectBytes) ||
attr.Hash == Shape && parse.EqualFold(val, rectBytes) ||
attr.Hash == Span && bytes.Equal(val, oneBytes) ||
attr.Hash == Media && t.Hash == Style && bytes.Equal(val, allBytes)) {
attr.Hash == Media && t.Hash == Style && parse.EqualFold(val, allBytes)) {
continue
}

Expand Down
2 changes: 1 addition & 1 deletion html/html_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestHTML(t *testing.T) {
{`<meta http-equiv="content-type" content="text/html; charset=utf-8">`, `<meta charset=utf-8>`},
{`<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />`, `<meta charset=utf-8>`},
{`<meta http-equiv=" content-type " content=" text/html; charset=utf-8 ">`, `<meta charset=utf-8>`},
{`<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">`, `<meta http-equiv=content-security-policy content="default-src 'self'; img-src https://*; child-src 'none';">`},
{`<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">`, `<meta http-equiv=Content-Security-Policy content="default-src 'self'; img-src https://*; child-src 'none';">`},
{`<meta name="keywords" content="a, b">`, `<meta name=keywords content="a,b">`},
//{`<meta name="keywords" content=" a, b ">`, `<meta name=keywords content="a,b">`}, // TODO
{`<meta name="viewport" content="width = 996" />`, `<meta name=viewport content="width=996">`},
Expand Down
89 changes: 44 additions & 45 deletions html/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const (

const (
booleanAttr traits = 1 << iota
caselessAttr
urlAttr
trimAttr
)
Expand Down Expand Up @@ -163,77 +162,77 @@ var tagMap = map[Hash]traits{
}

var attrMap = map[Hash]traits{
Accept: caselessAttr | trimAttr, // list of mimetypes
Accept_Charset: caselessAttr | trimAttr,
Accept: trimAttr, // list of mimetypes
Accept_Charset: trimAttr,
Accesskey: trimAttr,
Action: urlAttr,
Allow: caselessAttr | trimAttr,
Allow: trimAttr,
Allowfullscreen: booleanAttr,
As: caselessAttr | trimAttr,
As: trimAttr,
Async: booleanAttr,
Autocapitalize: caselessAttr | trimAttr,
Autocomplete: caselessAttr | trimAttr,
Autocapitalize: trimAttr,
Autocomplete: trimAttr,
Autofocus: booleanAttr,
Autoplay: booleanAttr,
Blocking: caselessAttr | trimAttr,
Capture: caselessAttr | trimAttr,
Charset: caselessAttr | trimAttr,
Blocking: trimAttr,
Capture: trimAttr,
Charset: trimAttr,
Checked: booleanAttr,
Cite: urlAttr,
Class: trimAttr,
Color: caselessAttr | trimAttr,
Color: trimAttr,
Cols: trimAttr, // uint bigger than 0
Colspan: trimAttr, // uint bigger than 0
Contenteditable: caselessAttr | trimAttr,
Contenteditable: trimAttr,
Controls: booleanAttr,
Coords: trimAttr, // list of floats
Crossorigin: caselessAttr | trimAttr,
Crossorigin: trimAttr,
Data: urlAttr,
Datetime: trimAttr,
Decoding: caselessAttr | trimAttr,
Decoding: trimAttr,
Default: booleanAttr,
Defer: booleanAttr,
Dir: caselessAttr | trimAttr,
Dir: trimAttr,
Disabled: booleanAttr,
Draggable: caselessAttr | trimAttr,
Enctype: caselessAttr | trimAttr, // mimetype
Enterkeyhint: caselessAttr | trimAttr,
Fetchpriority: caselessAttr | trimAttr,
Draggable: trimAttr,
Enctype: trimAttr, // mimetype
Enterkeyhint: trimAttr,
Fetchpriority: trimAttr,
For: trimAttr,
Form: trimAttr,
Formaction: urlAttr,
Formenctype: caselessAttr | trimAttr, // mimetype
Formmethod: caselessAttr | trimAttr,
Formenctype: trimAttr, // mimetype
Formmethod: trimAttr,
Formnovalidate: booleanAttr,
Formtarget: trimAttr,
Headers: trimAttr,
Height: trimAttr, // uint
Hidden: caselessAttr | trimAttr, // TODO: boolean
High: trimAttr, // float
Height: trimAttr, // uint
Hidden: trimAttr, // TODO: boolean
High: trimAttr, // float
Href: urlAttr,
Hreflang: trimAttr, // BCP 47
Http_Equiv: caselessAttr | trimAttr,
Imagesizes: caselessAttr | trimAttr,
Http_Equiv: trimAttr,
Imagesizes: trimAttr,
Imagesrcset: trimAttr,
Inert: booleanAttr,
Inputmode: caselessAttr | trimAttr,
Is: caselessAttr | trimAttr,
Inputmode: trimAttr,
Is: trimAttr,
Ismap: booleanAttr,
Itemid: urlAttr,
Itemprop: trimAttr,
Itemref: trimAttr,
Itemscope: booleanAttr,
Itemtype: trimAttr, // list of urls
Kind: caselessAttr | trimAttr,
Kind: trimAttr,
Lang: trimAttr, // BCP 47
List: trimAttr,
Loading: caselessAttr | trimAttr,
Loading: trimAttr,
Loop: booleanAttr,
Low: trimAttr, // float
Max: trimAttr, // float or varies
Maxlength: trimAttr, // uint
Media: caselessAttr | trimAttr,
Method: caselessAttr | trimAttr,
Media: trimAttr,
Method: trimAttr,
Min: trimAttr, // float or varies
Minlength: trimAttr, // uint
Multiple: booleanAttr,
Expand All @@ -245,41 +244,41 @@ var attrMap = map[Hash]traits{
Pattern: trimAttr, // regex
Ping: trimAttr, // list of urls
Playsinline: booleanAttr,
Popover: caselessAttr | trimAttr,
Popover: trimAttr,
Popovertarget: trimAttr,
Popovertargetaction: caselessAttr | trimAttr,
Popovertargetaction: trimAttr,
Poster: urlAttr,
Preload: caselessAttr | trimAttr,
Preload: trimAttr,
Profile: urlAttr,
Readonly: booleanAttr,
Referrerpolicy: caselessAttr | trimAttr,
Rel: caselessAttr | trimAttr,
Referrerpolicy: trimAttr,
Rel: trimAttr,
Required: booleanAttr,
Reversed: booleanAttr,
Rows: trimAttr, // uint bigger than 0
Rowspan: trimAttr, // uint
Sandbox: caselessAttr | trimAttr,
Scope: caselessAttr | trimAttr,
Sandbox: trimAttr,
Scope: trimAttr,
Selected: booleanAttr,
Shadowrootmode: caselessAttr | trimAttr,
Shadowrootmode: trimAttr,
Shadowrootdelegatesfocus: booleanAttr,
Shape: caselessAttr | trimAttr,
Shape: trimAttr,
Size: trimAttr, // uint bigger than 0
Sizes: caselessAttr | trimAttr,
Sizes: trimAttr,
Span: trimAttr, // uint bigger than 0
Spellcheck: caselessAttr | trimAttr,
Spellcheck: trimAttr,
Src: urlAttr,
Srclang: trimAttr, // BCP 47
Srcset: trimAttr,
Start: trimAttr, // int
Step: trimAttr, // float or "any"
Tabindex: trimAttr, // int
Target: trimAttr,
Translate: caselessAttr | trimAttr,
Translate: trimAttr,
Type: trimAttr,
Usemap: trimAttr,
Width: trimAttr, // uint
Wrap: caselessAttr | trimAttr,
Wrap: trimAttr,
Xmlns: urlAttr,
}

Expand Down

0 comments on commit 797d80c

Please sign in to comment.