]> Cypherpunks repositories - gostls13.git/commitdiff
net/mail: parse cases when phrase has special chars without quotes
authorGuilherme Rezende <guilhermebr@gmail.com>
Mon, 24 Jul 2017 20:04:02 +0000 (17:04 -0300)
committerIan Lance Taylor <iant@golang.org>
Tue, 29 Aug 2017 21:59:44 +0000 (21:59 +0000)
Updates #21018

Change-Id: I00b6667fb5fee78559a391815f58760a2baea90e
Reviewed-on: https://go-review.googlesource.com/50911
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Avelino <t@avelino.xxx>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/mail/message.go
src/net/mail/message_test.go

index 45a995ec7208a8b77a4a8f9c9139bead5edbc038..debc77d7339c2c865ebc68145f5d061d0833b9da 100644 (file)
@@ -14,6 +14,7 @@ Notable divergences:
        * The full range of spacing (the CFWS syntax element) is not supported,
          such as breaking addresses across lines.
        * No unicode normalization is performed.
+       * Address with some RFC 5322 3.2.3 specials without quotes are parsed.
 */
 package mail
 
@@ -190,7 +191,7 @@ func (a *Address) String() string {
        // Add quotes if needed
        quoteLocal := false
        for i, r := range local {
-               if isAtext(r, false) {
+               if isAtext(r, false, false) {
                        continue
                }
                if r == '.' {
@@ -482,20 +483,20 @@ Loop:
 
 // 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).
+// If permissive is true, consumeAtom will not fail on:
+// - leading/trailing/double dots in the atom (see golang.org/issue/4938)
+// - special characters (RFC 5322 3.2.3) except '<', '>' and '"' (see golang.org/issue/21018)
 func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) {
        i := 0
 
 Loop:
        for {
                r, size := utf8.DecodeRuneInString(p.s[i:])
-
                switch {
                case size == 1 && r == utf8.RuneError:
                        return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s)
 
-               case size == 0 || !isAtext(r, dot):
+               case size == 0 || !isAtext(r, dot, permissive):
                        break Loop
 
                default:
@@ -580,12 +581,18 @@ func (e charsetError) Error() string {
 
 // isAtext reports whether r is an RFC 5322 atext character.
 // If dot is true, period is included.
-func isAtext(r rune, dot bool) bool {
+// If permissive is true, RFC 5322 3.2.3 specials is included,
+// except '<', '>' and '"'.
+func isAtext(r rune, dot, permissive bool) bool {
        switch r {
        case '.':
                return dot
 
-       case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials
+       // RFC 5322 3.2.3. specials
+       case '(', ')', '[', ']', ':', ';', '@', '\\', ',':
+               return permissive
+
+       case '<', '>', '"':
                return false
        }
        return isVchar(r)
index 2106a0b97d682d8d8c1b8db2125892eaafe82ce3..90269371125e2ad41a13756b4d4d75d25962b4ec 100644 (file)
@@ -137,6 +137,8 @@ func TestAddressParsingError(t *testing.T) {
                5: {"\"\x00\" <null@example.net>", "bad character in quoted-string"},
                6: {"\"\\\x00\" <escaped-null@example.net>", "bad character in quoted-string"},
                7: {"John Doe", "no angle-addr"},
+               8: {`<jdoe#machine.example>`, "missing @ in addr-spec"},
+               9: {`John <middle> Doe <jdoe@machine.example>`, "missing @ in addr-spec"},
        }
 
        for i, tc := range mustErrTestCases {
@@ -175,6 +177,34 @@ func TestAddressParsing(t *testing.T) {
                                Address: "john.q.public@example.com",
                        }},
                },
+               {
+                       `"John (middle) Doe" <jdoe@machine.example>`,
+                       []*Address{{
+                               Name:    "John (middle) Doe",
+                               Address: "jdoe@machine.example",
+                       }},
+               },
+               {
+                       `John (middle) Doe <jdoe@machine.example>`,
+                       []*Address{{
+                               Name:    "John (middle) Doe",
+                               Address: "jdoe@machine.example",
+                       }},
+               },
+               {
+                       `John !@M@! Doe <jdoe@machine.example>`,
+                       []*Address{{
+                               Name:    "John !@M@! Doe",
+                               Address: "jdoe@machine.example",
+                       }},
+               },
+               {
+                       `"John <middle> Doe" <jdoe@machine.example>`,
+                       []*Address{{
+                               Name:    "John <middle> Doe",
+                               Address: "jdoe@machine.example",
+                       }},
+               },
                {
                        `Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>`,
                        []*Address{
@@ -203,6 +233,14 @@ func TestAddressParsing(t *testing.T) {
                                },
                        },
                },
+               // RFC 5322, Appendix A.6.1
+               {
+                       `Joe Q. Public <john.q.public@example.com>`,
+                       []*Address{{
+                               Name:    "Joe Q. Public",
+                               Address: "john.q.public@example.com",
+                       }},
+               },
                // RFC 5322, Appendix A.1.3
                // TODO(dsymonds): Group addresses.