Skip to content

Commit

Permalink
go mod tidy
Browse files Browse the repository at this point in the history
  • Loading branch information
mazrean committed Nov 9, 2024
1 parent 8541948 commit c330cfb
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 2 deletions.
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module github.com/mazrean/formstream

go 1.21.5
toolchain go1.22.5
go 1.22

toolchain go1.23.0

require go.uber.org/mock v0.5.0

Expand Down
78 changes: 78 additions & 0 deletions multipart/processor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package multipart

import (
"bytes"
"errors"
"io"
"mime/multipart"
"strings"
"sync"
)

type processor struct {
*multipart.Reader
valueMap map[string][]string
fileMap map[string][]*FileHeader
}

func newProcessor(r *multipart.Reader) *processor {
return &processor{
Reader: r,
valueMap: make(map[string][]string),
}
}

var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}

func (p *processor) readValue(name string) []string {
if values, ok := p.valueMap[name]; ok {
return values
}

part, err := p.readUntilField(name)
if err != nil {
return nil
}
defer part.Close()

if part == nil {
return nil
}

sb := strings.Builder{}
if _, err := io.Copy(&sb, part); err != nil {
return nil
}

return []string{sb.String()}
}

func (p *processor) readUntilField(name string) (*multipart.Part, error) {
buf, ok := bufPool.Get().(*bytes.Buffer)
if !ok {
buf = new(bytes.Buffer)
}
buf.Reset()

for {
part, err := p.NextPart()
if err != nil {
if errors.Is(err, io.EOF) {
return nil, nil
}
return nil, err
}

if part.FormName() == name {
return part, nil
}

if _, err := buf.ReadFrom(part); err != nil {
return nil, err
}
}
}
48 changes: 48 additions & 0 deletions multipart/reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package multipart

import (
"io"
"mime/multipart"
"net/textproto"
)

type Reader struct {
*multipart.Reader
}

func NewReader(r io.Reader, boundary string) *Reader {
return &Reader{
Reader: multipart.NewReader(r, boundary),
}
}

func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
return &Form{
processor: newProcessor(r.Reader),
}, nil
}

type Form struct {
processor *processor
}

func (f *Form) Value(name string) ([]string, bool) {
return f.processor.readValue(name)

Check failure on line 30 in multipart/reader.go

View workflow job for this annotation

GitHub Actions / Test

not enough return values
}

func (f *Form) File(name string) []*FileHeader

type FileHeader struct {
Filename string
Header textproto.MIMEHeader
Size int64
}

func (fh *FileHeader) Open() (File, error)

type File interface {
io.Reader
io.ReaderAt
io.Seeker
io.Closer
}

0 comments on commit c330cfb

Please sign in to comment.