summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/net/html/escape.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/net/html/escape.go')
-rw-r--r--vendor/golang.org/x/net/html/escape.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go
index d8561396..04c6bec2 100644
--- a/vendor/golang.org/x/net/html/escape.go
+++ b/vendor/golang.org/x/net/html/escape.go
@@ -193,6 +193,87 @@ func lower(b []byte) []byte {
return b
}
+// escapeComment is like func escape but escapes its input bytes less often.
+// Per https://github.com/golang/go/issues/58246 some HTML comments are (1)
+// meaningful and (2) contain angle brackets that we'd like to avoid escaping
+// unless we have to.
+//
+// "We have to" includes the '&' byte, since that introduces other escapes.
+//
+// It also includes those bytes (not including EOF) that would otherwise end
+// the comment. Per the summary table at the bottom of comment_test.go, this is
+// the '>' byte that, per above, we'd like to avoid escaping unless we have to.
+//
+// Studying the summary table (and T actions in its '>' column) closely, we
+// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
+// start of the comment data. State 52 is after a '!'. The other three states
+// are after a '-'.
+//
+// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
+// - The '>' is after a '!' or '-' (in the unescaped data) or
+// - The '>' is at the start of the comment data (after the opening "<!--").
+func escapeComment(w writer, s string) error {
+ // When modifying this function, consider manually increasing the
+ // maxSuffixLen constant in func TestComments, from 6 to e.g. 9 or more.
+ // That increase should only be temporary, not committed, as it
+ // exponentially affects the test running time.
+
+ if len(s) == 0 {
+ return nil
+ }
+
+ // Loop:
+ // - Grow j such that s[i:j] does not need escaping.
+ // - If s[j] does need escaping, output s[i:j] and an escaped s[j],
+ // resetting i and j to point past that s[j] byte.
+ i := 0
+ for j := 0; j < len(s); j++ {
+ escaped := ""
+ switch s[j] {
+ case '&':
+ escaped = "&amp;"
+
+ case '>':
+ if j > 0 {
+ if prev := s[j-1]; (prev != '!') && (prev != '-') {
+ continue
+ }
+ }
+ escaped = "&gt;"
+
+ default:
+ continue
+ }
+
+ if i < j {
+ if _, err := w.WriteString(s[i:j]); err != nil {
+ return err
+ }
+ }
+ if _, err := w.WriteString(escaped); err != nil {
+ return err
+ }
+ i = j + 1
+ }
+
+ if i < len(s) {
+ if _, err := w.WriteString(s[i:]); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// escapeCommentString is to EscapeString as escapeComment is to escape.
+func escapeCommentString(s string) string {
+ if strings.IndexAny(s, "&>") == -1 {
+ return s
+ }
+ var buf bytes.Buffer
+ escapeComment(&buf, s)
+ return buf.String()
+}
+
const escapedChars = "&'<>\"\r"
func escape(w writer, s string) error {