html: escape comment and doctype tokens' data

Fixes golang/go#48237

Change-Id: I309e3ad30684fb71b9b3e67dfac156da08dbc69b
Reviewed-on: https://go-review.googlesource.com/c/net/+/419334
Run-TryBot: Nigel Tao <nigeltao@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Kunpei Sakai <namusyaka@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/html/render.go b/html/render.go
index b46d81c..497e132 100644
--- a/html/render.go
+++ b/html/render.go
@@ -85,7 +85,7 @@
 		if _, err := w.WriteString("<!--"); err != nil {
 			return err
 		}
-		if _, err := w.WriteString(n.Data); err != nil {
+		if err := escape(w, n.Data); err != nil {
 			return err
 		}
 		if _, err := w.WriteString("-->"); err != nil {
@@ -96,7 +96,7 @@
 		if _, err := w.WriteString("<!DOCTYPE "); err != nil {
 			return err
 		}
-		if _, err := w.WriteString(n.Data); err != nil {
+		if err := escape(w, n.Data); err != nil {
 			return err
 		}
 		if n.Attr != nil {
diff --git a/html/render_test.go b/html/render_test.go
index 1cd439e..08e592b 100644
--- a/html/render_test.go
+++ b/html/render_test.go
@@ -94,6 +94,10 @@
 			Data: "comm",
 		},
 		15: {
+			Type: CommentNode,
+			Data: "x-->y", // Needs escaping.
+		},
+		16: {
 			Type: RawNode,
 			Data: "7<pre>8</pre>9",
 		},
@@ -119,7 +123,8 @@
 		12: `.	.	<br>`,
 		13: `.	.	"6"`,
 		14: `.	.	"<!--comm-->"`,
-		15: `.	.	"7<pre>8</pre>9"`,
+		15: `.	.	"<!--x--&gt;y-->"`,
+		16: `.	.	"7<pre>8</pre>9"`,
 	}
 	if len(nodes) != len(treeAsText) {
 		t.Fatal("len(nodes) != len(treeAsText)")
@@ -155,7 +160,7 @@
 
 	want := `<html><head></head><body>0&lt;1<p id="A" foo="abc&#34;def">` +
 		`2<b empty="">3</b><i backslash="\">&amp;4</i></p>` +
-		`5<blockquote></blockquote><br/>6<!--comm-->7<pre>8</pre>9</body></html>`
+		`5<blockquote></blockquote><br/>6<!--comm--><!--x--&gt;y-->7<pre>8</pre>9</body></html>`
 	b := new(bytes.Buffer)
 	if err := Render(b, nodes[0]); err != nil {
 		t.Fatal(err)
diff --git a/html/token.go b/html/token.go
index 877709f..be3c754 100644
--- a/html/token.go
+++ b/html/token.go
@@ -110,9 +110,9 @@
 	case SelfClosingTagToken:
 		return "<" + t.tagString() + "/>"
 	case CommentToken:
-		return "<!--" + t.Data + "-->"
+		return "<!--" + EscapeString(t.Data) + "-->"
 	case DoctypeToken:
-		return "<!DOCTYPE " + t.Data + ">"
+		return "<!DOCTYPE " + EscapeString(t.Data) + ">"
 	}
 	return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
 }
diff --git a/html/token_test.go b/html/token_test.go
index d59c3c6..ee33caf 100644
--- a/html/token_test.go
+++ b/html/token_test.go
@@ -314,12 +314,12 @@
 	{
 		"comment3",
 		"a<!--x>-->z",
-		"a$<!--x>-->$z",
+		"a$<!--x&gt;-->$z",
 	},
 	{
 		"comment4",
 		"a<!--x->-->z",
-		"a$<!--x->-->$z",
+		"a$<!--x-&gt;-->$z",
 	},
 	{
 		"comment5",
@@ -334,7 +334,7 @@
 	{
 		"comment7",
 		"a<!---<>z",
-		"a$<!---<>z-->",
+		"a$<!---&lt;&gt;z-->",
 	},
 	{
 		"comment8",