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