Skip to content

Commit

Permalink
[release-branch.go1.20] net/mail: permit more characters in mail headers
Browse files Browse the repository at this point in the history
We parse mail messages using net/textproto. For #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.

For #58862
For #60332
Fixes #60874
Fixes #60875

Change-Id: I5437f5e18a756f6ca61c13c4d8ba727be73eff9a
Reviewed-on: https://go-review.googlesource.com/c/go/+/504881
Run-TryBot: Ian Lance Taylor <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
Reviewed-by: Damien Neil <[email protected]>
  • Loading branch information
ianlancetaylor authored and Ian Lance Taylor committed Jun 21, 2023
1 parent c32f1af commit b59efe6
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
51 changes: 50 additions & 1 deletion src/net/mail/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Notable divergences:
such as breaking addresses across lines.
- No unicode normalization is performed.
- The special characters ()[]:;@\, are allowed to appear unquoted in names.
- A leading From line is permitted, as in mbox format (RFC 4155).
*/
package mail

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

hdr, err := tp.ReadMIMEHeader()
hdr, err := readHeader(tp)
if err != nil {
return nil, err
}
Expand All @@ -64,6 +65,54 @@ func ReadMessage(r io.Reader) (msg *Message, err error) {
}, nil
}

// readHeader reads the message headers from r.
// This is like textproto.ReadMIMEHeader, but doesn't validate.
// The fix for issue #53188 tightened up net/textproto to enforce
// restrictions of RFC 7230.
// This package implements RFC 5322, which does not have those restrictions.
// This function copies the relevant code from net/textproto,
// simplified for RFC 5322.
func readHeader(r *textproto.Reader) (map[string][]string, error) {
m := make(map[string][]string)

// The first line cannot start with a leading space.
if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
line, err := r.ReadLine()
if err != nil {
return m, err
}
return m, errors.New("malformed initial line: " + line)
}

for {
kv, err := r.ReadContinuedLine()
if kv == "" {
return m, err
}

// Key ends at first colon.
k, v, ok := strings.Cut(kv, ":")
if !ok {
return m, errors.New("malformed header line: " + kv)
}
key := textproto.CanonicalMIMEHeaderKey(k)

// Permit empty key, because that is what we did in the past.
if key == "" {
continue
}

// Skip initial spaces in value.
value := strings.TrimLeft(v, " \t")

m[key] = append(m[key], value)

if err != nil {
return m, err
}
}
}

// Layouts suitable for passing to time.Parse.
// These are tried in order.
var (
Expand Down
28 changes: 28 additions & 0 deletions src/net/mail/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ So, "Hello".
},
body: "This is a message just to say hello.\nSo, \"Hello\".\n",
},
{
// RFC 5322 permits any printable ASCII character,
// except colon, in a header key. Issue #58862.
in: `From: [email protected]
Custom/Header: v
Body
`,
header: Header{
"From": []string{"[email protected]"},
"Custom/Header": []string{"v"},
},
body: "Body\n",
},
{
// RFC 4155 mbox format. We've historically permitted this,
// so we continue to permit it. Issue #60332.
in: `From [email protected] Mon Jun 19 00:00:00 2023
From: [email protected]
Hello, gophers!
`,
header: Header{
"From": []string{"[email protected]"},
"From [email protected] Mon Jun 19 00": []string{"00:00 2023"},
},
body: "Hello, gophers!\n",
},
}

func TestParsing(t *testing.T) {
Expand Down

0 comments on commit b59efe6

Please sign in to comment.