src/pkg/html/template/content.go - The Go Programming Language

Golang

Source file src/pkg/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/#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 as defined in RFC 3896.
    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 t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
    78			// Avoid creating a reflect.Value if it's not a pointer.
    79			return a
    80		}
    81		v := reflect.ValueOf(a)
    82		for v.Kind() == reflect.Ptr && !v.IsNil() {
    83			v = v.Elem()
    84		}
    85		return v.Interface()
    86	}
    87	
    88	var (
    89		errorType       = reflect.TypeOf((*error)(nil)).Elem()
    90		fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
    91	)
    92	
    93	// indirectToStringerOrError returns the value, after dereferencing as many times
    94	// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
    95	// or error,
    96	func indirectToStringerOrError(a interface{}) interface{} {
    97		v := reflect.ValueOf(a)
    98		for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
    99			v = v.Elem()
   100		}
   101		return v.Interface()
   102	}
   103	
   104	// stringify converts its arguments to a string and the type of the content.
   105	// All pointers are dereferenced, as in the text/template package.
   106	func stringify(args ...interface{}) (string, contentType) {
   107		if len(args) == 1 {
   108			switch s := indirect(args[0]).(type) {
   109			case string:
   110				return s, contentTypePlain
   111			case CSS:
   112				return string(s), contentTypeCSS
   113			case HTML:
   114				return string(s), contentTypeHTML
   115			case HTMLAttr:
   116				return string(s), contentTypeHTMLAttr
   117			case JS:
   118				return string(s), contentTypeJS
   119			case JSStr:
   120				return string(s), contentTypeJSStr
   121			case URL:
   122				return string(s), contentTypeURL
   123			}
   124		}
   125		for i, arg := range args {
   126			args[i] = indirectToStringerOrError(arg)
   127		}
   128		return fmt.Sprint(args...), contentTypePlain
   129	}