aicra/internal/multipart/reader.go

99 lines
1.8 KiB
Go
Raw Permalink Normal View History

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 {
// io.Reader used for reading multipart components reading.
2019-05-01 19:30:16 +00:00
reader *bufio.Reader
// boundary used to separate multipart components.
2019-05-01 19:30:16 +00:00
boundary string
// data will contain parsed components.
2019-05-01 19:30:16 +00:00
Data map[string]*Component
}
// NewReader creates a new multipart reader for a reader and a boundary.
func NewReader(r io.Reader, boundary string) (*Reader, error) {
2018-09-25 19:22:25 +00:00
reader := &Reader{
reader: nil,
boundary: fmt.Sprintf("--%s", boundary),
2018-09-25 19:22:25 +00:00
Data: make(map[string]*Component),
}
// 1. Create reader
dst, ok := r.(*bufio.Reader)
2018-09-25 19:22:25 +00:00
if !ok {
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
}
// 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 {
return errMissingDataName
2018-09-25 19:22:25 +00:00
}
if _, nameUsed := reader.Data[name]; nameUsed {
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
}
}
}
// 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
}