Skip to content

Commit cdf3273

Browse files
ianlancetaylorbradfitz
authored andcommitted
net/mail: permit more characters in mail headers
We parse mail messages using net/textproto. For golang#53188, we tightened up the bytes permitted by net/textproto to match RFC 7230. However, this package uses RFC 5322 which is more permissive. Restore the permisiveness we used to have, so that older code continues to work. Fixes golang#58862 Fixes golang#60332 Change-Id: I5437f5e18a756f6ca61c13c4d8ba727be73eff9a Reviewed-on: https://go-review.googlesource.com/c/go/+/504416 Run-TryBot: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
1 parent 9fb7e77 commit cdf3273

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

src/net/mail/message.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Notable divergences:
1414
such as breaking addresses across lines.
1515
- No unicode normalization is performed.
1616
- The special characters ()[]:;@\, are allowed to appear unquoted in names.
17+
- A leading From line is permitted, as in mbox format (RFC 4155).
1718
*/
1819
package mail
1920

@@ -53,7 +54,7 @@ type Message struct {
5354
func ReadMessage(r io.Reader) (msg *Message, err error) {
5455
tp := textproto.NewReader(bufio.NewReader(r))
5556

56-
hdr, err := tp.ReadMIMEHeader()
57+
hdr, err := readHeader(tp)
5758
if err != nil && (err != io.EOF || len(hdr) == 0) {
5859
return nil, err
5960
}
@@ -64,6 +65,54 @@ func ReadMessage(r io.Reader) (msg *Message, err error) {
6465
}, nil
6566
}
6667

68+
// readHeader reads the message headers from r.
69+
// This is like textproto.ReadMIMEHeader, but doesn't validate.
70+
// The fix for issue #53188 tightened up net/textproto to enforce
71+
// restrictions of RFC 7230.
72+
// This package implements RFC 5322, which does not have those restrictions.
73+
// This function copies the relevant code from net/textproto,
74+
// simplified for RFC 5322.
75+
func readHeader(r *textproto.Reader) (map[string][]string, error) {
76+
m := make(map[string][]string)
77+
78+
// The first line cannot start with a leading space.
79+
if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
80+
line, err := r.ReadLine()
81+
if err != nil {
82+
return m, err
83+
}
84+
return m, errors.New("malformed initial line: " + line)
85+
}
86+
87+
for {
88+
kv, err := r.ReadContinuedLine()
89+
if kv == "" {
90+
return m, err
91+
}
92+
93+
// Key ends at first colon.
94+
k, v, ok := strings.Cut(kv, ":")
95+
if !ok {
96+
return m, errors.New("malformed header line: " + kv)
97+
}
98+
key := textproto.CanonicalMIMEHeaderKey(k)
99+
100+
// Permit empty key, because that is what we did in the past.
101+
if key == "" {
102+
continue
103+
}
104+
105+
// Skip initial spaces in value.
106+
value := strings.TrimLeft(v, " \t")
107+
108+
m[key] = append(m[key], value)
109+
110+
if err != nil {
111+
return m, err
112+
}
113+
}
114+
}
115+
67116
// Layouts suitable for passing to time.Parse.
68117
// These are tried in order.
69118
var (

src/net/mail/message_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,34 @@ Version: 1
5252
},
5353
body: "",
5454
},
55+
{
56+
// RFC 5322 permits any printable ASCII character,
57+
// except colon, in a header key. Issue #58862.
58+
in: `From: [email protected]
59+
Custom/Header: v
60+
61+
Body
62+
`,
63+
header: Header{
64+
"From": []string{"[email protected]"},
65+
"Custom/Header": []string{"v"},
66+
},
67+
body: "Body\n",
68+
},
69+
{
70+
// RFC 4155 mbox format. We've historically permitted this,
71+
// so we continue to permit it. Issue #60332.
72+
in: `From [email protected] Mon Jun 19 00:00:00 2023
73+
74+
75+
Hello, gophers!
76+
`,
77+
header: Header{
78+
"From": []string{"[email protected]"},
79+
"From [email protected] Mon Jun 19 00": []string{"00:00 2023"},
80+
},
81+
body: "Hello, gophers!\n",
82+
},
5583
}
5684

5785
func TestParsing(t *testing.T) {

0 commit comments

Comments
 (0)