From 51bfe06f1a713926ab218ef26628d5a656cb5529 Mon Sep 17 00:00:00 2001 From: Matt Bell <mappum@gmail.com> Date: Sun, 16 Nov 2014 22:07:01 -0800 Subject: [PATCH] commands/http: Support recursive multipart in MultiFileReader --- commands/http/client.go | 2 +- commands/http/multifilereader.go | 43 ++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/commands/http/client.go b/commands/http/client.go index 3fe9c23a6..3dcf6e9c3 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -50,7 +50,7 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { var fileReader *MultiFileReader if req.Files() != nil { - fileReader = NewMultiFileReader(req.Files()) + fileReader = NewMultiFileReader(req.Files(), true) } path := strings.Join(req.Path(), "/") diff --git a/commands/http/multifilereader.go b/commands/http/multifilereader.go index c6c74b048..d652db7cb 100644 --- a/commands/http/multifilereader.go +++ b/commands/http/multifilereader.go @@ -2,8 +2,10 @@ package http import ( "bytes" + "fmt" "io" "mime/multipart" + "net/textproto" cmds "github.com/jbenet/go-ipfs/commands" ) @@ -12,15 +14,20 @@ type MultiFileReader struct { io.Reader files cmds.File - currentFile cmds.File + currentFile io.Reader buf bytes.Buffer mpWriter *multipart.Writer closed bool + + // if true, the data will be type 'multipart/form-data' + // if false, the data will be type 'multipart/mixed' + form bool } -func NewMultiFileReader(file cmds.File) *MultiFileReader { +func NewMultiFileReader(file cmds.File, form bool) *MultiFileReader { mfr := &MultiFileReader{ files: file, + form: form, } mfr.mpWriter = multipart.NewWriter(&mfr.buf) @@ -35,16 +42,42 @@ func (mfr *MultiFileReader) Read(buf []byte) (written int, err error) { // if the current file isn't set, advance to the next file if mfr.currentFile == nil { - mfr.currentFile, err = mfr.files.NextFile() - if err == io.EOF || (err == nil && mfr.currentFile == nil) { + file, err := mfr.files.NextFile() + if err == io.EOF || (err == nil && file == nil) { mfr.mpWriter.Close() mfr.closed = true } else if err != nil { return 0, err } + // handle starting a new file part if !mfr.closed { - _, err := mfr.mpWriter.CreateFormFile("file", mfr.currentFile.FileName()) + if file.IsDirectory() { + // if file is a directory, create a multifilereader from it + // (using 'multipart/mixed') + mfr.currentFile = NewMultiFileReader(file, false) + } else { + // otherwise, use the file as a reader to read its contents + mfr.currentFile = file + } + + // write the boundary and headers + header := make(textproto.MIMEHeader) + if mfr.form { + contentDisposition := fmt.Sprintf("form-data; name=\"file\"; filename=\"%s\"", file.FileName()) + header.Set("Content-Disposition", contentDisposition) + } else { + header.Set("Content-Disposition", fmt.Sprintf("file; filename=\"%s\"", file.FileName())) + } + + if file.IsDirectory() { + boundary := mfr.currentFile.(*MultiFileReader).Boundary() + header.Set("Content-Type", fmt.Sprintf("multipart/mixed; boundary=%s", boundary)) + } else { + header.Set("Content-Type", "application/octet-stream") + } + + _, err := mfr.mpWriter.CreatePart(header) if err != nil { return 0, err } -- GitLab