diff --git a/src/pkg/exp/template/html/Makefile b/src/pkg/exp/template/html/Makefile index 9032aead87..2ccbdd3e85 100644 --- a/src/pkg/exp/template/html/Makefile +++ b/src/pkg/exp/template/html/Makefile @@ -6,6 +6,7 @@ include ../../../../Make.inc TARG=exp/template/html GOFILES=\ + attr.go\ clone.go\ content.go\ context.go\ diff --git a/src/pkg/exp/template/html/attr.go b/src/pkg/exp/template/html/attr.go new file mode 100644 index 0000000000..cc57f8bd8a --- /dev/null +++ b/src/pkg/exp/template/html/attr.go @@ -0,0 +1,184 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +// attrType[n] describes the value of the given attribute. +// If an attribute affects (or can mask) the encoding or interpretation of +// other content, or affects the contents, idempotency, or credentials of a +// network message, then the value in this map is contentTypeUnsafe. +// This map is derived from HTML5, specifically +// http://www.w3.org/TR/html5/Overview.html#attributes-1 and +// http://www.w3.org/TR/html5/Overview.html#event-handlers-on-elements-document-objects-and-window-objects +// as well as "%URI"-typed attributes from +// http://www.w3.org/TR/html4/index/attributes.html +var attrType = map[string]contentType{ + "accept": contentTypePlain, + "accept-charset": contentTypeUnsafe, + "action": contentTypeURL, + "alt": contentTypePlain, + "archive": contentTypeURL, + "async": contentTypeUnsafe, + "autocomplete": contentTypePlain, + "autofocus": contentTypePlain, + "autoplay": contentTypePlain, + "background": contentTypeURL, + "border": contentTypePlain, + "checked": contentTypePlain, + "cite": contentTypeURL, + "challenge": contentTypeUnsafe, + "charset": contentTypeUnsafe, + "class": contentTypePlain, + "classid": contentTypeURL, + "codebase": contentTypeURL, + "cols": contentTypePlain, + "colspan": contentTypePlain, + "content": contentTypeUnsafe, + "contenteditable": contentTypePlain, + "contextmenu": contentTypePlain, + "controls": contentTypePlain, + "coords": contentTypePlain, + "crossorigin": contentTypeUnsafe, + "data": contentTypeURL, + "datetime": contentTypePlain, + "default": contentTypePlain, + "defer": contentTypeUnsafe, + "dir": contentTypePlain, + "dirname": contentTypePlain, + "disabled": contentTypePlain, + "draggable": contentTypePlain, + "dropzone": contentTypePlain, + "enctype": contentTypeUnsafe, + "for": contentTypePlain, + "form": contentTypeUnsafe, + "formaction": contentTypeURL, + "formenctype": contentTypeUnsafe, + "formmethod": contentTypeUnsafe, + "formnovalidate": contentTypeUnsafe, + "formtarget": contentTypePlain, + "headers": contentTypePlain, + "height": contentTypePlain, + "hidden": contentTypePlain, + "high": contentTypePlain, + "href": contentTypeURL, + "hreflang": contentTypePlain, + "http-equiv": contentTypeUnsafe, + "icon": contentTypeURL, + "id": contentTypePlain, + "ismap": contentTypePlain, + "keytype": contentTypeUnsafe, + "kind": contentTypePlain, + "label": contentTypePlain, + "lang": contentTypePlain, + "language": contentTypeUnsafe, + "list": contentTypePlain, + "longdesc": contentTypeURL, + "loop": contentTypePlain, + "low": contentTypePlain, + "manifest": contentTypeURL, + "max": contentTypePlain, + "maxlength": contentTypePlain, + "media": contentTypePlain, + "mediagroup": contentTypePlain, + "method": contentTypeUnsafe, + "min": contentTypePlain, + "multiple": contentTypePlain, + "name": contentTypePlain, + "novalidate": contentTypeUnsafe, + "onabort": contentTypeJS, + "onblur": contentTypeJS, + "oncanplay": contentTypeJS, + "oncanplaythrough": contentTypeJS, + "onchange": contentTypeJS, + "onclick": contentTypeJS, + "oncontextmenu": contentTypeJS, + "oncuechange": contentTypeJS, + "ondblclick": contentTypeJS, + "ondrag": contentTypeJS, + "ondragend": contentTypeJS, + "ondragenter": contentTypeJS, + "ondragleave": contentTypeJS, + "ondragover": contentTypeJS, + "ondragstart": contentTypeJS, + "ondrop": contentTypeJS, + "ondurationchange": contentTypeJS, + "onemptied": contentTypeJS, + "onended": contentTypeJS, + "onerror": contentTypeJS, + "onfocus": contentTypeJS, + "oninput": contentTypeJS, + "oninvalid": contentTypeJS, + "onkeydown": contentTypeJS, + "onkeypress": contentTypeJS, + "onkeyup": contentTypeJS, + "onload": contentTypeJS, + "onloadeddata": contentTypeJS, + "onloadedmetadata": contentTypeJS, + "onloadstart": contentTypeJS, + "onmousedown": contentTypeJS, + "onmousemove": contentTypeJS, + "onmouseout": contentTypeJS, + "onmouseover": contentTypeJS, + "onmouseup": contentTypeJS, + "onmousewheel": contentTypeJS, + "onpause": contentTypeJS, + "onplay": contentTypeJS, + "onplaying": contentTypeJS, + "onprogress": contentTypeJS, + "onratechange": contentTypeJS, + "onreadystatechange": contentTypeJS, + "onreset": contentTypeJS, + "onscroll": contentTypeJS, + "onseeked": contentTypeJS, + "onseeking": contentTypeJS, + "onselect": contentTypeJS, + "onshow": contentTypeJS, + "onstalled": contentTypeJS, + "onsubmit": contentTypeJS, + "onsuspend": contentTypeJS, + "ontimeupdate": contentTypeJS, + "onvolumechange": contentTypeJS, + "onwaiting": contentTypeJS, + "open": contentTypePlain, + "optimum": contentTypePlain, + "pattern": contentTypeUnsafe, + "placeholder": contentTypePlain, + "poster": contentTypeURL, + "profile": contentTypeURL, + "preload": contentTypePlain, + "pubdate": contentTypePlain, + "radiogroup": contentTypePlain, + "readonly": contentTypePlain, + "rel": contentTypeUnsafe, + "required": contentTypePlain, + "reversed": contentTypePlain, + "rows": contentTypePlain, + "rowspan": contentTypePlain, + "sandbox": contentTypeUnsafe, + "spellcheck": contentTypePlain, + "scope": contentTypePlain, + "scoped": contentTypePlain, + "seamless": contentTypePlain, + "selected": contentTypePlain, + "shape": contentTypePlain, + "size": contentTypePlain, + "sizes": contentTypePlain, + "span": contentTypePlain, + "src": contentTypeURL, + "srcdoc": contentTypeHTML, + "srclang": contentTypePlain, + "start": contentTypePlain, + "step": contentTypePlain, + "style": contentTypeCSS, + "tabindex": contentTypePlain, + "target": contentTypePlain, + "title": contentTypePlain, + "type": contentTypeUnsafe, + "usemap": contentTypeURL, + "value": contentTypeUnsafe, + "width": contentTypePlain, + "wrap": contentTypePlain, + + // TODO: data-* attrs? Recognize data-foo-url and similar. +} diff --git a/src/pkg/exp/template/html/content.go b/src/pkg/exp/template/html/content.go index 8b9809b982..dcaff8c15c 100644 --- a/src/pkg/exp/template/html/content.go +++ b/src/pkg/exp/template/html/content.go @@ -64,6 +64,10 @@ const ( contentTypeJS contentTypeJSStr contentTypeURL + // contentTypeUnsafe is used in attr.go for values that affect how + // embedded content and network messages are formed, vetted, + // or interpreted; or which credentials network messages carry. + contentTypeUnsafe ) // stringify converts its arguments to a string and the type of the content. diff --git a/src/pkg/exp/template/html/escape_test.go b/src/pkg/exp/template/html/escape_test.go index 8a64515dec..1ce66c5fb1 100644 --- a/src/pkg/exp/template/html/escape_test.go +++ b/src/pkg/exp/template/html/escape_test.go @@ -553,11 +553,51 @@ func TestEscape(t *testing.T) { // Treated as JS since quotes are inserted. ``, }, + { + "bad dynamic attribute name 1", + // Allow checked, selected, disabled, but not JS or + // CSS attributes. + ``, + ``, + }, + { + "bad dynamic attribute name 2", + `