2018-09-25 19:22:25 +00:00
|
|
|
package multipart
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2019-05-01 19:30:16 +00:00
|
|
|
// Reader is a multipart reader.
|
|
|
|
type Reader struct {
|
2019-05-04 08:04:16 +00:00
|
|
|
// io.Reader used for reading multipart components reading.
|
2019-05-01 19:30:16 +00:00
|
|
|
reader *bufio.Reader
|
|
|
|
|
2019-05-04 08:04:16 +00:00
|
|
|
// boundary used to separate multipart components.
|
2019-05-01 19:30:16 +00:00
|
|
|
boundary string
|
|
|
|
|
2019-05-04 08:04:16 +00:00
|
|
|
// data will contain parsed components.
|
2019-05-01 19:30:16 +00:00
|
|
|
Data map[string]*Component
|
|
|
|
}
|
|
|
|
|
2019-05-04 08:04:16 +00:00
|
|
|
// NewReader creates a new multipart reader for a reader and a boundary.
|
2019-05-01 16:01:32 +00:00
|
|
|
func NewReader(r io.Reader, boundary string) (*Reader, error) {
|
2018-09-25 19:22:25 +00:00
|
|
|
reader := &Reader{
|
|
|
|
reader: nil,
|
2019-05-01 16:01:32 +00:00
|
|
|
boundary: fmt.Sprintf("--%s", boundary),
|
2018-09-25 19:22:25 +00:00
|
|
|
Data: make(map[string]*Component),
|
|
|
|
}
|
|
|
|
|
|
|
|
// 1. Create reader
|
2019-05-01 16:01:32 +00:00
|
|
|
dst, ok := r.(*bufio.Reader)
|
2018-09-25 19:22:25 +00:00
|
|
|
if !ok {
|
2019-05-01 16:01:32 +00:00
|
|
|
dst = bufio.NewReader(r)
|
2018-09-25 19:22:25 +00:00
|
|
|
}
|
|
|
|
reader.reader = dst
|
|
|
|
|
2019-05-01 19:30:16 +00:00
|
|
|
// 2. "move" reader right after the first boundary
|
2018-09-25 19:22:25 +00:00
|
|
|
var err error
|
|
|
|
line := make([]byte, 0)
|
|
|
|
|
|
|
|
for err == nil && string(line) != reader.boundary {
|
|
|
|
line, _, err = dst.ReadLine()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. return reader
|
|
|
|
return reader, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-04 08:04:16 +00:00
|
|
|
// Parse parses the multipart components from the reader.
|
2018-09-25 19:22:25 +00:00
|
|
|
func (reader *Reader) Parse() error {
|
|
|
|
|
2019-05-01 19:30:16 +00:00
|
|
|
// for each component (until boundary)
|
2018-09-25 19:22:25 +00:00
|
|
|
for {
|
|
|
|
|
2018-09-26 05:42:03 +00:00
|
|
|
comp := &Component{
|
2018-09-25 19:22:25 +00:00
|
|
|
ContentType: "raw",
|
|
|
|
Data: make([]byte, 0),
|
|
|
|
Headers: make(map[string]string),
|
|
|
|
}
|
|
|
|
|
|
|
|
// 1. Read and parse data
|
2018-09-26 05:42:03 +00:00
|
|
|
err := comp.read(reader.reader, reader.boundary)
|
2018-09-25 19:22:25 +00:00
|
|
|
|
|
|
|
// 3. Dispatch error
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-09-26 05:42:03 +00:00
|
|
|
name := comp.GetHeader("name")
|
2018-09-25 19:22:25 +00:00
|
|
|
if len(name) < 1 {
|
2020-04-04 10:43:55 +00:00
|
|
|
return errMissingDataName
|
2018-09-25 19:22:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, nameUsed := reader.Data[name]; nameUsed {
|
2020-04-04 10:43:55 +00:00
|
|
|
return errDataNameConflict
|
2018-09-25 19:22:25 +00:00
|
|
|
}
|
|
|
|
|
2018-09-26 05:42:03 +00:00
|
|
|
reader.Data[name] = comp
|
2018-09-25 19:22:25 +00:00
|
|
|
|
|
|
|
if err == io.EOF {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-04 08:04:16 +00:00
|
|
|
// Get returns a multipart component by its name.
|
2018-09-25 19:22:25 +00:00
|
|
|
func (reader *Reader) Get(_key string) *Component {
|
|
|
|
data, ok := reader.Data[_key]
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return data
|
|
|
|
}
|