Skip to content

Commit e6e6eee

Browse files
committed
mime/quotedprintable: accept LWSP-char after =
SP and HTAB are allowed after a = before the following CRLF. RFC 2045 section 6.7 describes the ABNF for the quoted-printable encoding: qp-line := *(qp-segment transport-padding CRLF) qp-part transport-padding qp-segment := qp-section *(SPACE / TAB) "=" transport-padding := *LWSP-char ; Composers MUST NOT generate ; non-zero length transport ; padding, but receivers MUST ; be able to handle padding ; added by message transports. RFC 822 defines LWSP-char as: LWSP-char = SPACE / HTAB Dovecot's imaptest contains such a message in src/tests/fetch-binary-mime-qp.mbox. Fixes #70952
1 parent 669d87a commit e6e6eee

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

src/mime/quotedprintable/reader.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ var (
6666
crlf = []byte("\r\n")
6767
lf = []byte("\n")
6868
softSuffix = []byte("=")
69+
lwspChar = " \t"
6970
)
7071

7172
// Read reads and decodes quoted-printable data from the underlying reader.
@@ -92,7 +93,7 @@ func (r *Reader) Read(p []byte) (n int, err error) {
9293
wholeLine := r.line
9394
r.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
9495
if bytes.HasSuffix(r.line, softSuffix) {
95-
rightStripped := wholeLine[len(r.line):]
96+
rightStripped := bytes.TrimLeft(wholeLine[len(r.line):], lwspChar)
9697
r.line = r.line[:len(r.line)-1]
9798
if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) &&
9899
!(len(rightStripped) == 0 && len(r.line) > 0 && r.rerr == io.EOF) {

src/mime/quotedprintable/reader_test.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func TestReader(t *testing.T) {
6666
want: "Now's the time for all folk to come to the aid of their country."},
6767
{in: "accept UTF-8 right quotation mark: ’",
6868
want: "accept UTF-8 right quotation mark: ’"},
69+
70+
// Transport padding
71+
{in: "foo= \r\nbar", want: "foobar"},
72+
{in: "foo=\t \r\nbar", want: "foobar"},
6973
}
7074
for _, tt := range tests {
7175
var buf strings.Builder
@@ -199,13 +203,13 @@ func TestExhaustive(t *testing.T) {
199203
}
200204
slices.Sort(outcomes)
201205
got := strings.Join(outcomes, "\n")
202-
want := `OK: 28934
203-
invalid bytes after =: 3949
204-
quotedprintable: invalid hex byte 0x0d: 2048
206+
want := `OK: 30638
207+
invalid bytes after =: 2243
208+
quotedprintable: invalid hex byte 0x0d: 2050
205209
unexpected EOF: 194`
206210
if testing.Short() {
207-
want = `OK: 896
208-
invalid bytes after =: 100
211+
want = `OK: 935
212+
invalid bytes after =: 61
209213
quotedprintable: invalid hex byte 0x0d: 26
210214
unexpected EOF: 3`
211215
}

0 commit comments

Comments
 (0)