go html/template: 当样式标签未关闭时出现模糊错误

fsi0uk1n  于 6个月前  发布在  Go
关注(0)|答案(3)|浏览(43)

你使用的Go版本是什么( go version )?

$ go version
go version go1.11.3 linux/amd64

这个问题在最新版本中是否重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/george/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/george/.go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/george/tmp/resume/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build336466026=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

运行了以下程序: https://play.golang.org/p/BtMWAAxnb3o

你期望看到什么?

程序没有返回错误,或者至少返回一个错误通知样式标签没有关闭。

你看到了什么?

html/template:test:11:17: {{.}} appears in an ambiguous context within a URL
gmxoilav

gmxoilav1#

我调查了一下,这不仅仅是模糊的错误。它似乎是一个错误,使转义器误以为它在标签内而不是在CSS状态下。(我认为这与样式标签是否关闭无关)
这段代码:

t := template.Must(template.New("base").Parse(`<style>
{{/*This is fine*/}}
<a href="{{.}}"></a>
{{if true}}
{{/*The colon is important*/}}
<a href=":{{.}}"></a>
{{if true}}
{{/*This is fine*/}}
<a href="{{.}}"></a>
{{end}}
{{end}}
{{if true}}
{{/*This is not fine*/}}
<a href="a?{{.}}"></a>
{{end}}
</style>`))

	err := t.Execute(os.Stdout, "{")

产生的结果是:

<style>
        <a href="\7b "></a>                 ← Extra trailing space?
                <a href=":\7b "></a>        ← Extra trailing space?
                        <a href="\7b "></a> ← Extra trailing space?
                <a href="a?%7b"></a>        ← Incoherent escaping
</style>

我会调查一下并尝试找到根本原因。
@mikesamuel 我们应该如何转义 <style> 标签内的HTML内容?我相信它都应该像CSS一样进行转义。

x33g5p2x

x33g5p2x2#

根据您的说法,<style>具有特殊的内容模型,因此在<style><a></style>中没有"a"标签。

  1. 双引号开始一个URL上下文。
  2. ':'和'?'分别表示协议/查询的结束和开始。

我不确定为什么%7b在CSS转义假设为引用字符串的URL上下文中是不合适的,尽管它对于selector:after { font-family: "{{.}}"; content: "{{.}}" }来说并不是非常合适。

当你不知道下一个字符时,"额外的尾随空格"对于CSS转义是必要的。
CSS允许一个空格:
示例3:值为"&B"的标识符可以写成\26 B\000026B
我们应该如何转义标签内的HTML内容?我认为它们都应该被转义为CSS。
同意。
如果我们要非常严格地遵守规范,那么我们会将这两种情况区分对待:

  • <style><a></a></style>
  • <svg><style><a></style></svg>

但这需要为外部内容模式添加额外的上下文位,而这样做似乎并没有什么明显的好处。
倾向于第二种做法可能会破坏

<style>
/* Make <b> blue */ b { color: blue }
/* Make <p> pink */ p { color: pink }
</style>
qyswt5oh

qyswt5oh3#

感谢@mikesamuel的回复。
我对此进行了更深入的研究。

关于错误

当报告错误返回时,解析器的状态是:

{stateCSSDqStr delimNone urlPartUnknown jsCtxRegexp attrNone elementStyle <nil>}
                         ^^^^^^^^^^^^^^

这就是为什么错误是 {{.}} appears in an ambiguous context within a URL 的原因。这发生在模板结束之前,所以我认为我们不能轻易地给出更好的错误信息。我们从未看到未关闭的 <style> 标签。

一些额外的疑问

解析器进入 urlPartUnknown 状态是因为它连接了两个除了 urlPart 之外完全相同的状态。可以用一个 minimal example 来重现:

t := template.Must(template.New("a").Parse(`
<style>{{if true}} "a{{.}}" {{end}} "{{.}}"`))
	fmt.Printf("%v",t.Execute(os.Stdout, ""))

这会给出上面的错误,因为第一个 {{.}} 之前的 a 使 then 分支在 urlPartPreQuery 状态下结束。我想知道关闭引号是否应该使解析器返回到 urlPartNone 状态
"a{{.}}" 替换为仅 "a" 使解析器正确识别 urlPartNone
相反,The code below 返回一个错误,指出模板“以非文本上下文结尾”,并且连接的两个分支都在 urlPartNone 状态下。

t := template.Must(template.New("a").Parse(`
<style>{{if true}} "{{.}}" {{end}} "{{.}}"`))
//                          ↑ Removed `a`
	fmt.Printf("%v", t.Execute(os.Stdout, ""))

这是由于在 URL 初始部分,我们保持在 urlPartNone 状态,我们不考虑插值值更新到 urlPart* 状态。
如果我们假设插值值内部的所有引号都会被转义(它们确实被转义了),那么这是有道理的,但这让我困惑为什么我们不在前一个示例中做同样的事情。我们在那里也会转义引号。
为什么在这些情况下关闭引号的行为不同?

相关问题