diff options
Diffstat (limited to 'libgo/go/net/mail')
-rw-r--r-- | libgo/go/net/mail/message.go | 23 | ||||
-rw-r--r-- | libgo/go/net/mail/message_test.go | 68 |
2 files changed, 85 insertions, 6 deletions
diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go index 266ac50..923630c 100644 --- a/libgo/go/net/mail/message.go +++ b/libgo/go/net/mail/message.go @@ -234,6 +234,12 @@ func (a *Address) String() string { return b.String() } + // Text in an encoded-word in a display-name must not contain certain + // characters like quotes or parentheses (see RFC 2047 section 5.3). + // When this is the case encode the name using base64 encoding. + if strings.ContainsAny(a.Name, "\"#$%&'(),.:;<>@[]^`{|}~") { + return mime.BEncoding.Encode("utf-8", a.Name) + " " + s + } return mime.QEncoding.Encode("utf-8", a.Name) + " " + s } @@ -386,10 +392,9 @@ func (p *addrParser) consumePhrase() (phrase string, err error) { // We actually parse dot-atom here to be more permissive // than what RFC 5322 specifies. word, err = p.consumeAtom(true, true) - } - - if err == nil { - word, err = p.decodeRFC2047Word(word) + if err == nil { + word, err = p.decodeRFC2047Word(word) + } } if err != nil { @@ -442,17 +447,25 @@ Loop: return string(qsb), nil } +var errNonASCII = errors.New("mail: unencoded non-ASCII text in address") + // consumeAtom parses an RFC 5322 atom at the start of p. // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. // If permissive is true, consumeAtom will not fail on // leading/trailing/double dots in the atom (see golang.org/issue/4938). func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { - if !isAtext(p.peek(), false) { + if c := p.peek(); !isAtext(c, false) { + if c > 127 { + return "", errNonASCII + } return "", errors.New("mail: invalid string") } i := 1 for ; i < p.len() && isAtext(p.s[i], dot); i++ { } + if i < p.len() && p.s[i] > 127 { + return "", errNonASCII + } atom, p.s = string(p.s[:i]), p.s[i:] if !permissive { if strings.HasPrefix(atom, ".") { diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go index 1b42274..4e718e2 100644 --- a/libgo/go/net/mail/message_test.go +++ b/libgo/go/net/mail/message_test.go @@ -127,6 +127,14 @@ func TestAddressParsingError(t *testing.T) { } } +func TestAddressParsingErrorUnquotedNonASCII(t *testing.T) { + const txt = "µ <micro@example.net>" + _, err := ParseAddress(txt) + if err == nil || !strings.Contains(err.Error(), "unencoded non-ASCII text in address") { + t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*unencoded non-ASCII text in address.*"`, txt, err) + } +} + func TestAddressParsing(t *testing.T) { tests := []struct { addrsStr string @@ -449,7 +457,7 @@ func TestAddressParser(t *testing.T) { } } -func TestAddressFormatting(t *testing.T) { +func TestAddressString(t *testing.T) { tests := []struct { addr *Address exp string @@ -491,11 +499,40 @@ func TestAddressFormatting(t *testing.T) { &Address{Name: "Rob", Address: "@"}, `"Rob" <@>`, }, + { + &Address{Name: "Böb, Jacöb", Address: "bob@example.com"}, + `=?utf-8?b?QsO2YiwgSmFjw7Zi?= <bob@example.com>`, + }, + { + &Address{Name: "=??Q?x?=", Address: "hello@world.com"}, + `"=??Q?x?=" <hello@world.com>`, + }, + { + &Address{Name: "=?hello", Address: "hello@world.com"}, + `"=?hello" <hello@world.com>`, + }, + { + &Address{Name: "world?=", Address: "hello@world.com"}, + `"world?=" <hello@world.com>`, + }, } for _, test := range tests { s := test.addr.String() if s != test.exp { t.Errorf("Address%+v.String() = %v, want %v", *test.addr, s, test.exp) + continue + } + + // Check round-trip. + if test.addr.Address != "" && test.addr.Address != "@" { + a, err := ParseAddress(test.exp) + if err != nil { + t.Errorf("ParseAddress(%#q): %v", test.exp, err) + continue + } + if a.Name != test.addr.Name || a.Address != test.addr.Address { + t.Errorf("ParseAddress(%#q) = %#v, want %#v", test.exp, a, test.addr) + } } } } @@ -586,3 +623,32 @@ func TestAddressParsingAndFormatting(t *testing.T) { } } + +func TestAddressFormattingAndParsing(t *testing.T) { + tests := []*Address{ + {Name: "@lïce", Address: "alice@example.com"}, + {Name: "Böb O'Connor", Address: "bob@example.com"}, + {Name: "???", Address: "bob@example.com"}, + {Name: "Böb ???", Address: "bob@example.com"}, + {Name: "Böb (Jacöb)", Address: "bob@example.com"}, + {Name: "à#$%&'(),.:;<>@[]^`{|}~'", Address: "bob@example.com"}, + // https://golang.org/issue/11292 + {Name: "\"\\\x1f,\"", Address: "0@0"}, + // https://golang.org/issue/12782 + {Name: "naé, mée", Address: "test.mail@gmail.com"}, + } + + for i, test := range tests { + parsed, err := ParseAddress(test.String()) + if err != nil { + t.Errorf("test #%d: ParseAddr(%q) error: %v", i, test.String(), err) + continue + } + if parsed.Name != test.Name { + t.Errorf("test #%d: Parsed name = %q; want %q", i, parsed.Name, test.Name) + } + if parsed.Address != test.Address { + t.Errorf("test #%d: Parsed address = %q; want %q", i, parsed.Address, test.Address) + } + } +} |