Commit 24555c7b authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

mime/multipart: don't strip leading space/tab in quoted-printable decoding

Late bug fix, but this is arguably a regression from Go 1.0,
since we added this transparent decoding since then. Without
this fix, Go 1.0 users could decode this correctly, but Go 1.1
users would not be able to.

The newly added test is from the RFC itself.

The updated tests had the wrong "want" values before. They
were there to test \r\n vs \n equivalence (which is
unchanged), not leading whitespace.

The skipWhite decoder struct field was added in the battles of
Issue 4771 in revision b3bb265bfecf. It was just a wrong
strategy, from an earlier round of attempts in
https://golang.org/cl/7300092/

Update #4771
Fixes #5295

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/8536045
parent 67e26fce
......@@ -18,16 +18,14 @@ import (
)
type qpReader struct {
br *bufio.Reader
skipWhite bool
rerr error // last read error
line []byte // to be consumed before more of br
br *bufio.Reader
rerr error // last read error
line []byte // to be consumed before more of br
}
func newQuotedPrintableReader(r io.Reader) io.Reader {
return &qpReader{
br: bufio.NewReader(r),
skipWhite: true,
br: bufio.NewReader(r),
}
}
......@@ -55,10 +53,6 @@ func (q *qpReader) readHexByte(v []byte) (b byte, err error) {
return hb<<4 | lb, nil
}
func isQPSkipWhiteByte(b byte) bool {
return b == ' ' || b == '\t'
}
func isQPDiscardWhitespace(r rune) bool {
switch r {
case '\n', '\r', ' ', '\t':
......@@ -79,7 +73,6 @@ func (q *qpReader) Read(p []byte) (n int, err error) {
if q.rerr != nil {
return n, q.rerr
}
q.skipWhite = true
q.line, q.rerr = q.br.ReadSlice('\n')
// Does the line end in CRLF instead of just LF?
......@@ -103,11 +96,6 @@ func (q *qpReader) Read(p []byte) (n int, err error) {
continue
}
b := q.line[0]
if q.skipWhite && isQPSkipWhiteByte(b) {
q.line = q.line[1:]
continue
}
q.skipWhite = false
switch {
case b == '=':
......
......@@ -32,8 +32,9 @@ func TestQuotedPrintable(t *testing.T) {
{in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
{in: "foo bar=ab", want: "foo bar", err: "multipart: invalid quoted-printable hex byte 0x61"},
{in: "foo bar=0D=0A", want: "foo bar\r\n"},
{in: " A B =\r\n C ", want: "A B C"},
{in: " A B =\n C ", want: "A B C"}, // lax. treating LF as CRLF
{in: " A B \r\n C ", want: " A B\r\n C"},
{in: " A B =\r\n C ", want: " A B C"},
{in: " A B =\n C ", want: " A B C"}, // lax. treating LF as CRLF
{in: "foo=\nbar", want: "foobar"},
{in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"},
{in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"},
......@@ -57,6 +58,10 @@ func TestQuotedPrintable(t *testing.T) {
{in: "foo=\nbar", want: "foobar"},
{in: "foo=\rbar", want: "foo", err: "multipart: invalid quoted-printable hex byte 0x0d"},
{in: "foo=\r\r\r \nbar", want: "foo", err: `multipart: invalid bytes after =: "\r\r\r \n"`},
// Example from RFC 2045:
{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
want: "Now's the time for all folk to come to the aid of their country."},
}
for _, tt := range tests {
var buf bytes.Buffer
......
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