github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/html/template/content.go (about) 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 "fmt" 9 "reflect" 10 ) 11 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/#style 20 CSS string 21 22 // HTML encapsulates a known safe HTML document fragment. 23 // It should not be used for HTML from a third-party, or HTML with 24 // unclosed tags or comments. The outputs of a sound HTML sanitizer 25 // and a template escaped by this package are fine for use with HTML. 26 HTML string 27 28 // HTMLAttr encapsulates an HTML attribute from a trusted source, 29 // for example, ` dir="ltr"`. 30 HTMLAttr string 31 32 // JS encapsulates a known safe EcmaScript5 Expression, for example, 33 // `(x + y * z())`. 34 // Template authors are responsible for ensuring that typed expressions 35 // do not break the intended precedence and that there is no 36 // statement/expression ambiguity as when passing an expression like 37 // "{ foo: bar() }\n['foo']()", which is both a valid Expression and a 38 // valid Program with a very different meaning. 39 JS string 40 41 // JSStr encapsulates a sequence of characters meant to be embedded 42 // between quotes in a JavaScript expression. 43 // The string must match a series of StringCharacters: 44 // StringCharacter :: SourceCharacter but not `\` or LineTerminator 45 // | EscapeSequence 46 // Note that LineContinuations are not allowed. 47 // JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not. 48 JSStr string 49 50 // URL encapsulates a known safe URL or URL substring (see RFC 3986). 51 // A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()` 52 // from a trusted source should go in the page, but by default dynamic 53 // `javascript:` URLs are filtered out since they are a frequently 54 // exploited injection vector. 55 URL string 56 ) 57 58 type contentType uint8 59 60 const ( 61 contentTypePlain contentType = iota 62 contentTypeCSS 63 contentTypeHTML 64 contentTypeHTMLAttr 65 contentTypeJS 66 contentTypeJSStr 67 contentTypeURL 68 // contentTypeUnsafe is used in attr.go for values that affect how 69 // embedded content and network messages are formed, vetted, 70 // or interpreted; or which credentials network messages carry. 71 contentTypeUnsafe 72 ) 73 74 // indirect returns the value, after dereferencing as many times 75 // as necessary to reach the base type (or nil). 76 func indirect(a interface{}) interface{} { 77 if a == nil { 78 return nil 79 } 80 if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { 81 // Avoid creating a reflect.Value if it's not a pointer. 82 return a 83 } 84 v := reflect.ValueOf(a) 85 for v.Kind() == reflect.Ptr && !v.IsNil() { 86 v = v.Elem() 87 } 88 return v.Interface() 89 } 90 91 var ( 92 errorType = reflect.TypeOf((*error)(nil)).Elem() 93 fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() 94 ) 95 96 // indirectToStringerOrError returns the value, after dereferencing as many times 97 // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer 98 // or error, 99 func indirectToStringerOrError(a interface{}) interface{} { 100 if a == nil { 101 return nil 102 } 103 v := reflect.ValueOf(a) 104 for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { 105 v = v.Elem() 106 } 107 return v.Interface() 108 } 109 110 // stringify converts its arguments to a string and the type of the content. 111 // All pointers are dereferenced, as in the text/template package. 112 func stringify(args ...interface{}) (string, contentType) { 113 if len(args) == 1 { 114 switch s := indirect(args[0]).(type) { 115 case string: 116 return s, contentTypePlain 117 case CSS: 118 return string(s), contentTypeCSS 119 case HTML: 120 return string(s), contentTypeHTML 121 case HTMLAttr: 122 return string(s), contentTypeHTMLAttr 123 case JS: 124 return string(s), contentTypeJS 125 case JSStr: 126 return string(s), contentTypeJSStr 127 case URL: 128 return string(s), contentTypeURL 129 } 130 } 131 for i, arg := range args { 132 args[i] = indirectToStringerOrError(arg) 133 } 134 return fmt.Sprint(args...), contentTypePlain 135 }