diff --git a/src/net/mail/message.go b/src/net/mail/message.go index 985b6fcae2..5770e3d8dc 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -745,17 +745,41 @@ func (p *addrParser) consumeComment() (string, bool) { } func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) { - if p.dec != nil { - word, err = p.dec.Decode(s) - } else { - word, err = rfc2047Decoder.Decode(s) + dec := p.dec + if dec == nil { + dec = &rfc2047Decoder } + // Substitute our own CharsetReader function so that we can tell + // whether an error from the Decode method was due to the + // CharsetReader (meaning the charset is invalid). + // We used to look for the charsetError type in the error result, + // but that behaves badly with CharsetReaders other than the + // one in rfc2047Decoder. + adec := *dec + charsetReaderError := false + adec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { + if dec.CharsetReader == nil { + charsetReaderError = true + return nil, charsetError(charset) + } + r, err := dec.CharsetReader(charset, input) + if err != nil { + charsetReaderError = true + } + return r, err + } + word, err = adec.Decode(s) if err == nil { return word, true, nil } - if _, ok := err.(charsetError); ok { + // If the error came from the character set reader + // (meaning the character set itself is invalid + // but the decoding worked fine until then), + // return the original text and the error, + // with isEncoded=true. + if charsetReaderError { return s, true, err } diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index 80a17b2853..41c54b8687 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -344,6 +344,17 @@ func TestAddressParsingError(t *testing.T) { t.Errorf(`mail.ParseAddress(%q) #%d want %q, got %v`, tc.text, i, tc.wantErrText, err) } } + + t.Run("CustomWordDecoder", func(t *testing.T) { + p := &AddressParser{WordDecoder: &mime.WordDecoder{}} + for i, tc := range mustErrTestCases { + _, err := p.Parse(tc.text) + if err == nil || !strings.Contains(err.Error(), tc.wantErrText) { + t.Errorf(`p.Parse(%q) #%d want %q, got %v`, tc.text, i, tc.wantErrText, err) + } + } + }) + } func TestAddressParsing(t *testing.T) {