From e73f1d73143ebba9c7e80d21c45bba9b61f2611c Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Tue, 1 May 2018 01:54:11 +0900 Subject: MM-9072/MM-10185 Force-convert the encoding of OpenGraph metadata to UTF-8 (#8631) * Force-convert non-UTF8 HTML to UTF8 before opengraph processing * Split the force-encoding function * Add benchmark Test for the forceHTMLEncodingToUTF8() ``` Running tool: /home/comet/go-v1.9.2/bin/go test -benchmem -run=^$ github.com/mattermost/mattermost-server/app -bench ^BenchmarkForceHTMLEncodingToUTF8$ [03:32:58 KST 2018/04/21] [INFO] (github.com/mattermost/mattermost-server/app.TestMain:28) -test.run used, not creating temporary containers goos: linux goarch: amd64 pkg: github.com/mattermost/mattermost-server/app BenchmarkForceHTMLEncodingToUTF8/with_converting-4 100000 11201 ns/op 18704 B/op 32 allocs/op BenchmarkForceHTMLEncodingToUTF8/without_converting-4 300000 3931 ns/op 4632 B/op 13 allocs/op PASS ok github.com/mattermost/mattermost-server/app 2.703s Success: Benchmarks passed. ``` * Remove an unnecessary constraint * Add pre-check if content-type header is already utf-8 * Move the checking for utf-8 into forceHTMLEncodingToUTF8() for testing * Revert df3f347213faa0d023c26d201fa6531f46391086..HEAD, without Gopkg.lock --- .../x/text/encoding/simplifiedchinese/hzgb2312.go | 245 +++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go (limited to 'vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go') diff --git a/vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go b/vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go new file mode 100644 index 000000000..eb3157f0b --- /dev/null +++ b/vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go @@ -0,0 +1,245 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package simplifiedchinese + +import ( + "unicode/utf8" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/internal" + "golang.org/x/text/encoding/internal/identifier" + "golang.org/x/text/transform" +) + +// HZGB2312 is the HZ-GB2312 encoding. +var HZGB2312 encoding.Encoding = &hzGB2312 + +var hzGB2312 = internal.Encoding{ + internal.FuncEncoding{hzGB2312NewDecoder, hzGB2312NewEncoder}, + "HZ-GB2312", + identifier.HZGB2312, +} + +func hzGB2312NewDecoder() transform.Transformer { + return new(hzGB2312Decoder) +} + +func hzGB2312NewEncoder() transform.Transformer { + return new(hzGB2312Encoder) +} + +const ( + asciiState = iota + gbState +) + +type hzGB2312Decoder int + +func (d *hzGB2312Decoder) Reset() { + *d = asciiState +} + +func (d *hzGB2312Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + r, size := rune(0), 0 +loop: + for ; nSrc < len(src); nSrc += size { + c0 := src[nSrc] + if c0 >= utf8.RuneSelf { + r, size = utf8.RuneError, 1 + goto write + } + + if c0 == '~' { + if nSrc+1 >= len(src) { + if !atEOF { + err = transform.ErrShortSrc + break loop + } + r = utf8.RuneError + goto write + } + size = 2 + switch src[nSrc+1] { + case '{': + *d = gbState + continue + case '}': + *d = asciiState + continue + case '~': + if nDst >= len(dst) { + err = transform.ErrShortDst + break loop + } + dst[nDst] = '~' + nDst++ + continue + case '\n': + continue + default: + r = utf8.RuneError + goto write + } + } + + if *d == asciiState { + r, size = rune(c0), 1 + } else { + if nSrc+1 >= len(src) { + if !atEOF { + err = transform.ErrShortSrc + break loop + } + r, size = utf8.RuneError, 1 + goto write + } + size = 2 + c1 := src[nSrc+1] + if c0 < 0x21 || 0x7e <= c0 || c1 < 0x21 || 0x7f <= c1 { + // error + } else if i := int(c0-0x01)*190 + int(c1+0x3f); i < len(decode) { + r = rune(decode[i]) + if r != 0 { + goto write + } + } + if c1 > utf8.RuneSelf { + // Be consistent and always treat non-ASCII as a single error. + size = 1 + } + r = utf8.RuneError + } + + write: + if nDst+utf8.RuneLen(r) > len(dst) { + err = transform.ErrShortDst + break loop + } + nDst += utf8.EncodeRune(dst[nDst:], r) + } + return nDst, nSrc, err +} + +type hzGB2312Encoder int + +func (d *hzGB2312Encoder) Reset() { + *d = asciiState +} + +func (e *hzGB2312Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + r, size := rune(0), 0 + for ; nSrc < len(src); nSrc += size { + r = rune(src[nSrc]) + + // Decode a 1-byte rune. + if r < utf8.RuneSelf { + size = 1 + if r == '~' { + if nDst+2 > len(dst) { + err = transform.ErrShortDst + break + } + dst[nDst+0] = '~' + dst[nDst+1] = '~' + nDst += 2 + continue + } else if *e != asciiState { + if nDst+3 > len(dst) { + err = transform.ErrShortDst + break + } + *e = asciiState + dst[nDst+0] = '~' + dst[nDst+1] = '}' + nDst += 2 + } else if nDst >= len(dst) { + err = transform.ErrShortDst + break + } + dst[nDst] = uint8(r) + nDst += 1 + continue + + } + + // Decode a multi-byte rune. + r, size = utf8.DecodeRune(src[nSrc:]) + if size == 1 { + // All valid runes of size 1 (those below utf8.RuneSelf) were + // handled above. We have invalid UTF-8 or we haven't seen the + // full character yet. + if !atEOF && !utf8.FullRune(src[nSrc:]) { + err = transform.ErrShortSrc + break + } + } + + // func init checks that the switch covers all tables. + switch { + case encode0Low <= r && r < encode0High: + if r = rune(encode0[r-encode0Low]); r != 0 { + goto writeGB + } + case encode1Low <= r && r < encode1High: + if r = rune(encode1[r-encode1Low]); r != 0 { + goto writeGB + } + case encode2Low <= r && r < encode2High: + if r = rune(encode2[r-encode2Low]); r != 0 { + goto writeGB + } + case encode3Low <= r && r < encode3High: + if r = rune(encode3[r-encode3Low]); r != 0 { + goto writeGB + } + case encode4Low <= r && r < encode4High: + if r = rune(encode4[r-encode4Low]); r != 0 { + goto writeGB + } + } + + terminateInASCIIState: + // Switch back to ASCII state in case of error so that an ASCII + // replacement character can be written in the correct state. + if *e != asciiState { + if nDst+2 > len(dst) { + err = transform.ErrShortDst + break + } + dst[nDst+0] = '~' + dst[nDst+1] = '}' + nDst += 2 + } + err = internal.ErrASCIIReplacement + break + + writeGB: + c0 := uint8(r>>8) - 0x80 + c1 := uint8(r) - 0x80 + if c0 < 0x21 || 0x7e <= c0 || c1 < 0x21 || 0x7f <= c1 { + goto terminateInASCIIState + } + if *e == asciiState { + if nDst+4 > len(dst) { + err = transform.ErrShortDst + break + } + *e = gbState + dst[nDst+0] = '~' + dst[nDst+1] = '{' + nDst += 2 + } else if nDst+2 > len(dst) { + err = transform.ErrShortDst + break + } + dst[nDst+0] = c0 + dst[nDst+1] = c1 + nDst += 2 + continue + } + // TODO: should one always terminate in ASCII state to make it safe to + // concatenate two HZ-GB2312-encoded strings? + return nDst, nSrc, err +} -- cgit v1.2.3-1-g7c22