111 lines
1.9 KiB
Go
111 lines
1.9 KiB
Go
package message
|
|
|
|
import (
|
|
"io"
|
|
"mime/multipart"
|
|
)
|
|
|
|
// MultipartReader is an iterator over parts in a MIME multipart body.
|
|
type MultipartReader interface {
|
|
io.Closer
|
|
|
|
// NextPart returns the next part in the multipart or an error. When there are
|
|
// no more parts, the error io.EOF is returned.
|
|
//
|
|
// Entity.Body must be read completely before the next call to NextPart,
|
|
// otherwise it will be discarded.
|
|
NextPart() (*Entity, error)
|
|
}
|
|
|
|
type multipartReader struct {
|
|
r *multipart.Reader
|
|
}
|
|
|
|
// NextPart implements MultipartReader.
|
|
func (r *multipartReader) NextPart() (*Entity, error) {
|
|
p, err := r.r.NextPart()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return New(Header(p.Header), p)
|
|
}
|
|
|
|
// Close implements io.Closer.
|
|
func (r *multipartReader) Close() error {
|
|
return nil
|
|
}
|
|
|
|
type multipartBody struct {
|
|
header Header
|
|
parts []*Entity
|
|
|
|
r *io.PipeReader
|
|
w *Writer
|
|
|
|
i int
|
|
}
|
|
|
|
// Read implements io.Reader.
|
|
func (m *multipartBody) Read(p []byte) (n int, err error) {
|
|
if m.r == nil {
|
|
r, w := io.Pipe()
|
|
m.r = r
|
|
m.w = newWriter(w, m.header)
|
|
|
|
// Prevent calls to NextPart to succeed
|
|
m.i = len(m.parts)
|
|
|
|
go func() {
|
|
if err := m.writeBodyTo(m.w); err != nil {
|
|
w.CloseWithError(err)
|
|
return
|
|
}
|
|
|
|
if err := m.w.Close(); err != nil {
|
|
w.CloseWithError(err)
|
|
return
|
|
}
|
|
|
|
w.Close()
|
|
}()
|
|
}
|
|
|
|
return m.r.Read(p)
|
|
}
|
|
|
|
// Close implements io.Closer.
|
|
func (m *multipartBody) Close() error {
|
|
if m.r != nil {
|
|
m.r.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NextPart implements MultipartReader.
|
|
func (m *multipartBody) NextPart() (*Entity, error) {
|
|
if m.i >= len(m.parts) {
|
|
return nil, io.EOF
|
|
}
|
|
|
|
part := m.parts[m.i]
|
|
m.i++
|
|
return part, nil
|
|
}
|
|
|
|
func (m *multipartBody) writeBodyTo(w *Writer) error {
|
|
for _, p := range m.parts {
|
|
pw, err := w.CreatePart(p.Header)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := p.writeBodyTo(pw); err != nil {
|
|
return err
|
|
}
|
|
if err := pw.Close(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|