@cryptotaxi247 / kubo / commits / 51bfe06f1

commands/http: Support recursive multipart in MultiFileReader

Matt Bell committed Nov 16, 2014 at 22:07 UTC 51bfe06f1a713926ab218ef26628d5a656cb5529
2 files changed +39 -6
commands/http/client.go
+1 -1
@@ -50,7 +50,7 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
50
51 var fileReader *MultiFileReader
52 if req.Files() != nil {
53 - fileReader = NewMultiFileReader(req.Files())
53 + fileReader = NewMultiFileReader(req.Files(), true)
54 }
55
56 path := strings.Join(req.Path(), "/")
commands/http/multifilereader.go
+38 -5
@@ -2,8 +2,10 @@ package http
2
3 import (
4 "bytes"
5 + "fmt"
6 "io"
7 "mime/multipart"
8 + "net/textproto"
9
10 cmds "github.com/jbenet/go-ipfs/commands"
11 )
@@ -12,15 +14,20 @@ type MultiFileReader struct {
14 io.Reader
15
16 files cmds.File
15 - currentFile cmds.File
17 + currentFile io.Reader
18 buf bytes.Buffer
19 mpWriter *multipart.Writer
20 closed bool
21 +
22 + // if true, the data will be type 'multipart/form-data'
23 + // if false, the data will be type 'multipart/mixed'
24 + form bool
25 }
26
21 -func NewMultiFileReader(file cmds.File) *MultiFileReader {
27 +func NewMultiFileReader(file cmds.File, form bool) *MultiFileReader {
28 mfr := &MultiFileReader{
29 files: file,
30 + form: form,
31 }
32 mfr.mpWriter = multipart.NewWriter(&mfr.buf)
33
@@ -35,16 +42,42 @@ func (mfr *MultiFileReader) Read(buf []byte) (written int, err error) {
42
43 // if the current file isn't set, advance to the next file
44 if mfr.currentFile == nil {
38 - mfr.currentFile, err = mfr.files.NextFile()
39 - if err == io.EOF || (err == nil && mfr.currentFile == nil) {
45 + file, err := mfr.files.NextFile()
46 + if err == io.EOF || (err == nil && file == nil) {
47 mfr.mpWriter.Close()
48 mfr.closed = true
49 } else if err != nil {
50 return 0, err
51 }
52
53 + // handle starting a new file part
54 if !mfr.closed {
47 - _, err := mfr.mpWriter.CreateFormFile("file", mfr.currentFile.FileName())
55 + if file.IsDirectory() {
56 + // if file is a directory, create a multifilereader from it
57 + // (using 'multipart/mixed')
58 + mfr.currentFile = NewMultiFileReader(file, false)
59 + } else {
60 + // otherwise, use the file as a reader to read its contents
61 + mfr.currentFile = file
62 + }
63 +
64 + // write the boundary and headers
65 + header := make(textproto.MIMEHeader)
66 + if mfr.form {
67 + contentDisposition := fmt.Sprintf("form-data; name=\"file\"; filename=\"%s\"", file.FileName())
68 + header.Set("Content-Disposition", contentDisposition)
69 + } else {
70 + header.Set("Content-Disposition", fmt.Sprintf("file; filename=\"%s\"", file.FileName()))
71 + }
72 +
73 + if file.IsDirectory() {
74 + boundary := mfr.currentFile.(*MultiFileReader).Boundary()
75 + header.Set("Content-Type", fmt.Sprintf("multipart/mixed; boundary=%s", boundary))
76 + } else {
77 + header.Set("Content-Type", "application/octet-stream")
78 + }
79 +
80 + _, err := mfr.mpWriter.CreatePart(header)
81 if err != nil {
82 return 0, err
83 }