Implement Backblaze B2 - fixes #224
This commit is contained in:
+50
-11
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/ncw/rclone/fs"
|
||||
@@ -16,27 +17,48 @@ type Client struct {
|
||||
c *http.Client
|
||||
rootURL string
|
||||
errorHandler func(resp *http.Response) error
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
// NewClient takes an oauth http.Client and makes a new api instance
|
||||
func NewClient(c *http.Client, rootURL string) *Client {
|
||||
return &Client{
|
||||
func NewClient(c *http.Client) *Client {
|
||||
api := &Client{
|
||||
c: c,
|
||||
rootURL: rootURL,
|
||||
errorHandler: defaultErrorHandler,
|
||||
headers: make(map[string]string),
|
||||
}
|
||||
api.SetHeader("User-Agent", fs.UserAgent)
|
||||
return api
|
||||
}
|
||||
|
||||
// defaultErrorHandler doesn't attempt to parse the http body
|
||||
// defaultErrorHandler doesn't attempt to parse the http body, just
|
||||
// returns it in the error message
|
||||
func defaultErrorHandler(resp *http.Response) (err error) {
|
||||
defer fs.CheckClose(resp.Body, &err)
|
||||
return fmt.Errorf("HTTP error %v (%v) returned", resp.StatusCode, resp.Status)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("HTTP error %v (%v) returned body: %q", resp.StatusCode, resp.Status, body)
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the handler to decode an error response when
|
||||
// the HTTP status code is not 2xx. The handler should close resp.Body.
|
||||
func (api *Client) SetErrorHandler(fn func(resp *http.Response) error) {
|
||||
func (api *Client) SetErrorHandler(fn func(resp *http.Response) error) *Client {
|
||||
api.errorHandler = fn
|
||||
return api
|
||||
}
|
||||
|
||||
// SetRoot sets the default root URL
|
||||
func (api *Client) SetRoot(RootURL string) *Client {
|
||||
api.rootURL = RootURL
|
||||
return api
|
||||
}
|
||||
|
||||
// SetHeader sets a header for all requests
|
||||
func (api *Client) SetHeader(key, value string) *Client {
|
||||
api.headers[key] = value
|
||||
return api
|
||||
}
|
||||
|
||||
// Opts contains parameters for Call, CallJSON etc
|
||||
@@ -50,6 +72,8 @@ type Opts struct {
|
||||
ContentLength *int64
|
||||
ContentRange string
|
||||
ExtraHeaders map[string]string
|
||||
UserName string // username for Basic Auth
|
||||
Password string // password for Basic Auth
|
||||
}
|
||||
|
||||
// DecodeJSON decodes resp.Body into result
|
||||
@@ -72,27 +96,42 @@ func (api *Client) Call(opts *Opts) (resp *http.Response, err error) {
|
||||
if opts.Absolute {
|
||||
url = opts.Path
|
||||
} else {
|
||||
if api.rootURL == "" {
|
||||
return nil, fmt.Errorf("RootURL not set")
|
||||
}
|
||||
url = api.rootURL + opts.Path
|
||||
}
|
||||
req, err := http.NewRequest(opts.Method, url, opts.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
headers := make(map[string]string)
|
||||
// Set default headers
|
||||
for k, v := range api.headers {
|
||||
headers[k] = v
|
||||
}
|
||||
if opts.ContentType != "" {
|
||||
req.Header.Add("Content-Type", opts.ContentType)
|
||||
headers["Content-Type"] = opts.ContentType
|
||||
}
|
||||
if opts.ContentLength != nil {
|
||||
req.ContentLength = *opts.ContentLength
|
||||
}
|
||||
if opts.ContentRange != "" {
|
||||
req.Header.Add("Content-Range", opts.ContentRange)
|
||||
headers["Content-Range"] = opts.ContentRange
|
||||
}
|
||||
// Set any extra headers
|
||||
if opts.ExtraHeaders != nil {
|
||||
for k, v := range opts.ExtraHeaders {
|
||||
req.Header.Add(k, v)
|
||||
headers[k] = v
|
||||
}
|
||||
}
|
||||
req.Header.Add("User-Agent", fs.UserAgent)
|
||||
// Now set the headers
|
||||
for k, v := range headers {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if opts.UserName != "" || opts.Password != "" {
|
||||
req.SetBasicAuth(opts.UserName, opts.Password)
|
||||
}
|
||||
resp, err = api.c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -127,7 +166,7 @@ func (api *Client) CallJSON(opts *Opts, request interface{}, response interface{
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
if opts.NoResponse {
|
||||
if response == nil || opts.NoResponse {
|
||||
return resp, nil
|
||||
}
|
||||
err = DecodeJSON(resp, response)
|
||||
|
||||
Reference in New Issue
Block a user