]> Cypherpunks repositories - gostls13.git/commitdiff
mime/quotedprintable: accept = not followed by 2 hex digits as literal equals
authorRuss Cox <rsc@golang.org>
Wed, 26 Oct 2016 17:34:55 +0000 (13:34 -0400)
committerRuss Cox <rsc@golang.org>
Fri, 28 Oct 2016 16:08:06 +0000 (16:08 +0000)
This lets quotedprintable handle some inputs found in the wild,
most notably generated by "Microsoft CDO for Exchange 2000",
and it also matches how Python's quopri package handles these inputs.

Fixes #13219.

Change-Id: I69d400659d01b6ea0f707b7053d61803a85b4799
Reviewed-on: https://go-review.googlesource.com/32174
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/mime/quotedprintable/example_test.go
src/mime/quotedprintable/reader.go
src/mime/quotedprintable/reader_test.go

index 1ef841ed5c0c1e83c09b39da4bd0b21f9791075e..5a9ab450a3cb6e2a868da5bf585923234917ccf9 100644 (file)
@@ -15,7 +15,7 @@ import (
 func ExampleNewReader() {
        for _, s := range []string{
                `=48=65=6C=6C=6F=2C=20=47=6F=70=68=65=72=73=21`,
-               `invalid escape: =B`,
+               `invalid escape: <b style="font-size: 200%">hello</b>`,
                "Hello, Gophers! This symbol will be unescaped: =3D and this will be written in =\r\none line.",
        } {
                b, err := ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(s)))
@@ -23,7 +23,7 @@ func ExampleNewReader() {
        }
        // Output:
        // Hello, Gophers! <nil>
-       // invalid escape:  unexpected EOF
+       // invalid escape: <b style="font-size: 200%">hello</b> <nil>
        // Hello, Gophers! This symbol will be unescaped: = and this will be written in one line. <nil>
 }
 
index 7645777ab2170d34f3bd261b54a082a8b3ceb82a..b14224034307b480c1e6bcb98fc710075d2efebe 100644 (file)
@@ -77,6 +77,8 @@ func (r *Reader) Read(p []byte) (n int, err error) {
        // 3. it accepts soft line-break (=) at end of message (issue 15486); i.e.
        //    the final byte read from the underlying reader is allowed to be '=',
        //    and it will be silently ignored.
+       // 4. it takes = as literal = if not followed by two hex digits
+       //    but not at end of line (issue 13219).
        for len(p) > 0 {
                if len(r.line) == 0 {
                        if r.rerr != nil {
@@ -111,6 +113,11 @@ func (r *Reader) Read(p []byte) (n int, err error) {
                case b == '=':
                        b, err = readHexByte(r.line[1:])
                        if err != nil {
+                               if len(r.line) >= 2 && r.line[1] != '\r' && r.line[1] != '\n' {
+                                       // Take the = as a literal =.
+                                       b = '='
+                                       break
+                               }
                                return n, err
                        }
                        r.line = r.line[2:] // 2 of the 3; other 1 is done below
index 966f33e6c0efb6ea265188aaa523b06fd72e4a1f..ca016f969a4c1a62ebb7de9ce6a9007f7ae08b64 100644 (file)
@@ -30,7 +30,7 @@ func TestReader(t *testing.T) {
                {in: "foo bar=3d", want: "foo bar="}, // lax.
                {in: "foo bar=\n", want: "foo bar"},
                {in: "foo bar\n", want: "foo bar\n"}, // somewhat lax.
-               {in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
+               {in: "foo bar=0", want: "foo bar=0"}, // lax
                {in: "foo bar=0D=0A", want: "foo bar\r\n"},
                {in: " A B        \r\n C ", want: " A B\r\n C"},
                {in: " A B =\r\n C ", want: " A B  C"},
@@ -194,13 +194,10 @@ func TestExhaustive(t *testing.T) {
        }
        sort.Strings(outcomes)
        got := strings.Join(outcomes, "\n")
-       want := `OK: 21576
-invalid bytes after =: 3397
-quotedprintable: invalid hex byte 0x0a: 1400
-quotedprintable: invalid hex byte 0x0d: 2700
-quotedprintable: invalid hex byte 0x20: 2490
-quotedprintable: invalid hex byte 0x3d: 440
-unexpected EOF: 3122`
+       want := `OK: 28934
+invalid bytes after =: 3949
+quotedprintable: invalid hex byte 0x0d: 2048
+unexpected EOF: 194`
        if got != want {
                t.Errorf("Got:\n%s\nWant:\n%s", got, want)
        }