Source file src/pkg/mime/multipart/multipart.go
1
2
3
4
5
6 7 8 9 10 11 12
13 package multipart
14
15 import (
16 "bufio"
17 "bytes"
18 "fmt"
19 "io"
20 "io/ioutil"
21 "mime"
22 "net/textproto"
23 )
24
25 var emptyParams = make(map[string]string)
26
27
28 type Part struct {
29
30
31
32
33
34
35
36
37 Header textproto.MIMEHeader
38
39 buffer *bytes.Buffer
40 mr *Reader
41 bytesRead int
42
43 disposition string
44 dispositionParams map[string]string
45
46
47
48
49 r io.Reader
50 }
51
52
53
54 func (p *Part) FormName() string {
55
56
57 if p.dispositionParams == nil {
58 p.parseContentDisposition()
59 }
60 if p.disposition != "form-data" {
61 return ""
62 }
63 return p.dispositionParams["name"]
64 }
65
66
67
68 func (p *Part) FileName() string {
69 if p.dispositionParams == nil {
70 p.parseContentDisposition()
71 }
72 return p.dispositionParams["filename"]
73 }
74
75 func (p *Part) parseContentDisposition() {
76 v := p.Header.Get("Content-Disposition")
77 var err error
78 p.disposition, p.dispositionParams, err = mime.ParseMediaType(v)
79 if err != nil {
80 p.dispositionParams = emptyParams
81 }
82 }
83
84
85
86 func NewReader(reader io.Reader, boundary string) *Reader {
87 b := []byte("\r\n--" + boundary + "--")
88 return &Reader{
89 bufReader: bufio.NewReader(reader),
90
91 nl: b[:2],
92 nlDashBoundary: b[:len(b)-2],
93 dashBoundaryDash: b[2:],
94 dashBoundary: b[2 : len(b)-2],
95 }
96 }
97
98 func newPart(mr *Reader) (*Part, error) {
99 bp := &Part{
100 Header: make(map[string][]string),
101 mr: mr,
102 buffer: new(bytes.Buffer),
103 }
104 if err := bp.populateHeaders(); err != nil {
105 return nil, err
106 }
107 bp.r = partReader{bp}
108 const cte = "Content-Transfer-Encoding"
109 if bp.Header.Get(cte) == "quoted-printable" {
110 bp.Header.Del(cte)
111 bp.r = newQuotedPrintableReader(bp.r)
112 }
113 return bp, nil
114 }
115
116 func (bp *Part) populateHeaders() error {
117 r := textproto.NewReader(bp.mr.bufReader)
118 header, err := r.ReadMIMEHeader()
119 if err == nil {
120 bp.Header = header
121 }
122 return err
123 }
124
125
126
127 func (p *Part) Read(d []byte) (n int, err error) {
128 return p.r.Read(d)
129 }
130
131
132
133 type partReader struct {
134 p *Part
135 }
136
137 func (pr partReader) Read(d []byte) (n int, err error) {
138 p := pr.p
139 defer func() {
140 p.bytesRead += n
141 }()
142 if p.buffer.Len() >= len(d) {
143
144
145 return p.buffer.Read(d)
146 }
147 peek, err := p.mr.bufReader.Peek(4096)
148
149
150
151
152
153
154 if p.bytesRead == 0 && p.mr.peekBufferIsEmptyPart(peek) {
155 return 0, io.EOF
156 }
157 unexpectedEOF := err == io.EOF
158 if err != nil && !unexpectedEOF {
159 return 0, fmt.Errorf("multipart: Part Read: %v", err)
160 }
161 if peek == nil {
162 panic("nil peek buf")
163 }
164
165
166
167
168
169 nCopy := 0
170 foundBoundary := false
171 if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
172 nCopy = idx
173 foundBoundary = true
174 } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
175 nCopy = safeCount
176 } else if unexpectedEOF {
177
178
179
180 return 0, io.ErrUnexpectedEOF
181 }
182 if nCopy > 0 {
183 if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
184 return 0, err
185 }
186 }
187 n, err = p.buffer.Read(d)
188 if err == io.EOF && !foundBoundary {
189
190
191 err = nil
192 }
193 return
194 }
195
196 func (p *Part) Close() error {
197 io.Copy(ioutil.Discard, p)
198 return nil
199 }
200
201
202
203
204 type Reader struct {
205 bufReader *bufio.Reader
206
207 currentPart *Part
208 partsRead int
209
210 nl []byte
211 nlDashBoundary []byte
212 dashBoundaryDash []byte
213 dashBoundary []byte
214 }
215
216
217
218 func (r *Reader) NextPart() (*Part, error) {
219 if r.currentPart != nil {
220 r.currentPart.Close()
221 }
222
223 expectNewPart := false
224 for {
225 line, err := r.bufReader.ReadSlice('\n')
226 if err == io.EOF && r.isFinalBoundary(line) {
227
228
229
230
231
232 return nil, io.EOF
233 }
234 if err != nil {
235 return nil, fmt.Errorf("multipart: NextPart: %v", err)
236 }
237
238 if r.isBoundaryDelimiterLine(line) {
239 r.partsRead++
240 bp, err := newPart(r)
241 if err != nil {
242 return nil, err
243 }
244 r.currentPart = bp
245 return bp, nil
246 }
247
248 if r.isFinalBoundary(line) {
249
250 return nil, io.EOF
251 }
252
253 if expectNewPart {
254 return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
255 }
256
257 if r.partsRead == 0 {
258
259 continue
260 }
261
262
263
264
265
266 if bytes.Equal(line, r.nl) {
267 expectNewPart = true
268 continue
269 }
270
271 return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
272 }
273 }
274
275
276
277
278 func (mr *Reader) isFinalBoundary(line []byte) bool {
279 if !bytes.HasPrefix(line, mr.dashBoundaryDash) {
280 return false
281 }
282 rest := line[len(mr.dashBoundaryDash):]
283 rest = skipLWSPChar(rest)
284 return len(rest) == 0 || bytes.Equal(rest, mr.nl)
285 }
286
287 func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
288
289
290
291
292
293
294 if !bytes.HasPrefix(line, mr.dashBoundary) {
295 return false
296 }
297 rest := line[len(mr.dashBoundary):]
298 rest = skipLWSPChar(rest)
299
300
301
302
303 if mr.partsRead == 0 && len(rest) == 1 && rest[0] == '\n' {
304 mr.nl = mr.nl[1:]
305 mr.nlDashBoundary = mr.nlDashBoundary[1:]
306 }
307 return bytes.Equal(rest, mr.nl)
308 }
309
310
311
312
313
314
315
316
317
318
319
320 func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
321
322
323 if bytes.HasPrefix(peek, mr.dashBoundaryDash) {
324 rest := peek[len(mr.dashBoundaryDash):]
325 rest = skipLWSPChar(rest)
326 return bytes.HasPrefix(rest, mr.nl) || len(rest) == 0
327 }
328 if !bytes.HasPrefix(peek, mr.dashBoundary) {
329 return false
330 }
331
332 rest := peek[len(mr.dashBoundary):]
333 rest = skipLWSPChar(rest)
334 return bytes.HasPrefix(rest, mr.nl)
335 }
336
337
338
339
340 func skipLWSPChar(b []byte) []byte {
341 for len(b) > 0 && (b[0] == ' ' || b[0] == '\t') {
342 b = b[1:]
343 }
344 return b
345 }
View as plain text