mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-11 05:06:51 +00:00
fix(GODT-770): handle extraneous end-of-mail
This commit is contained in:
@ -32,7 +32,7 @@ type Parser struct {
|
||||
func New(r io.Reader) (*Parser, error) {
|
||||
p := new(Parser)
|
||||
|
||||
entity, err := message.Read(r)
|
||||
entity, err := message.Read(newEndOfMailTrimmer(r))
|
||||
if err != nil && !message.IsUnknownCharset(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
56
pkg/message/parser/trimmer.go
Normal file
56
pkg/message/parser/trimmer.go
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
const endOfMail = "\r\n.\r\n"
|
||||
|
||||
// endOfMailTrimmer wraps a reader to trim the End-Of-Mail indicator at the end
|
||||
// of the input, if present.
|
||||
//
|
||||
// During SMTP sending of a message, the DATA command indicates that you are
|
||||
// about to send the text (or body) of the message. The message text must end
|
||||
// with "\r\n.\r\n." I'm 99% sure that these 5 bytes should not be considered
|
||||
// part of the message body. However, some mail servers keep them as part of
|
||||
// the message, which our parser sometimes doesn't like. Therefore, we strip
|
||||
// them if we find them.
|
||||
type endOfMailTrimmer struct {
|
||||
r io.Reader
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func newEndOfMailTrimmer(r io.Reader) *endOfMailTrimmer {
|
||||
return &endOfMailTrimmer{r: r}
|
||||
}
|
||||
|
||||
func (r *endOfMailTrimmer) Read(p []byte) (int, error) {
|
||||
_, err := io.CopyN(&r.buf, r.r, int64(len(p)+len(endOfMail)-r.buf.Len()))
|
||||
if err != nil && err != io.EOF {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err == io.EOF && bytes.HasSuffix(r.buf.Bytes(), []byte(endOfMail)) {
|
||||
r.buf.Truncate(r.buf.Len() - len(endOfMail))
|
||||
}
|
||||
|
||||
return r.buf.Read(p)
|
||||
}
|
||||
55
pkg/message/parser/trimmer_test.go
Normal file
55
pkg/message/parser/trimmer_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package parser
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEndOfMailTrimmer(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"string without eom", "string without eom"},
|
||||
{"string with eom\r\n.\r\n", "string with eom"},
|
||||
{"string with eom\r\n.\r\nin the middle", "string with eom\r\n.\r\nin the middle"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.in, func(t *testing.T) {
|
||||
res := dumbRead(newEndOfMailTrimmer(strings.NewReader(tt.in)))
|
||||
assert.Equal(t, tt.out, string(res))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func dumbRead(r io.Reader) []byte {
|
||||
out := []byte{}
|
||||
|
||||
b := make([]byte, 1)
|
||||
for _, err := r.Read(b); err == nil; _, err = r.Read(b) {
|
||||
out = append(out, b...)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user