From 8ae584f21e32ab1a07d9d5d4d39cb5f7530c49df Mon Sep 17 00:00:00 2001 From: Daniel Speichert Date: Tue, 29 Dec 2015 16:46:40 +0100 Subject: [PATCH] net/textproto: accept multi-line error messages Ads documentation for both formats of messages accepted by ReadResponse(). Validity of message should not be altered by the validation process. On message with unexpected code, a properly formatted message was not fully read. Fixes #10230 Change-Id: Ic0b473059a68ab624ce0525e359d0f5d0b8d2117 Reviewed-on: https://go-review.googlesource.com/18172 Reviewed-by: Russ Cox --- src/net/textproto/reader.go | 16 +++++++++++++--- src/net/textproto/reader_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index 17edfadad2..91bbb57304 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -237,7 +237,12 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err err // separated by a newline (\n). // // See page 36 of RFC 959 (http://www.ietf.org/rfc/rfc959.txt) for -// details. +// details of another form of response accepted: +// +// code-message line 1 +// message line 2 +// ... +// code message line n // // If the prefix of the status does not match the digits in expectCode, // ReadResponse returns with err set to &Error{code, message}. @@ -248,7 +253,8 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err err // func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) { code, continued, message, err := r.readCodeLine(expectCode) - for err == nil && continued { + multi := continued + for continued { line, err := r.ReadLine() if err != nil { return 0, "", err @@ -256,7 +262,7 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err err var code2 int var moreMessage string - code2, continued, moreMessage, err = parseCodeLine(line, expectCode) + code2, continued, moreMessage, err = parseCodeLine(line, 0) if err != nil || code2 != code { message += "\n" + strings.TrimRight(line, "\r\n") continued = true @@ -264,6 +270,10 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err err } message += "\n" + moreMessage } + if err != nil && multi && message != "" { + // replace one line error message with all lines (full message) + err = &Error{code, message} + } return } diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go index db7d8ab41c..9c71594362 100644 --- a/src/net/textproto/reader_test.go +++ b/src/net/textproto/reader_test.go @@ -284,6 +284,35 @@ func TestRFC959Lines(t *testing.T) { } } +// Test that multi-line errors are appropriately and fully read. Issue 10230. +func TestReadMultiLineError(t *testing.T) { + r := reader("550-5.1.1 The email account that you tried to reach does not exist. Please try\n" + + "550-5.1.1 double-checking the recipient's email address for typos or\n" + + "550-5.1.1 unnecessary spaces. Learn more at\n" + + "Unexpected but legal text!\n" + + "550 5.1.1 https://support.google.com/mail/answer/6596 h20si25154304pfd.166 - gsmtp\n") + + wantMsg := "5.1.1 The email account that you tried to reach does not exist. Please try\n" + + "5.1.1 double-checking the recipient's email address for typos or\n" + + "5.1.1 unnecessary spaces. Learn more at\n" + + "Unexpected but legal text!\n" + + "5.1.1 https://support.google.com/mail/answer/6596 h20si25154304pfd.166 - gsmtp" + + code, msg, err := r.ReadResponse(250) + if err == nil { + t.Errorf("ReadResponse: no error, want error") + } + if code != 550 { + t.Errorf("ReadResponse: code=%d, want %d", code, 550) + } + if msg != wantMsg { + t.Errorf("ReadResponse: msg=%q, want %q", msg, wantMsg) + } + if err.Error() != "550 "+wantMsg { + t.Errorf("ReadResponse: error=%q, want %q", err.Error(), "550 "+wantMsg) + } +} + func TestCommonHeaders(t *testing.T) { for h := range commonHeader { if h != CanonicalMIMEHeaderKey(h) {