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 (bp *Part) populateHeaders() error {
153 r := textproto.NewReader(bp.mr.bufReader)
154 header, err := r.ReadMIMEHeader()
155 if err == nil {
156 bp.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 func matchAfterPrefix(buf, prefix []byte, readErr error) int {
274 if len(buf) == len(prefix) {
275 if readErr != nil {
276 return +1
277 }
278 return 0
279 }
280 c := buf[len(prefix)]
281 if c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '-' {
282 return +1
283 }
284 return -1
285 }
286
287 func (p *Part) Close() error {
288 io.Copy(io.Discard, p)
289 return nil
290 }
291
292
293
294
295 type Reader struct {
296 bufReader *bufio.Reader
297
298 currentPart *Part
299 partsRead int
300
301 nl []byte
302 nlDashBoundary []byte
303 dashBoundaryDash []byte
304 dashBoundary []byte
305 }
306
307
308
309
310
311
312
313 func (r *Reader) NextPart() (*Part, error) {
314 return r.nextPart(false)
315 }
316
317
318
319
320
321
322 func (r *Reader) NextRawPart() (*Part, error) {
323 return r.nextPart(true)
324 }
325
326 func (r *Reader) nextPart(rawPart bool) (*Part, error) {
327 if r.currentPart != nil {
328 r.currentPart.Close()
329 }
330 if string(r.dashBoundary) == "--" {
331 return nil, fmt.Errorf("multipart: boundary is empty")
332 }
333 expectNewPart := false
334 for {
335 line, err := r.bufReader.ReadSlice('\n')
336
337 if err == io.EOF && r.isFinalBoundary(line) {
338
339
340
341
342
343 return nil, io.EOF
344 }
345 if err != nil {
346 return nil, fmt.Errorf("multipart: NextPart: %v", err)
347 }
348
349 if r.isBoundaryDelimiterLine(line) {
350 r.partsRead++
351 bp, err := newPart(r, rawPart)
352 if err != nil {
353 return nil, err
354 }
355 r.currentPart = bp
356 return bp, nil
357 }
358
359 if r.isFinalBoundary(line) {
360
361 return nil, io.EOF
362 }
363
364 if expectNewPart {
365 return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
366 }
367
368 if r.partsRead == 0 {
369
370 continue
371 }
372
373
374
375
376
377 if bytes.Equal(line, r.nl) {
378 expectNewPart = true
379 continue
380 }
381
382 return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
383 }
384 }
385
386
387
388
389 func (mr *Reader) isFinalBoundary(line []byte) bool {
390 if !bytes.HasPrefix(line, mr.dashBoundaryDash) {
391 return false
392 }
393 rest := line[len(mr.dashBoundaryDash):]
394 rest = skipLWSPChar(rest)
395 return len(rest) == 0 || bytes.Equal(rest, mr.nl)
396 }
397
398 func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
399
400
401
402
403
404
405 if !bytes.HasPrefix(line, mr.dashBoundary) {
406 return false
407 }
408 rest := line[len(mr.dashBoundary):]
409 rest = skipLWSPChar(rest)
410
411
412
413
414 if mr.partsRead == 0 && len(rest) == 1 && rest[0] == '\n' {
415 mr.nl = mr.nl[1:]
416 mr.nlDashBoundary = mr.nlDashBoundary[1:]
417 }
418 return bytes.Equal(rest, mr.nl)
419 }
420
421
422
423
424 func skipLWSPChar(b []byte) []byte {
425 for len(b) > 0 && (b[0] == ' ' || b[0] == '\t') {
426 b = b[1:]
427 }
428 return b
429 }
430
View as plain text