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
}