golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.93k stars 17.65k forks source link

html/template: URL types always escape in attributes #53342

Open weberc2 opened 2 years ago

weberc2 commented 2 years ago

What version of Go are you using (go version)?

$ go version
go version go1.18 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/weberc2/Library/Caches/go-build"
GOENV="/Users/weberc2/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/weberc2/.gvm/pkgsets/go1.18/global/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/weberc2/.gvm/pkgsets/go1.18/global"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/weberc2/.gvm/gos/go1.18"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/weberc2/.gvm/gos/go1.18/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.18"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/weberc2/projects/mono/go.mod"
GOWORK="/Users/weberc2/projects/go.work"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3727685623=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

printTemplate(`<x action="{{.}}">`, html.HTML("<expected-not-escaped>"))
// <x action="%3cexpected-not-escaped%3e">

printTemplate(`<x action="{{.}}">`, html.HTMLAttr("<expected-not-escaped>"))
// <x action="%3cexpected-not-escaped%3e">

printTemplate(`<x action="{{.}}">`, html.URL("<expected-not-escaped>"))
// <x action="%3cexpected-not-escaped%3e">

// executes the provided template with the provided data and prints the result
func printTemplate(template string, data interface{}) {
    var b bytes.Buffer
    t := html.Must(html.New("").Parse(template))
    if err := t.Execute(&b, data); err != nil {
        panic(err)
    }
    fmt.Println(b.String())
}

Playground

What did you expect to see?

I expect that data of type HTML, URL, or HTMLAttr is not escaped inside of an attribute.

What did you see instead?

Attributes are always escaped irrespective of data type.

seankhliao commented 2 years ago

As documented, those are incorrect uses of HTML (requires an entire html fragment) and HTMLAttr (requires the entire key=value pair): https://go.dev/play/p/XmBsJ_itlER Not sure about URL.

cc @empijei

weberc2 commented 2 years ago

@seankhliao Thanks for the response. The docs specify "an HTML document fragment", but "fragment" isn't clearly defined (so perhaps the documentation could be updated to be more explicit about what constitutes a fragment?). For example, from the documentation alone (I'm not sure if "fragment" is taken from the HTML spec or if Go expects users to be familiar with the spec), any of the following could be reasonably understood as fragments:

Documentation aside, I think you're right that URL seems like the relevant type.