diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index 1f7afc57665cda..a4d6919888dbdf 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -157,7 +157,11 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([ r.buf = append(r.buf[:0], trim(line)...) // Read continuation lines. - for r.skipSpace() > 0 { + for { + n, err := r.skipSpace() + if n == 0 || err != nil { + return r.buf, err + } line, err := r.readLineSlice() if err != nil { break @@ -169,13 +173,13 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([ } // skipSpace skips R over all spaces and returns the number of bytes skipped. -func (r *Reader) skipSpace() int { +func (r *Reader) skipSpace() (int, error) { n := 0 for { c, err := r.R.ReadByte() if err != nil { // Bufio will keep err until next read. - break + return n, err } if c != ' ' && c != '\t' { r.R.UnreadByte() @@ -183,7 +187,7 @@ func (r *Reader) skipSpace() int { } n++ } - return n + return n, nil } func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) { diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go index d11d40f1cf10b3..ef14a0953cffc3 100644 --- a/src/net/textproto/reader_test.go +++ b/src/net/textproto/reader_test.go @@ -46,7 +46,7 @@ func TestReadContinuedLine(t *testing.T) { t.Fatalf("Line 2: %s, %v", s, err) } s, err = r.ReadContinuedLine() - if s != "line3" || err != nil { + if s != "line3" { t.Fatalf("Line 3: %s, %v", s, err) } s, err = r.ReadContinuedLine() @@ -225,6 +225,52 @@ func TestReadMIMEHeaderTrimContinued(t *testing.T) { } } +type autoRewind struct { + buf string + r io.Reader +} + +func (r *autoRewind) Read(p []byte) (int, error) { + if r.r == nil { + r.r = strings.NewReader(r.buf) + } + + n, err := r.r.Read(p) + if err == io.EOF { + // rewind + r.r = strings.NewReader(r.buf) + } + + return n, err +} + +// Special io reader that does not hold errors. Issue 53858 +func TestReadMimeHeaderRewind(t *testing.T) { + // Improper message, expect EOF as error + r := &autoRewind{ + buf: "From: Gopher \n" + + "To: Another Gopher \n", + } + + tp := NewReader(bufio.NewReader(r)) + _, err := tp.ReadMIMEHeader() + if err != io.EOF { + t.Fatalf("ReadMIMEHeaderRewind mismatch.\n got: %v\nwant: EOF", err) + } + + // Proper message, expect nil as err + r = &autoRewind{ + buf: "From: Gopher \r\n" + + "To: Another Gopher \r\n" + + "\r\n", + } + tp = NewReader(bufio.NewReader(r)) + _, err = tp.ReadMIMEHeader() + if err != nil { + t.Fatalf("ReadMIMEHeaderRewind mismatch.\n got: %v\nwant: nil", err) + } +} + type readResponseTest struct { in string inCode int