...
Run Format

Source file src/html/template/content.go

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

View as plain text