mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 12:46:46 +00:00
131 lines
3.0 KiB
Go
131 lines
3.0 KiB
Go
// Copyright (c) 2021 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 message
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
)
|
|
|
|
type boundaryReader struct {
|
|
reader *bufio.Reader
|
|
|
|
closed, first bool
|
|
skipped int
|
|
|
|
nl []byte // "\r\n" or "\n" (set after seeing first boundary line)
|
|
nlDashBoundary []byte // nl + "--boundary"
|
|
dashBoundaryDash []byte // "--boundary--"
|
|
dashBoundary []byte // "--boundary"
|
|
}
|
|
|
|
func newBoundaryReader(r *bufio.Reader, boundary string) (br *boundaryReader, err error) {
|
|
b := []byte("\r\n--" + boundary + "--")
|
|
br = &boundaryReader{
|
|
reader: r,
|
|
closed: false,
|
|
first: true,
|
|
nl: b[:2],
|
|
nlDashBoundary: b[:len(b)-2],
|
|
dashBoundaryDash: b[2:],
|
|
dashBoundary: b[2 : len(b)-2],
|
|
}
|
|
err = br.writeNextPartTo(nil)
|
|
return
|
|
}
|
|
|
|
// writeNextPartTo will copy the the bytes of next part and write them to
|
|
// writer. Will return EOF if the underlying reader is empty.
|
|
func (br *boundaryReader) writeNextPartTo(part io.Writer) (err error) {
|
|
if br.closed {
|
|
return io.EOF
|
|
}
|
|
|
|
var line, slice []byte
|
|
br.skipped = 0
|
|
|
|
for {
|
|
slice, err = br.reader.ReadSlice('\n')
|
|
line = append(line, slice...)
|
|
if err == bufio.ErrBufferFull {
|
|
continue
|
|
}
|
|
|
|
br.skipped += len(line)
|
|
|
|
if err == io.EOF && br.isFinalBoundary(line) {
|
|
err = nil
|
|
br.closed = true
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if br.isBoundaryDelimiterLine(line) {
|
|
br.first = false
|
|
return
|
|
}
|
|
|
|
if br.isFinalBoundary(line) {
|
|
br.closed = true
|
|
return
|
|
}
|
|
|
|
if part != nil {
|
|
if _, err = part.Write(line); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
line = []byte{}
|
|
}
|
|
}
|
|
|
|
func (br *boundaryReader) isFinalBoundary(line []byte) bool {
|
|
if !bytes.HasPrefix(line, br.dashBoundaryDash) {
|
|
return false
|
|
}
|
|
rest := line[len(br.dashBoundaryDash):]
|
|
rest = skipLWSPChar(rest)
|
|
return len(rest) == 0 || bytes.Equal(rest, br.nl)
|
|
}
|
|
|
|
func (br *boundaryReader) isBoundaryDelimiterLine(line []byte) (ret bool) {
|
|
if !bytes.HasPrefix(line, br.dashBoundary) {
|
|
return false
|
|
}
|
|
rest := line[len(br.dashBoundary):]
|
|
rest = skipLWSPChar(rest)
|
|
|
|
if br.first && len(rest) == 1 && rest[0] == '\n' {
|
|
br.nl = br.nl[1:]
|
|
br.nlDashBoundary = br.nlDashBoundary[1:]
|
|
}
|
|
return bytes.Equal(rest, br.nl)
|
|
}
|
|
|
|
func skipLWSPChar(b []byte) []byte {
|
|
for len(b) > 0 && (b[0] == ' ' || b[0] == '\t') {
|
|
b = b[1:]
|
|
}
|
|
return b
|
|
}
|