Commit 2b6d3b49 authored by Nigel Tao's avatar Nigel Tao

exp/template/html: string replacement refactoring.

R=mikesamuel
CC=golang-dev
https://golang.org/cl/4968063
parent 9854fd2a
......@@ -166,66 +166,7 @@ func jsValEscaper(args ...interface{}) string {
// JavaScript source, in JavaScript embedded in an HTML5 <script> element,
// or in an HTML5 event handler attribute such as onclick.
func jsStrEscaper(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
}
var b bytes.Buffer
written := 0
for i, r := range s {
var repl string
switch r {
case 0:
repl = `\0`
case '\t':
repl = `\t`
case '\n':
repl = `\n`
case '\v':
// "\v" == "v" on IE 6.
repl = `\x0b`
case '\f':
repl = `\f`
case '\r':
repl = `\r`
// Encode HTML specials as hex so the output can be embedded
// in HTML attributes without further encoding.
case '"':
repl = `\x22`
case '&':
repl = `\x26`
case '\'':
repl = `\x27`
case '+':
repl = `\x2b`
case '/':
repl = `\/`
case '<':
repl = `\x3c`
case '>':
repl = `\x3e`
case '\\':
repl = `\\`
case '\u2028':
repl = `\u2028`
case '\u2029':
repl = `\u2029`
default:
continue
}
b.WriteString(s[written:i])
b.WriteString(repl)
written = i + utf8.RuneLen(r)
}
if written == 0 {
return s
}
b.WriteString(s[written:])
return b.String()
return replace(stringify(args...), jsStrReplacementTable)
}
// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression
......@@ -233,79 +174,35 @@ func jsStrEscaper(args ...interface{}) string {
// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by
// the literal text of {{.X}} followed by the string "bar".
func jsRegexpEscaper(args ...interface{}) string {
ok := false
var s string
return replace(stringify(args...), jsRegexpReplacementTable)
}
// stringify is an optimized form of fmt.Sprint.
func stringify(args ...interface{}) string {
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
if s, ok := args[0].(string); ok {
return s
}
}
return fmt.Sprint(args...)
}
// replace replaces each rune r of s with replacementTable[r], provided that
// r < len(replacementTable). If replacementTable[r] is the empty string then
// no replacement is made.
// It also replaces the runes '\u2028' and '\u2029' with the strings
// `\u2028` and `\u2029`. Note the different quotes used.
func replace(s string, replacementTable []string) string {
var b bytes.Buffer
written := 0
for i, r := range s {
var repl string
switch r {
case 0:
repl = `\0`
case '\t':
repl = `\t`
case '\n':
repl = `\n`
case '\v':
// "\v" == "v" on IE 6.
repl = `\x0b`
case '\f':
repl = `\f`
case '\r':
repl = `\r`
// Encode HTML specials as hex so the output can be embedded
// in HTML attributes without further encoding.
case '"':
repl = `\x22`
case '$':
repl = `\$`
case '&':
repl = `\x26`
case '\'':
repl = `\x27`
case '(':
repl = `\(`
case ')':
repl = `\)`
case '*':
repl = `\*`
case '+':
repl = `\x2b`
case '-':
repl = `\-`
case '.':
repl = `\.`
case '/':
repl = `\/`
case '<':
repl = `\x3c`
case '>':
repl = `\x3e`
case '?':
repl = `\?`
case '[':
repl = `\[`
case '\\':
repl = `\\`
case ']':
repl = `\]`
case '^':
repl = `\^`
case '{':
repl = `\{`
case '|':
repl = `\|`
case '}':
repl = `\}`
case '\u2028':
switch {
case r < len(replacementTable) && replacementTable[r] != "":
repl = replacementTable[r]
case r == '\u2028':
repl = `\u2028`
case '\u2029':
case r == '\u2029':
repl = `\u2029`
default:
continue
......@@ -321,6 +218,57 @@ func jsRegexpEscaper(args ...interface{}) string {
return b.String()
}
var jsStrReplacementTable = []string{
0: `\0`,
'\t': `\t`,
'\n': `\n`,
'\v': `\x0b`, // "\v" == "v" on IE 6.
'\f': `\f`,
'\r': `\r`,
// Encode HTML specials as hex so the output can be embedded
// in HTML attributes without further encoding.
'"': `\x22`,
'&': `\x26`,
'\'': `\x27`,
'+': `\x2b`,
'/': `\/`,
'<': `\x3c`,
'>': `\x3e`,
'\\': `\\`,
}
var jsRegexpReplacementTable = []string{
0: `\0`,
'\t': `\t`,
'\n': `\n`,
'\v': `\x0b`, // "\v" == "v" on IE 6.
'\f': `\f`,
'\r': `\r`,
// Encode HTML specials as hex so the output can be embedded
// in HTML attributes without further encoding.
'"': `\x22`,
'$': `\$`,
'&': `\x26`,
'\'': `\x27`,
'(': `\(`,
')': `\)`,
'*': `\*`,
'+': `\x2b`,
'-': `\-`,
'.': `\.`,
'/': `\/`,
'<': `\x3c`,
'>': `\x3e`,
'?': `\?`,
'[': `\[`,
'\\': `\\`,
']': `\]`,
'^': `\^`,
'{': `\{`,
'|': `\|`,
'}': `\}`,
}
// isJSIdentPart is true if the given rune is a JS identifier part.
// It does not handle all the non-Latin letters, joiners, and combining marks,
// but it does handle every codepoint that can occur in a numeric literal or
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment