|  | // 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 template | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "reflect" | 
|  | ) | 
|  |  | 
|  | // Strings of content from a trusted source. | 
|  | type ( | 
|  | // CSS encapsulates known safe content that matches any of: | 
|  | //   1. The CSS3 stylesheet production, such as `p { color: purple }`. | 
|  | //   2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`. | 
|  | //   3. CSS3 declaration productions, such as `color: red; margin: 2px`. | 
|  | //   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`. | 
|  | // See http://www.w3.org/TR/css3-syntax/#style | 
|  | CSS string | 
|  |  | 
|  | // HTML encapsulates a known safe HTML document fragment. | 
|  | // It should not be used for HTML from a third-party, or HTML with | 
|  | // unclosed tags or comments. The outputs of a sound HTML sanitizer | 
|  | // and a template escaped by this package are fine for use with HTML. | 
|  | HTML string | 
|  |  | 
|  | // HTMLAttr encapsulates an HTML attribute from a trusted source, | 
|  | // for example, ` dir="ltr"`. | 
|  | HTMLAttr string | 
|  |  | 
|  | // JS encapsulates a known safe EcmaScript5 Expression, for example, | 
|  | // `(x + y * z())`. | 
|  | // Template authors are responsible for ensuring that typed expressions | 
|  | // do not break the intended precedence and that there is no | 
|  | // statement/expression ambiguity as when passing an expression like | 
|  | // "{ foo: bar() }\n['foo']()", which is both a valid Expression and a | 
|  | // valid Program with a very different meaning. | 
|  | JS string | 
|  |  | 
|  | // JSStr encapsulates a sequence of characters meant to be embedded | 
|  | // between quotes in a JavaScript expression. | 
|  | // The string must match a series of StringCharacters: | 
|  | //   StringCharacter :: SourceCharacter but not `\` or LineTerminator | 
|  | //                    | EscapeSequence | 
|  | // Note that LineContinuations are not allowed. | 
|  | // JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not. | 
|  | JSStr string | 
|  |  | 
|  | // URL encapsulates a known safe URL or URL substring (see RFC 3986). | 
|  | // A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()` | 
|  | // from a trusted source should go in the page, but by default dynamic | 
|  | // `javascript:` URLs are filtered out since they are a frequently | 
|  | // exploited injection vector. | 
|  | URL string | 
|  | ) | 
|  |  | 
|  | type contentType uint8 | 
|  |  | 
|  | const ( | 
|  | contentTypePlain contentType = iota | 
|  | contentTypeCSS | 
|  | contentTypeHTML | 
|  | contentTypeHTMLAttr | 
|  | 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 | 
|  | ) | 
|  |  | 
|  | // indirect returns the value, after dereferencing as many times | 
|  | // as necessary to reach the base type (or nil). | 
|  | func indirect(a interface{}) interface{} { | 
|  | if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { | 
|  | // Avoid creating a reflect.Value if it's not a pointer. | 
|  | return a | 
|  | } | 
|  | v := reflect.ValueOf(a) | 
|  | for v.Kind() == reflect.Ptr && !v.IsNil() { | 
|  | v = v.Elem() | 
|  | } | 
|  | return v.Interface() | 
|  | } | 
|  |  | 
|  | var ( | 
|  | errorType       = reflect.TypeOf((*error)(nil)).Elem() | 
|  | fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() | 
|  | ) | 
|  |  | 
|  | // indirectToStringerOrError returns the value, after dereferencing as many times | 
|  | // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer | 
|  | // or error, | 
|  | func indirectToStringerOrError(a interface{}) interface{} { | 
|  | v := reflect.ValueOf(a) | 
|  | for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { | 
|  | v = v.Elem() | 
|  | } | 
|  | return v.Interface() | 
|  | } | 
|  |  | 
|  | // stringify converts its arguments to a string and the type of the content. | 
|  | // All pointers are dereferenced, as in the text/template package. | 
|  | func stringify(args ...interface{}) (string, contentType) { | 
|  | if len(args) == 1 { | 
|  | switch s := indirect(args[0]).(type) { | 
|  | case string: | 
|  | return s, contentTypePlain | 
|  | case CSS: | 
|  | return string(s), contentTypeCSS | 
|  | case HTML: | 
|  | return string(s), contentTypeHTML | 
|  | case HTMLAttr: | 
|  | return string(s), contentTypeHTMLAttr | 
|  | case JS: | 
|  | return string(s), contentTypeJS | 
|  | case JSStr: | 
|  | return string(s), contentTypeJSStr | 
|  | case URL: | 
|  | return string(s), contentTypeURL | 
|  | } | 
|  | } | 
|  | for i, arg := range args { | 
|  | args[i] = indirectToStringerOrError(arg) | 
|  | } | 
|  | return fmt.Sprint(args...), contentTypePlain | 
|  | } |