forked from TrueCloudLab/rclone
rest: implement multipart uploads
This commit is contained in:
parent
edfa1b3a69
commit
45ba4ed594
1 changed files with 73 additions and 20 deletions
67
rest/rest.go
67
rest/rest.go
|
@ -8,6 +8,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -90,6 +91,15 @@ type Opts struct {
|
||||||
Password string // password for Basic Auth
|
Password string // password for Basic Auth
|
||||||
Options []fs.OpenOption
|
Options []fs.OpenOption
|
||||||
IgnoreStatus bool // if set then we don't check error status or parse error body
|
IgnoreStatus bool // if set then we don't check error status or parse error body
|
||||||
|
MultipartMetadataName string // set the following 3 vars
|
||||||
|
MultipartContentName string // and Body and pass in request
|
||||||
|
MultipartFileName string // for multipart upload
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a copy of the options
|
||||||
|
func (o *Opts) Copy() *Opts {
|
||||||
|
newOpts := *o
|
||||||
|
return &newOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeJSON decodes resp.Body into result
|
// DecodeJSON decodes resp.Body into result
|
||||||
|
@ -202,16 +212,53 @@ func (api *Client) Call(opts *Opts) (resp *http.Response, err error) {
|
||||||
//
|
//
|
||||||
// It will return resp if at all possible, even if err is set
|
// It will return resp if at all possible, even if err is set
|
||||||
func (api *Client) CallJSON(opts *Opts, request interface{}, response interface{}) (resp *http.Response, err error) {
|
func (api *Client) CallJSON(opts *Opts, request interface{}, response interface{}) (resp *http.Response, err error) {
|
||||||
// Set the body up as a JSON object if required
|
var requestBody []byte
|
||||||
if opts.Body == nil && request != nil {
|
// Marshal the request if given
|
||||||
body, err := json.Marshal(request)
|
if request != nil {
|
||||||
|
opts = opts.Copy()
|
||||||
|
requestBody, err = json.Marshal(request)
|
||||||
|
opts.ContentType = "application/json"
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var newOpts = *opts
|
// Set the body up as a JSON object if required
|
||||||
newOpts.Body = bytes.NewBuffer(body)
|
if opts.Body == nil {
|
||||||
newOpts.ContentType = "application/json"
|
opts.Body = bytes.NewBuffer(requestBody)
|
||||||
opts = &newOpts
|
}
|
||||||
|
}
|
||||||
|
errChan := make(chan error, 1)
|
||||||
|
isMultipart := opts.MultipartMetadataName != "" && opts.Body != nil && request != nil
|
||||||
|
if isMultipart {
|
||||||
|
bodyReader, bodyWriter := io.Pipe()
|
||||||
|
writer := multipart.NewWriter(bodyWriter)
|
||||||
|
opts.ContentType = writer.FormDataContentType()
|
||||||
|
in := opts.Body
|
||||||
|
opts.Body = bodyReader
|
||||||
|
go func() {
|
||||||
|
defer func() { _ = bodyWriter.Close() }()
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Create the first part
|
||||||
|
err = writer.WriteField(opts.MultipartMetadataName, string(requestBody))
|
||||||
|
if err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the file part
|
||||||
|
part, err := writer.CreateFormFile(opts.MultipartContentName, opts.MultipartFileName)
|
||||||
|
if err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy it in
|
||||||
|
if _, err := io.Copy(part, in); err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errChan <- writer.Close()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
resp, err = api.Call(opts)
|
resp, err = api.Call(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -220,6 +267,12 @@ func (api *Client) CallJSON(opts *Opts, request interface{}, response interface{
|
||||||
if response == nil || opts.NoResponse {
|
if response == nil || opts.NoResponse {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
if isMultipart {
|
||||||
|
err = <-errChan
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
}
|
||||||
err = DecodeJSON(resp, response)
|
err = DecodeJSON(resp, response)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue