Rebase.
[official-gcc.git] / libgo / go / html / template / content.go
blob3715ed5c93805f8dbb8222be2e5142154a3872a5
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.
5 package template
7 import (
8 "fmt"
9 "reflect"
12 // Strings of content from a trusted source.
13 type (
14 // CSS encapsulates known safe content that matches any of:
15 // 1. The CSS3 stylesheet production, such as `p { color: purple }`.
16 // 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
17 // 3. CSS3 declaration productions, such as `color: red; margin: 2px`.
18 // 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
19 // See http://www.w3.org/TR/css3-syntax/#parsing and
20 // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
21 CSS string
23 // HTML encapsulates a known safe HTML document fragment.
24 // It should not be used for HTML from a third-party, or HTML with
25 // unclosed tags or comments. The outputs of a sound HTML sanitizer
26 // and a template escaped by this package are fine for use with HTML.
27 HTML string
29 // HTMLAttr encapsulates an HTML attribute from a trusted source,
30 // for example, ` dir="ltr"`.
31 HTMLAttr string
33 // JS encapsulates a known safe EcmaScript5 Expression, for example,
34 // `(x + y * z())`.
35 // Template authors are responsible for ensuring that typed expressions
36 // do not break the intended precedence and that there is no
37 // statement/expression ambiguity as when passing an expression like
38 // "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
39 // valid Program with a very different meaning.
40 JS string
42 // JSStr encapsulates a sequence of characters meant to be embedded
43 // between quotes in a JavaScript expression.
44 // The string must match a series of StringCharacters:
45 // StringCharacter :: SourceCharacter but not `\` or LineTerminator
46 // | EscapeSequence
47 // Note that LineContinuations are not allowed.
48 // JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
49 JSStr string
51 // URL encapsulates a known safe URL or URL substring (see RFC 3986).
52 // A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()`
53 // from a trusted source should go in the page, but by default dynamic
54 // `javascript:` URLs are filtered out since they are a frequently
55 // exploited injection vector.
56 URL string
59 type contentType uint8
61 const (
62 contentTypePlain contentType = iota
63 contentTypeCSS
64 contentTypeHTML
65 contentTypeHTMLAttr
66 contentTypeJS
67 contentTypeJSStr
68 contentTypeURL
69 // contentTypeUnsafe is used in attr.go for values that affect how
70 // embedded content and network messages are formed, vetted,
71 // or interpreted; or which credentials network messages carry.
72 contentTypeUnsafe
75 // indirect returns the value, after dereferencing as many times
76 // as necessary to reach the base type (or nil).
77 func indirect(a interface{}) interface{} {
78 if a == nil {
79 return nil
81 if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
82 // Avoid creating a reflect.Value if it's not a pointer.
83 return a
85 v := reflect.ValueOf(a)
86 for v.Kind() == reflect.Ptr && !v.IsNil() {
87 v = v.Elem()
89 return v.Interface()
92 var (
93 errorType = reflect.TypeOf((*error)(nil)).Elem()
94 fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
97 // indirectToStringerOrError returns the value, after dereferencing as many times
98 // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
99 // or error,
100 func indirectToStringerOrError(a interface{}) interface{} {
101 if a == nil {
102 return nil
104 v := reflect.ValueOf(a)
105 for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
106 v = v.Elem()
108 return v.Interface()
111 // stringify converts its arguments to a string and the type of the content.
112 // All pointers are dereferenced, as in the text/template package.
113 func stringify(args ...interface{}) (string, contentType) {
114 if len(args) == 1 {
115 switch s := indirect(args[0]).(type) {
116 case string:
117 return s, contentTypePlain
118 case CSS:
119 return string(s), contentTypeCSS
120 case HTML:
121 return string(s), contentTypeHTML
122 case HTMLAttr:
123 return string(s), contentTypeHTMLAttr
124 case JS:
125 return string(s), contentTypeJS
126 case JSStr:
127 return string(s), contentTypeJSStr
128 case URL:
129 return string(s), contentTypeURL
132 for i, arg := range args {
133 args[i] = indirectToStringerOrError(arg)
135 return fmt.Sprint(args...), contentTypePlain