src/net/mail/message.go | 23 +++++++++++++++++------ src/net/mail/message_test.go | 11 +++++++++++ diff --git a/src/net/mail/message.go b/src/net/mail/message.go index fbf1fca68f5e683b76d81a60e85e7e45330aa30d..80140a467771b99590c253eadfbc4e520dbc7a86 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -575,8 +575,10 @@ // consumePhrase parses the RFC 5322 phrase at the start of p. func (p *addrParser) consumePhrase() (phrase string, err error) { debug.Printf("consumePhrase: [%s]", p.s) // phrase = 1*word - var words []string - var isPrevEncoded bool + var ( + words []string + sb strings.Builder + ) for { // obs-phrase allows CFWS after one word if len(words) > 0 { @@ -608,13 +610,22 @@ if err != nil { break } debug.Printf("consumePhrase: consumed %q", word) - if isPrevEncoded && isEncoded { - words[len(words)-1] += word - } else { + switch { + case isEncoded: + sb.WriteString(word) + case !isEncoded && sb.Len() > 0: + words = append(words, sb.String()) + sb.Reset() + words = append(words, word) + default: words = append(words, word) } - isPrevEncoded = isEncoded } + + if sb.Len() > 0 { + words = append(words, sb.String()) + } + // Ignore any error if we got at least one word. if err != nil && len(words) == 0 { debug.Printf("consumePhrase: hit err: %v", err) diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index 3393b03af54bf256bd36c3dc2ed174843614b181..80a4b2da765e6a35b003b846bcfaf37c14ce1780 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -1262,6 +1262,17 @@ t.Errorf(`ParseAddressList("") = %v, %v, want nil, error`, list, err) } } +func BenchmarkConsumePhrase(b *testing.B) { + for _, n := range []int{10, 100, 1000, 10000} { + b.Run(fmt.Sprintf("words-%d", n), func(b *testing.B) { + input := strings.Repeat("=?utf-8?q?hello?= ", n) + "" + for b.Loop() { + (&addrParser{s: input}).consumePhrase() + } + }) + } +} + func BenchmarkConsumeComment(b *testing.B) { for _, n := range []int{10, 100, 1000, 10000} { b.Run(fmt.Sprintf("depth-%d", n), func(b *testing.B) {