]> Cypherpunks repositories - gostls13.git/commitdiff
net/mail: skip trailing comment while parsing email
authorMinaev Mike <minaev.mike@gmail.com>
Mon, 7 Aug 2017 08:22:21 +0000 (08:22 +0000)
committerIan Lance Taylor <iant@golang.org>
Sun, 24 Sep 2017 23:26:13 +0000 (23:26 +0000)
The existing implementation doesn't handle
comment constructions in email address.
So addresses that are consistent with RFC 5322
don't parse at all.

Fixes #21257

Change-Id: Iae3ba951dfb26b7cf0e1885a680bbceb9123d6d5
Reviewed-on: https://go-review.googlesource.com/53550
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/mail/message.go
src/net/mail/message_test.go

index debc77d7339c2c865ebc68145f5d061d0833b9da..e080e017da3554891942945faa0e9b694c673f50 100644 (file)
@@ -254,7 +254,9 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
                }
                list = append(list, addr)
 
-               p.skipSpace()
+               if !p.skipCfws() {
+                       return nil, errors.New("mail: misformatted parenthetical comment")
+               }
                if p.empty() {
                        break
                }
@@ -270,7 +272,9 @@ func (p *addrParser) parseSingleAddress() (*Address, error) {
        if err != nil {
                return nil, err
        }
-       p.skipSpace()
+       if !p.skipCfws() {
+               return nil, errors.New("mail: misformatted parenthetical comment")
+       }
        if !p.empty() {
                return nil, fmt.Errorf("mail: expected single address, got %q", p.s)
        }
@@ -548,6 +552,47 @@ func (p *addrParser) len() int {
        return len(p.s)
 }
 
+// skipCfws skips CFWS as defined in RFC5322.
+func (p *addrParser) skipCfws() bool {
+       p.skipSpace()
+
+       for {
+               if !p.consume('(') {
+                       break
+               }
+
+               if !p.skipComment() {
+                       return false
+               }
+
+               p.skipSpace()
+       }
+
+       return true
+}
+
+func (p *addrParser) skipComment() bool {
+       // '(' already consumed.
+       depth := 1
+
+       for {
+               if p.empty() || depth == 0 {
+                       break
+               }
+
+               if p.peek() == '\\' && p.len() > 1 {
+                       p.s = p.s[1:]
+               } else if p.peek() == '(' {
+                       depth++
+               } else if p.peek() == ')' {
+                       depth--
+               }
+               p.s = p.s[1:]
+       }
+
+       return depth == 0
+}
+
 func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) {
        if p.dec != nil {
                word, err = p.dec.Decode(s)
index 90269371125e2ad41a13756b4d4d75d25962b4ec..17655f98b44f25ff991066a79ce33ebac236d614 100644 (file)
@@ -129,16 +129,17 @@ func TestAddressParsingError(t *testing.T) {
                text        string
                wantErrText string
        }{
-               0: {"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>", "charset not supported"},
-               1: {"a@gmail.com b@gmail.com", "expected single address"},
-               2: {string([]byte{0xed, 0xa0, 0x80}) + " <micro@example.net>", "invalid utf-8 in address"},
-               3: {"\"" + string([]byte{0xed, 0xa0, 0x80}) + "\" <half-surrogate@example.com>", "invalid utf-8 in quoted-string"},
-               4: {"\"\\" + string([]byte{0x80}) + "\" <escaped-invalid-unicode@example.net>", "invalid utf-8 in quoted-string"},
-               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"},
+               0:  {"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>", "charset not supported"},
+               1:  {"a@gmail.com b@gmail.com", "expected single address"},
+               2:  {string([]byte{0xed, 0xa0, 0x80}) + " <micro@example.net>", "invalid utf-8 in address"},
+               3:  {"\"" + string([]byte{0xed, 0xa0, 0x80}) + "\" <half-surrogate@example.com>", "invalid utf-8 in quoted-string"},
+               4:  {"\"\\" + string([]byte{0x80}) + "\" <escaped-invalid-unicode@example.net>", "invalid utf-8 in quoted-string"},
+               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"},
+               10: {"cfws@example.com (", "misformatted parenthetical comment"},
        }
 
        for i, tc := range mustErrTestCases {
@@ -374,6 +375,29 @@ func TestAddressParsing(t *testing.T) {
                                },
                        },
                },
+               // CFWS
+               {
+                       `cfws@example.com (CFWS (cfws))  (another comment)`,
+                       []*Address{
+                               {
+                                       Name:    "",
+                                       Address: "cfws@example.com",
+                               },
+                       },
+               },
+               {
+                       `cfws@example.com ()  (another comment), cfws2@example.com (another)`,
+                       []*Address{
+                               {
+                                       Name:    "",
+                                       Address: "cfws@example.com",
+                               },
+                               {
+                                       Name:    "",
+                                       Address: "cfws2@example.com",
+                               },
+                       },
+               },
        }
        for _, test := range tests {
                if len(test.exp) == 1 {