Source File
url.go
Belonging Package
html/template
// 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 (
)
// urlFilter returns its input unless it contains an unsafe scheme in which
// case it defangs the entire URL.
//
// Schemes that cause unintended side effects that are irreversible without user
// interaction are considered unsafe. For example, clicking on a "javascript:"
// link can immediately trigger JavaScript code execution.
//
// This filter conservatively assumes that all schemes other than the following
// are unsafe:
// - http: Navigates to a new website, and may open a new window or tab.
// These side effects can be reversed by navigating back to the
// previous website, or closing the window or tab. No irreversible
// changes will take place without further user interaction with
// the new website.
// - https: Same as http.
// - mailto: Opens an email program and starts a new draft. This side effect
// is not irreversible until the user explicitly clicks send; it
// can be undone by closing the email program.
//
// To allow URLs containing other schemes to bypass this filter, developers must
// explicitly indicate that such a URL is expected and safe by encapsulating it
// in a template.URL value.
func urlFilter( ...any) string {
, := stringify(...)
if == contentTypeURL {
return
}
if !isSafeURL() {
return "#" + filterFailsafe
}
return
}
// isSafeURL is true if s is a relative URL or if URL has a protocol in
// (http, https, mailto).
func isSafeURL( string) bool {
if , , := strings.Cut(, ":"); && !strings.Contains(, "/") {
if !strings.EqualFold(, "http") && !strings.EqualFold(, "https") && !strings.EqualFold(, "mailto") {
return false
}
}
return true
}
// urlEscaper produces an output that can be embedded in a URL query.
// The output can be embedded in an HTML attribute without further escaping.
func urlEscaper( ...any) string {
return urlProcessor(false, ...)
}
// urlNormalizer normalizes URL content so it can be embedded in a quote-delimited
// string or parenthesis delimited url(...).
// The normalizer does not encode all HTML specials. Specifically, it does not
// encode '&' so correct embedding in an HTML attribute requires escaping of
// '&' to '&'.
func urlNormalizer( ...any) string {
return urlProcessor(true, ...)
}
// urlProcessor normalizes (when norm is true) or escapes its input to produce
// a valid hierarchical or opaque URL part.
func urlProcessor( bool, ...any) string {
, := stringify(...)
if == contentTypeURL {
= true
}
var strings.Builder
if processURLOnto(, , &) {
return .String()
}
return
}
// processURLOnto appends a normalized URL corresponding to its input to b
// and reports whether the appended content differs from s.
func processURLOnto( string, bool, *strings.Builder) bool {
.Grow(len() + 16)
:= 0
// The byte loop below assumes that all URLs use UTF-8 as the
// content-encoding. This is similar to the URI to IRI encoding scheme
// defined in section 3.1 of RFC 3987, and behaves the same as the
// EcmaScript builtin encodeURIComponent.
// It should not cause any misencoding of URLs in pages with
// Content-type: text/html;charset=UTF-8.
for , := 0, len(); < ; ++ {
:= []
switch {
// Single quote and parens are sub-delims in RFC 3986, but we
// escape them so the output can be embedded in single
// quoted attributes and unquoted CSS url(...) constructs.
// Single quotes are reserved in URLs, but are only used in
// the obsolete "mark" rule in an appendix in RFC 3986
// so can be safely encoded.
case '!', '#', '$', '&', '*', '+', ',', '/', ':', ';', '=', '?', '@', '[', ']':
if {
continue
}
// Unreserved according to RFC 3986 sec 2.3
// "For consistency, percent-encoded octets in the ranges of
// ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
// period (%2E), underscore (%5F), or tilde (%7E) should not be
// created by URI producers
case '-', '.', '_', '~':
continue
case '%':
// When normalizing do not re-encode valid escapes.
if && +2 < len() && isHex([+1]) && isHex([+2]) {
continue
}
default:
// Unreserved according to RFC 3986 sec 2.3
if 'a' <= && <= 'z' {
continue
}
if 'A' <= && <= 'Z' {
continue
}
if '0' <= && <= '9' {
continue
}
}
.WriteString([:])
fmt.Fprintf(, "%%%02x", )
= + 1
}
.WriteString([:])
return != 0
}
// Filters and normalizes srcset values which are comma separated
// URLs followed by metadata.
func srcsetFilterAndEscaper( ...any) string {
, := stringify(...)
switch {
case contentTypeSrcset:
return
case contentTypeURL:
// Normalizing gets rid of all HTML whitespace
// which separate the image URL from its metadata.
var strings.Builder
if processURLOnto(, true, &) {
= .String()
}
// Additionally, commas separate one source from another.
return strings.ReplaceAll(, ",", "%2c")
}
var strings.Builder
:= 0
for := 0; < len(); ++ {
if [] == ',' {
filterSrcsetElement(, , , &)
.WriteString(",")
= + 1
}
}
filterSrcsetElement(, , len(), &)
return .String()
}
// Derived from https://play.golang.org/p/Dhmj7FORT5
const htmlSpaceAndASCIIAlnumBytes = "\x00\x36\x00\x00\x01\x00\xff\x03\xfe\xff\xff\x07\xfe\xff\xff\x07"
// isHTMLSpace is true iff c is a whitespace character per
// https://infra.spec.whatwg.org/#ascii-whitespace
func isHTMLSpace( byte) bool {
return ( <= 0x20) && 0 != (htmlSpaceAndASCIIAlnumBytes[>>3]&(1<<uint(&0x7)))
}
func isHTMLSpaceOrASCIIAlnum( byte) bool {
return ( < 0x80) && 0 != (htmlSpaceAndASCIIAlnumBytes[>>3]&(1<<uint(&0x7)))
}
func filterSrcsetElement( string, int, int, *strings.Builder) {
:=
for < && isHTMLSpace([]) {
++
}
:=
for := ; < ; ++ {
if isHTMLSpace([]) {
=
break
}
}
if := [:]; isSafeURL() {
// If image metadata is only spaces or alnums then
// we don't need to URL normalize it.
:= true
for := ; < ; ++ {
if !isHTMLSpaceOrASCIIAlnum([]) {
= false
break
}
}
if {
.WriteString([:])
processURLOnto(, true, )
.WriteString([:])
return
}
}
.WriteString("#")
.WriteString(filterFailsafe)
}
The pages are generated with Golds v0.7.0-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |