attr.go (6371B)
1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package template 6 7 import ( 8 "strings" 9 ) 10 11 // attrTypeMap[n] describes the value of the given attribute. 12 // If an attribute affects (or can mask) the encoding or interpretation of 13 // other content, or affects the contents, idempotency, or credentials of a 14 // network message, then the value in this map is contentTypeUnsafe. 15 // This map is derived from HTML5, specifically 16 // https://www.w3.org/TR/html5/Overview.html#attributes-1 17 // as well as "%URI"-typed attributes from 18 // https://www.w3.org/TR/html4/index/attributes.html 19 var attrTypeMap = map[string]contentType{ 20 "accept": contentTypePlain, 21 "accept-charset": contentTypeUnsafe, 22 "action": contentTypeURL, 23 "alt": contentTypePlain, 24 "archive": contentTypeURL, 25 "async": contentTypeUnsafe, 26 "autocomplete": contentTypePlain, 27 "autofocus": contentTypePlain, 28 "autoplay": contentTypePlain, 29 "background": contentTypeURL, 30 "border": contentTypePlain, 31 "checked": contentTypePlain, 32 "cite": contentTypeURL, 33 "challenge": contentTypeUnsafe, 34 "charset": contentTypeUnsafe, 35 "class": contentTypePlain, 36 "classid": contentTypeURL, 37 "codebase": contentTypeURL, 38 "cols": contentTypePlain, 39 "colspan": contentTypePlain, 40 "content": contentTypeUnsafe, 41 "contenteditable": contentTypePlain, 42 "contextmenu": contentTypePlain, 43 "controls": contentTypePlain, 44 "coords": contentTypePlain, 45 "crossorigin": contentTypeUnsafe, 46 "data": contentTypeURL, 47 "datetime": contentTypePlain, 48 "default": contentTypePlain, 49 "defer": contentTypeUnsafe, 50 "dir": contentTypePlain, 51 "dirname": contentTypePlain, 52 "disabled": contentTypePlain, 53 "draggable": contentTypePlain, 54 "dropzone": contentTypePlain, 55 "enctype": contentTypeUnsafe, 56 "for": contentTypePlain, 57 "form": contentTypeUnsafe, 58 "formaction": contentTypeURL, 59 "formenctype": contentTypeUnsafe, 60 "formmethod": contentTypeUnsafe, 61 "formnovalidate": contentTypeUnsafe, 62 "formtarget": contentTypePlain, 63 "headers": contentTypePlain, 64 "height": contentTypePlain, 65 "hidden": contentTypePlain, 66 "high": contentTypePlain, 67 "href": contentTypeURL, 68 "hreflang": contentTypePlain, 69 "http-equiv": contentTypeUnsafe, 70 "icon": contentTypeURL, 71 "id": contentTypePlain, 72 "ismap": contentTypePlain, 73 "keytype": contentTypeUnsafe, 74 "kind": contentTypePlain, 75 "label": contentTypePlain, 76 "lang": contentTypePlain, 77 "language": contentTypeUnsafe, 78 "list": contentTypePlain, 79 "longdesc": contentTypeURL, 80 "loop": contentTypePlain, 81 "low": contentTypePlain, 82 "manifest": contentTypeURL, 83 "max": contentTypePlain, 84 "maxlength": contentTypePlain, 85 "media": contentTypePlain, 86 "mediagroup": contentTypePlain, 87 "method": contentTypeUnsafe, 88 "min": contentTypePlain, 89 "multiple": contentTypePlain, 90 "name": contentTypePlain, 91 "novalidate": contentTypeUnsafe, 92 // Skip handler names from 93 // https://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects 94 // since we have special handling in attrType. 95 "open": contentTypePlain, 96 "optimum": contentTypePlain, 97 "pattern": contentTypeUnsafe, 98 "placeholder": contentTypePlain, 99 "poster": contentTypeURL, 100 "profile": contentTypeURL, 101 "preload": contentTypePlain, 102 "pubdate": contentTypePlain, 103 "radiogroup": contentTypePlain, 104 "readonly": contentTypePlain, 105 "rel": contentTypeUnsafe, 106 "required": contentTypePlain, 107 "reversed": contentTypePlain, 108 "rows": contentTypePlain, 109 "rowspan": contentTypePlain, 110 "sandbox": contentTypeUnsafe, 111 "spellcheck": contentTypePlain, 112 "scope": contentTypePlain, 113 "scoped": contentTypePlain, 114 "seamless": contentTypePlain, 115 "selected": contentTypePlain, 116 "shape": contentTypePlain, 117 "size": contentTypePlain, 118 "sizes": contentTypePlain, 119 "span": contentTypePlain, 120 "src": contentTypeURL, 121 "srcdoc": contentTypeHTML, 122 "srclang": contentTypePlain, 123 "srcset": contentTypeSrcset, 124 "start": contentTypePlain, 125 "step": contentTypePlain, 126 "style": contentTypeCSS, 127 "tabindex": contentTypePlain, 128 "target": contentTypePlain, 129 "title": contentTypePlain, 130 "type": contentTypeUnsafe, 131 "usemap": contentTypeURL, 132 "value": contentTypeUnsafe, 133 "width": contentTypePlain, 134 "wrap": contentTypePlain, 135 "xmlns": contentTypeURL, 136 } 137 138 // attrType returns a conservative (upper-bound on authority) guess at the 139 // type of the lowercase named attribute. 140 func attrType(name string) contentType { 141 if strings.HasPrefix(name, "data-") { 142 // Strip data- so that custom attribute heuristics below are 143 // widely applied. 144 // Treat data-action as URL below. 145 name = name[5:] 146 } else if prefix, short, ok := strings.Cut(name, ":"); ok { 147 if prefix == "xmlns" { 148 return contentTypeURL 149 } 150 // Treat svg:href and xlink:href as href below. 151 name = short 152 } 153 if t, ok := attrTypeMap[name]; ok { 154 return t 155 } 156 // Treat partial event handler names as script. 157 if strings.HasPrefix(name, "on") { 158 return contentTypeJS 159 } 160 161 // Heuristics to prevent "javascript:..." injection in custom 162 // data attributes and custom attributes like g:tweetUrl. 163 // https://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes 164 // "Custom data attributes are intended to store custom data 165 // private to the page or application, for which there are no 166 // more appropriate attributes or elements." 167 // Developers seem to store URL content in data URLs that start 168 // or end with "URI" or "URL". 169 if strings.Contains(name, "src") || 170 strings.Contains(name, "uri") || 171 strings.Contains(name, "url") { 172 return contentTypeURL 173 } 174 return contentTypePlain 175 }