diff options
| author | Didier Spezia <didier.06@gmail.com> | 2015-05-14 22:36:59 +0000 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2015-05-19 22:45:50 +0000 |
| commit | a1c1a763bc7c8d10ec30a7fa60ecf7d5f9a6f1c8 (patch) | |
| tree | 377cce9b259abe2b715a86a2daea41604a464173 /src/html/template/css.go | |
| parent | d6bbcea22a3d4cbcf8350b4b861f0d73ab142ac2 (diff) | |
| download | go-a1c1a763bc7c8d10ec30a7fa60ecf7d5f9a6f1c8.tar.xz | |
html/template: fix string iteration in replacement operations
In css, js, and html, the replacement operations are implemented
by iterating on strings (rune by rune). The for/range
statement is used. The length of the rune is required
and added to the index to properly slice the string.
This is potentially wrong because there is a discrepancy between
the result of utf8.RuneLen and the increment of the index
(set by the for/range statement). For invalid strings,
utf8.RuneLen('\ufffd') == 3, while the index is incremented
only by 1 byte.
htmlReplacer triggers a panic at slicing time for some
invalid strings.
Use a more robust iteration mechanism based on
utf8.DecodeRuneInString, and make sure the same
pattern is used for all similar functions in this
package.
Fixes #10799
Change-Id: Ibad3857b2819435d9fa564f06fc2ca8774102841
Reviewed-on: https://go-review.googlesource.com/10105
Reviewed-by: Rob Pike <r@golang.org>
Diffstat (limited to 'src/html/template/css.go')
| -rw-r--r-- | src/html/template/css.go | 76 |
1 files changed, 32 insertions, 44 deletions
diff --git a/src/html/template/css.go b/src/html/template/css.go index 634f183f79..318464835f 100644 --- a/src/html/template/css.go +++ b/src/html/template/css.go @@ -157,56 +157,20 @@ func isCSSSpace(b byte) bool { func cssEscaper(args ...interface{}) string { s, _ := stringify(args...) var b bytes.Buffer - written := 0 - for i, r := range s { + r, w, written := rune(0), 0, 0 + for i := 0; i < len(s); i += w { + // See comment in htmlEscaper. + r, w = utf8.DecodeRuneInString(s[i:]) var repl string - switch r { - case 0: - repl = `\0` - case '\t': - repl = `\9` - case '\n': - repl = `\a` - case '\f': - repl = `\c` - case '\r': - repl = `\d` - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - case '"': - repl = `\22` - case '&': - repl = `\26` - case '\'': - repl = `\27` - case '(': - repl = `\28` - case ')': - repl = `\29` - case '+': - repl = `\2b` - case '/': - repl = `\2f` - case ':': - repl = `\3a` - case ';': - repl = `\3b` - case '<': - repl = `\3c` - case '>': - repl = `\3e` - case '\\': - repl = `\\` - case '{': - repl = `\7b` - case '}': - repl = `\7d` + switch { + case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "": + repl = cssReplacementTable[r] default: continue } b.WriteString(s[written:i]) b.WriteString(repl) - written = i + utf8.RuneLen(r) + written = i + w if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) { b.WriteByte(' ') } @@ -218,6 +182,30 @@ func cssEscaper(args ...interface{}) string { return b.String() } +var cssReplacementTable = []string{ + 0: `\0`, + '\t': `\9`, + '\n': `\a`, + '\f': `\c`, + '\r': `\d`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\22`, + '&': `\26`, + '\'': `\27`, + '(': `\28`, + ')': `\29`, + '+': `\2b`, + '/': `\2f`, + ':': `\3a`, + ';': `\3b`, + '<': `\3c`, + '>': `\3e`, + '\\': `\\`, + '{': `\7b`, + '}': `\7d`, +} + var expressionBytes = []byte("expression") var mozBindingBytes = []byte("mozbinding") |
