@@ -14,6 +14,7 @@ Notable divergences:
14
14
such as breaking addresses across lines.
15
15
- No unicode normalization is performed.
16
16
- The special characters ()[]:;@\, are allowed to appear unquoted in names.
17
+ - A leading From line is permitted, as in mbox format (RFC 4155).
17
18
*/
18
19
package mail
19
20
@@ -53,7 +54,7 @@ type Message struct {
53
54
func ReadMessage (r io.Reader ) (msg * Message , err error ) {
54
55
tp := textproto .NewReader (bufio .NewReader (r ))
55
56
56
- hdr , err := tp . ReadMIMEHeader ( )
57
+ hdr , err := readHeader ( tp )
57
58
if err != nil && (err != io .EOF || len (hdr ) == 0 ) {
58
59
return nil , err
59
60
}
@@ -64,6 +65,54 @@ func ReadMessage(r io.Reader) (msg *Message, err error) {
64
65
}, nil
65
66
}
66
67
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
+
67
116
// Layouts suitable for passing to time.Parse.
68
117
// These are tried in order.
69
118
var (
0 commit comments