Source file src/pkg/mime/multipart/formdata.go
1
2
3
4
5 package multipart
6
7 import (
8 "bytes"
9 "errors"
10 "io"
11 "io/ioutil"
12 "net/textproto"
13 "os"
14 )
15
16
17
18
19
20
21
22
23 func (r *Reader) ReadForm(maxMemory int64) (f *Form, err error) {
24 form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
25 defer func() {
26 if err != nil {
27 form.RemoveAll()
28 }
29 }()
30
31 maxValueBytes := int64(10 << 20)
32 for {
33 p, err := r.NextPart()
34 if err == io.EOF {
35 break
36 }
37 if err != nil {
38 return nil, err
39 }
40
41 name := p.FormName()
42 if name == "" {
43 continue
44 }
45 filename := p.FileName()
46
47 var b bytes.Buffer
48
49 if filename == "" {
50
51 n, err := io.CopyN(&b, p, maxValueBytes)
52 if err != nil && err != io.EOF {
53 return nil, err
54 }
55 maxValueBytes -= n
56 if maxValueBytes == 0 {
57 return nil, errors.New("multipart: message too large")
58 }
59 form.Value[name] = append(form.Value[name], b.String())
60 continue
61 }
62
63
64 fh := &FileHeader{
65 Filename: filename,
66 Header: p.Header,
67 }
68 n, err := io.CopyN(&b, p, maxMemory+1)
69 if err != nil && err != io.EOF {
70 return nil, err
71 }
72 if n > maxMemory {
73
74 file, err := ioutil.TempFile("", "multipart-")
75 if err != nil {
76 return nil, err
77 }
78 defer file.Close()
79 _, err = io.Copy(file, io.MultiReader(&b, p))
80 if err != nil {
81 os.Remove(file.Name())
82 return nil, err
83 }
84 fh.tmpfile = file.Name()
85 } else {
86 fh.content = b.Bytes()
87 maxMemory -= n
88 }
89 form.File[name] = append(form.File[name], fh)
90 }
91
92 return form, nil
93 }
94
95
96
97
98
99
100 type Form struct {
101 Value map[string][]string
102 File map[string][]*FileHeader
103 }
104
105
106 func (f *Form) RemoveAll() error {
107 var err error
108 for _, fhs := range f.File {
109 for _, fh := range fhs {
110 if fh.tmpfile != "" {
111 e := os.Remove(fh.tmpfile)
112 if e != nil && err == nil {
113 err = e
114 }
115 }
116 }
117 }
118 return err
119 }
120
121
122 type FileHeader struct {
123 Filename string
124 Header textproto.MIMEHeader
125
126 content []byte
127 tmpfile string
128 }
129
130
131 func (fh *FileHeader) Open() (File, error) {
132 if b := fh.content; b != nil {
133 r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b)))
134 return sectionReadCloser{r}, nil
135 }
136 return os.Open(fh.tmpfile)
137 }
138
139
140
141
142 type File interface {
143 io.Reader
144 io.ReaderAt
145 io.Seeker
146 io.Closer
147 }
148
149
150
151 type sectionReadCloser struct {
152 *io.SectionReader
153 }
154
155 func (rc sectionReadCloser) Close() error {
156 return nil
157 }
View as plain text