1
2
3
4
5
6
13 package multipart
14
15 import (
16 "bufio"
17 "bytes"
18 "fmt"
19 "io"
20 "mime"
21 "mime/quotedprintable"
22 "net/textproto"
23 "path/filepath"
24 "strings"
25 )
26
27 var emptyParams = make(map[string]string)
28
29
30
31
32 const peekBufferSize = 4096
33
34
35 type Part struct {
36
37
38
39 Header textproto.MIMEHeader
40
41 mr *Reader
42
43 disposition string
44 dispositionParams map[string]string
45
46
47
48
49 r io.Reader
50
51 n int
52 total int64
53 err error
54 readErr error
55 }
56
57
58
59 func (p *Part) FormName() string {
60
61
62 if p.dispositionParams == nil {
63 p.parseContentDisposition()
64 }
65 if p.disposition != "form-data" {
66 return ""
67 }
68 return p.dispositionParams["name"]
69 }
70
71
72
73
74 func (p *Part) FileName() string {
75 if p.dispositionParams == nil {
76 p.parseContentDisposition()
77 }
78 filename := p.dispositionParams["filename"]
79 if filename == "" {
80 return ""
81 }
82
83
84 return filepath.Base(filename)
85 }
86
87 func (p *Part) parseContentDisposition() {
88 v := p.Header.Get("Content-Disposition")
89 var err error
90 p.disposition, p.dispositionParams, err = mime.ParseMediaType(v)
91 if err != nil {
92 p.dispositionParams = emptyParams
93 }
94 }
95
96
97
98
99
100
101
102 func NewReader(r io.Reader, boundary string) *Reader {
103 b := []byte("\r\n--" + boundary + "--")
104 return &Reader{
105 bufReader: bufio.NewReaderSize(&stickyErrorReader{r: r}, peekBufferSize),
106 nl: b[:2],
107 nlDashBoundary: b[:len(b)-2],
108 dashBoundaryDash: b[2:],
109 dashBoundary: b[2 : len(b)-2],
110 }
111 }
112
113
114
115
116
117
118 type stickyErrorReader struct {
119 r io.Reader
120 err error
121 }
122
123 func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
124 if r.err != nil {
125 return 0, r.err
126 }
127 n, r.err = r.r.Read(p)
128 return n, r.err
129 }
130
131 func newPart(mr *Reader, rawPart bool) (*Part, error) {
132 bp := &Part{
133 Header: make(map[string][]string),
134 mr: mr,
135 }
136 if err := bp.populateHeaders(); err != nil {
137 return nil, err
138 }
139 bp.r = partReader{bp}
140
141
142 if !rawPart {
143 const cte = "Content-Transfer-Encoding"
144 if strings.EqualFold(bp.Header.Get(cte), "quoted-printable") {
145 bp.Header.Del(cte)
146 bp.r = quotedprintable.NewReader(bp.r)
147 }
148 }
149 return bp, nil
150 }
151
152 func (p *Part) populateHeaders() error {
153 r := textproto.NewReader(p.mr.bufReader)
154 header, err := r.ReadMIMEHeader()
155 if err == nil {
156 p.Header = header
157 }
158 return err
159 }
160
161
162
163 func (p *Part) Read(d []byte) (n int, err error) {
164 return p.r.Read(d)
165 }
166
167
168
169 type partReader struct {
170 p *Part
171 }
172
173 func (pr partReader) Read(d []byte) (int, error) {
174 p := pr.p
175 br := p.mr.bufReader
176
177
178
179 for p.n == 0 && p.err == nil {
180 peek, _ := br.Peek(br.Buffered())
181 p.n, p.err = scanUntilBoundary(peek, p.mr.dashBoundary, p.mr.nlDashBoundary, p.total, p.readErr)
182 if p.n == 0 && p.err == nil {
183
184 _, p.readErr = br.Peek(len(peek) + 1)
185 if p.readErr == io.EOF {
186 p.readErr = io.ErrUnexpectedEOF
187 }
188 }
189 }
190
191
192 if p.n == 0 {
193 return 0, p.err
194 }
195 n := len(d)
196 if n > p.n {
197 n = p.n
198 }
199 n, _ = br.Read(d[:n])
200 p.total += int64(n)
201 p.n -= n
202 if p.n == 0 {
203 return n, p.err
204 }
205 return n, nil
206 }
207
208
209
210
211
212
213
214
215
216
217
218 func scanUntilBoundary(buf, dashBoundary, nlDashBoundary []byte, total int64, readErr error) (int, error) {
219 if total == 0 {
220
221 if bytes.HasPrefix(buf, dashBoundary) {
222 switch matchAfterPrefix(buf, dashBoundary, readErr) {
223 case -1:
224 return len(dashBoundary), nil
225 case 0:
226 return 0, nil
227 case +1:
228 return 0, io.EOF
229 }
230 }
231 if bytes.HasPrefix(dashBoundary, buf) {
232 return 0, readErr
233 }
234 }
235
236
237 if i := bytes.Index(buf, nlDashBoundary); i >= 0 {
238 switch matchAfterPrefix(buf[i:], nlDashBoundary, readErr) {
239 case -1:
240 return i + len(nlDashBoundary), nil
241 case 0:
242 return i, nil
243 case +1:
244 return i, io.EOF
245 }
246 }
247 if bytes.HasPrefix(nlDashBoundary, buf) {
248 return 0, readErr
249 }
250
251
252
253
254
255 i := bytes.LastIndexByte(buf, nlDashBoundary[0])
256 if i >= 0 && bytes.HasPrefix(nlDashBoundary, buf[i:]) {
257 return i, nil
258 }
259 return len(buf), readErr
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274 func matchAfterPrefix(buf, prefix []byte, readErr error) int {
275 if len(buf) == len(prefix) {
276 if readErr != nil {
277 return +1
278 }
279 return 0
280 }
281 c := buf[len(prefix)]
282
283 if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
284 return +1
285 }
286
287
288 if c == '-' {
289 if len(buf) == len(prefix)+1 {
290 if readErr != nil {
291
292 return -1
293 }
294 return 0
295 }
296 if buf[len(prefix)+1] == '-' {
297 return +1
298 }
299 }
300
301 return -1
302 }
303
304 func (p *Part) Close() error {
305 io.Copy(io.Discard, p)
306 return nil
307 }
308
309
310
311
312 type Reader struct {
313 bufReader *bufio.Reader
314
315 currentPart *Part
316 partsRead int
317
318 nl []byte
319 nlDashBoundary []byte
320 dashBoundaryDash []byte
321 dashBoundary []byte
322 }
323
324
325
326
327
328
329
330 func (r *Reader) NextPart() (*Part, error) {
331 return r.nextPart(false)
332 }
333
334
335
336
337
338
339 func (r *Reader) NextRawPart() (*Part, error) {
340 return r.nextPart(true)
341 }
342
343 func (r *Reader) nextPart(rawPart bool) (*Part, error) {
344 if r.currentPart != nil {
345 r.currentPart.Close()
346 }
347 if string(r.dashBoundary) == "--" {
348 return nil, fmt.Errorf("multipart: boundary is empty")
349 }
350 expectNewPart := false
351 for {
352 line, err := r.bufReader.ReadSlice('\n')
353
354 if err == io.EOF && r.isFinalBoundary(line) {
355
356
357
358
359
360 return nil, io.EOF
361 }
362 if err != nil {
363 return nil, fmt.Errorf("multipart: NextPart: %v", err)
364 }
365
366 if r.isBoundaryDelimiterLine(line) {
367 r.partsRead++
368 bp, err := newPart(r, rawPart)
369 if err != nil {
370 return nil, err
371 }
372 r.currentPart = bp
373 return bp, nil
374 }
375
376 if r.isFinalBoundary(line) {
377
378 return nil, io.EOF
379 }
380
381 if expectNewPart {
382 return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
383 }
384
385 if r.partsRead == 0 {
386
387 continue
388 }
389
390
391
392
393
394 if bytes.Equal(line, r.nl) {
395 expectNewPart = true
396 continue
397 }
398
399 return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
400 }
401 }
402
403
404
405
406 func (r *Reader) isFinalBoundary(line []byte) bool {
407 if !bytes.HasPrefix(line, r.dashBoundaryDash) {
408 return false
409 }
410 rest := line[len(r.dashBoundaryDash):]
411 rest = skipLWSPChar(rest)
412 return len(rest) == 0 || bytes.Equal(rest, r.nl)
413 }
414
415 func (r *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
416
417
418
419
420
421
422 if !bytes.HasPrefix(line, r.dashBoundary) {
423 return false
424 }
425 rest := line[len(r.dashBoundary):]
426 rest = skipLWSPChar(rest)
427
428
429
430
431 if r.partsRead == 0 && len(rest) == 1 && rest[0] == '\n' {
432 r.nl = r.nl[1:]
433 r.nlDashBoundary = r.nlDashBoundary[1:]
434 }
435 return bytes.Equal(rest, r.nl)
436 }
437
438
439
440
441
442 func skipLWSPChar(b []byte) []byte {
443 for len(b) > 0 && (b[0] == ' ' || b[0] == '\t') {
444 b = b[1:]
445 }
446 return b
447 }
448
View as plain text