forked from TrueCloudLab/rclone
vendor: add github.com/koofr/go-koofrclient
* added koofr client SDK dep for koofr backend
This commit is contained in:
parent
27714e29c3
commit
1d14e30383
22 changed files with 1461 additions and 0 deletions
11
vendor/github.com/koofr/go-httpclient/.gitignore
generated
vendored
Normal file
11
vendor/github.com/koofr/go-httpclient/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
/bin
|
||||
/pkg
|
||||
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# developer specific
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
21
vendor/github.com/koofr/go-httpclient/LICENSE
generated
vendored
Normal file
21
vendor/github.com/koofr/go-httpclient/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Koofr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
15
vendor/github.com/koofr/go-httpclient/README.md
generated
vendored
Normal file
15
vendor/github.com/koofr/go-httpclient/README.md
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
go-httpclient
|
||||
=============
|
||||
|
||||
Go HTTP client.
|
||||
|
||||
[](https://godoc.org/github.com/koofr/go-httpclient)
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/koofr/go-httpclient
|
||||
|
||||
## Testing
|
||||
|
||||
go get -t
|
||||
go test
|
38
vendor/github.com/koofr/go-httpclient/errors.go
generated
vendored
Normal file
38
vendor/github.com/koofr/go-httpclient/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type InvalidStatusError struct {
|
||||
Expected []int
|
||||
Got int
|
||||
Headers http.Header
|
||||
Content string
|
||||
}
|
||||
|
||||
func (e InvalidStatusError) Error() string {
|
||||
return fmt.Sprintf("Invalid response status! Got %d, expected %d; headers: %s, content: %s", e.Got, e.Expected, e.Headers, e.Content)
|
||||
}
|
||||
|
||||
func IsInvalidStatusError(err error) (invalidStatusError *InvalidStatusError, ok bool) {
|
||||
if ise, ok := err.(InvalidStatusError); ok {
|
||||
return &ise, true
|
||||
} else if ise, ok := err.(*InvalidStatusError); ok {
|
||||
return ise, true
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func IsInvalidStatusCode(err error, statusCode int) bool {
|
||||
if ise, ok := IsInvalidStatusError(err); ok {
|
||||
return ise.Got == statusCode
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var RateLimitTimeoutError = errors.New("HTTPClient rate limit timeout")
|
351
vendor/github.com/koofr/go-httpclient/httpclient.go
generated
vendored
Normal file
351
vendor/github.com/koofr/go-httpclient/httpclient.go
generated
vendored
Normal file
|
@ -0,0 +1,351 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var XmlHeaderBytes []byte = []byte(xml.Header)
|
||||
|
||||
type HTTPClient struct {
|
||||
BaseURL *url.URL
|
||||
Headers http.Header
|
||||
Client *http.Client
|
||||
PostHooks map[int]func(*http.Request, *http.Response) error
|
||||
rateLimited bool
|
||||
rateLimitChan chan struct{}
|
||||
rateLimitTimeout time.Duration
|
||||
}
|
||||
|
||||
func New() (httpClient *HTTPClient) {
|
||||
return &HTTPClient{
|
||||
Client: HttpClient,
|
||||
Headers: make(http.Header),
|
||||
PostHooks: make(map[int]func(*http.Request, *http.Response) error),
|
||||
}
|
||||
}
|
||||
|
||||
func Insecure() (httpClient *HTTPClient) {
|
||||
httpClient = New()
|
||||
httpClient.Client = InsecureHttpClient
|
||||
return httpClient
|
||||
}
|
||||
|
||||
var DefaultClient = New()
|
||||
|
||||
func (c *HTTPClient) SetPostHook(onStatus int, hook func(*http.Request, *http.Response) error) {
|
||||
c.PostHooks[onStatus] = hook
|
||||
}
|
||||
|
||||
func (c *HTTPClient) SetRateLimit(limit int, timeout time.Duration) {
|
||||
c.rateLimited = true
|
||||
c.rateLimitChan = make(chan struct{}, limit)
|
||||
|
||||
for i := 0; i < limit; i++ {
|
||||
c.rateLimitChan <- struct{}{}
|
||||
}
|
||||
|
||||
c.rateLimitTimeout = timeout
|
||||
}
|
||||
|
||||
func (c *HTTPClient) buildURL(req *RequestData) *url.URL {
|
||||
bu := c.BaseURL
|
||||
|
||||
rpath := req.Path
|
||||
|
||||
if strings.HasSuffix(bu.Path, "/") && strings.HasPrefix(rpath, "/") {
|
||||
rpath = rpath[1:]
|
||||
}
|
||||
|
||||
opaque := EscapePath(bu.Path + rpath)
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: bu.Scheme,
|
||||
Host: bu.Host,
|
||||
Opaque: opaque,
|
||||
}
|
||||
|
||||
if req.Params != nil {
|
||||
u.RawQuery = req.Params.Encode()
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func (c *HTTPClient) setHeaders(req *RequestData, httpReq *http.Request) {
|
||||
switch req.RespEncoding {
|
||||
case EncodingJSON:
|
||||
httpReq.Header.Set("Accept", "application/json")
|
||||
case EncodingXML:
|
||||
httpReq.Header.Set("Accept", "application/xml")
|
||||
}
|
||||
|
||||
if c.Headers != nil {
|
||||
for key, values := range c.Headers {
|
||||
for _, value := range values {
|
||||
httpReq.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if req.Headers != nil {
|
||||
for key, values := range req.Headers {
|
||||
for _, value := range values {
|
||||
httpReq.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HTTPClient) checkStatus(req *RequestData, response *http.Response) (err error) {
|
||||
if req.ExpectedStatus != nil {
|
||||
statusOk := false
|
||||
|
||||
for _, status := range req.ExpectedStatus {
|
||||
if response.StatusCode == status {
|
||||
statusOk = true
|
||||
}
|
||||
}
|
||||
|
||||
if !statusOk {
|
||||
lr := io.LimitReader(response.Body, 10*1024)
|
||||
contentBytes, _ := ioutil.ReadAll(lr)
|
||||
content := string(contentBytes)
|
||||
|
||||
err = InvalidStatusError{
|
||||
Expected: req.ExpectedStatus,
|
||||
Got: response.StatusCode,
|
||||
Headers: response.Header,
|
||||
Content: content,
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *HTTPClient) unmarshalResponse(req *RequestData, response *http.Response) (err error) {
|
||||
var buf []byte
|
||||
|
||||
switch req.RespEncoding {
|
||||
case EncodingJSON:
|
||||
defer response.Body.Close()
|
||||
|
||||
if buf, err = ioutil.ReadAll(response.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(buf, req.RespValue)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case EncodingXML:
|
||||
defer response.Body.Close()
|
||||
|
||||
if buf, err = ioutil.ReadAll(response.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = xml.Unmarshal(buf, req.RespValue)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
switch req.RespValue.(type) {
|
||||
case *[]byte:
|
||||
defer response.Body.Close()
|
||||
|
||||
if buf, err = ioutil.ReadAll(response.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respVal := req.RespValue.(*[]byte)
|
||||
*respVal = buf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if req.RespConsume {
|
||||
defer response.Body.Close()
|
||||
ioutil.ReadAll(response.Body)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *HTTPClient) marshalRequest(req *RequestData) (err error) {
|
||||
if req.ReqReader != nil || req.ReqValue == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if req.Headers == nil {
|
||||
req.Headers = make(http.Header)
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
|
||||
switch req.ReqEncoding {
|
||||
case EncodingJSON:
|
||||
buf, err = json.Marshal(req.ReqValue)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.ReqReader = bytes.NewReader(buf)
|
||||
req.Headers.Set("Content-Type", "application/json")
|
||||
req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf)))
|
||||
|
||||
req.ReqContentLength = int64(len(buf))
|
||||
|
||||
return nil
|
||||
|
||||
case EncodingXML:
|
||||
buf, err = xml.Marshal(req.ReqValue)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf = append(XmlHeaderBytes, buf...)
|
||||
|
||||
req.ReqReader = bytes.NewReader(buf)
|
||||
req.Headers.Set("Content-Type", "application/xml")
|
||||
req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf)))
|
||||
|
||||
req.ReqContentLength = int64(len(buf))
|
||||
|
||||
return nil
|
||||
|
||||
case EncodingForm:
|
||||
if data, ok := req.ReqValue.(url.Values); ok {
|
||||
formStr := data.Encode()
|
||||
req.ReqReader = strings.NewReader(formStr)
|
||||
req.Headers.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(formStr)))
|
||||
|
||||
req.ReqContentLength = int64(len(formStr))
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("HTTPClient: invalid ReqValue type %T", req.ReqValue)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("HTTPClient: invalid ReqEncoding: %s", req.ReqEncoding)
|
||||
}
|
||||
|
||||
func (c *HTTPClient) runPostHook(req *http.Request, response *http.Response) (err error) {
|
||||
hook, ok := c.PostHooks[response.StatusCode]
|
||||
|
||||
if ok {
|
||||
err = hook(req, response)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *HTTPClient) Request(req *RequestData) (response *http.Response, err error) {
|
||||
err = c.marshalRequest(req)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := http.NewRequest(req.Method, req.FullURL, req.ReqReader)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.ContentLength = req.ReqContentLength
|
||||
|
||||
if req.FullURL == "" {
|
||||
r.URL = c.buildURL(req)
|
||||
r.Host = r.URL.Host
|
||||
}
|
||||
|
||||
c.setHeaders(req, r)
|
||||
|
||||
if c.rateLimited {
|
||||
if c.rateLimitTimeout > 0 {
|
||||
select {
|
||||
case t := <-c.rateLimitChan:
|
||||
defer func() {
|
||||
c.rateLimitChan <- t
|
||||
}()
|
||||
case <-time.After(c.rateLimitTimeout):
|
||||
return nil, RateLimitTimeoutError
|
||||
}
|
||||
} else {
|
||||
t := <-c.rateLimitChan
|
||||
defer func() {
|
||||
c.rateLimitChan <- t
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
isTraceEnabled := os.Getenv("HTTPCLIENT_TRACE") != ""
|
||||
|
||||
if isTraceEnabled {
|
||||
requestBytes, _ := httputil.DumpRequestOut(r, true)
|
||||
fmt.Println(string(requestBytes))
|
||||
}
|
||||
|
||||
if req.IgnoreRedirects {
|
||||
transport := c.Client.Transport
|
||||
|
||||
if transport == nil {
|
||||
transport = http.DefaultTransport
|
||||
}
|
||||
|
||||
response, err = transport.RoundTrip(r)
|
||||
} else {
|
||||
response, err = c.Client.Do(r)
|
||||
}
|
||||
|
||||
if isTraceEnabled {
|
||||
responseBytes, _ := httputil.DumpResponse(response, true)
|
||||
fmt.Println(string(responseBytes))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if err = c.runPostHook(r, response); err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if err = c.checkStatus(req, response); err != nil {
|
||||
defer response.Body.Close()
|
||||
return response, err
|
||||
}
|
||||
|
||||
if err = c.unmarshalResponse(req, response); err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
96
vendor/github.com/koofr/go-httpclient/requestdata.go
generated
vendored
Normal file
96
vendor/github.com/koofr/go-httpclient/requestdata.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Encoding string
|
||||
|
||||
const (
|
||||
EncodingJSON = "JSON"
|
||||
EncodingXML = "XML"
|
||||
EncodingForm = "Form"
|
||||
)
|
||||
|
||||
type RequestData struct {
|
||||
Method string
|
||||
Path string
|
||||
Params url.Values
|
||||
FullURL string // client.BaseURL + Path or FullURL
|
||||
Headers http.Header
|
||||
ReqReader io.Reader
|
||||
ReqEncoding Encoding
|
||||
ReqValue interface{}
|
||||
ReqContentLength int64
|
||||
ExpectedStatus []int
|
||||
IgnoreRedirects bool
|
||||
RespEncoding Encoding
|
||||
RespValue interface{}
|
||||
RespConsume bool
|
||||
}
|
||||
|
||||
func (r *RequestData) CanCopy() bool {
|
||||
if r.ReqReader != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *RequestData) Copy() (ok bool, nr *RequestData) {
|
||||
if !r.CanCopy() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
nr = &RequestData{
|
||||
Method: r.Method,
|
||||
Path: r.Path,
|
||||
FullURL: r.FullURL,
|
||||
ReqEncoding: r.ReqEncoding,
|
||||
ReqValue: r.ReqValue,
|
||||
IgnoreRedirects: r.IgnoreRedirects,
|
||||
RespEncoding: r.RespEncoding,
|
||||
RespValue: r.RespValue,
|
||||
RespConsume: r.RespConsume,
|
||||
}
|
||||
|
||||
if r.Params != nil {
|
||||
nr.Params = make(url.Values)
|
||||
|
||||
for k, vs := range r.Params {
|
||||
nvs := make([]string, len(vs))
|
||||
|
||||
for i, v := range vs {
|
||||
nvs[i] = v
|
||||
}
|
||||
|
||||
nr.Params[k] = nvs
|
||||
}
|
||||
}
|
||||
|
||||
if r.Headers != nil {
|
||||
nr.Headers = make(http.Header)
|
||||
|
||||
for k, vs := range r.Headers {
|
||||
nvs := make([]string, len(vs))
|
||||
|
||||
for i, v := range vs {
|
||||
nvs[i] = v
|
||||
}
|
||||
|
||||
nr.Headers[k] = nvs
|
||||
}
|
||||
}
|
||||
|
||||
if r.ExpectedStatus != nil {
|
||||
nr.ExpectedStatus = make([]int, len(r.ExpectedStatus))
|
||||
|
||||
for i, v := range r.ExpectedStatus {
|
||||
nr.ExpectedStatus[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
return true, nr
|
||||
}
|
62
vendor/github.com/koofr/go-httpclient/requestdata_upload.go
generated
vendored
Normal file
62
vendor/github.com/koofr/go-httpclient/requestdata_upload.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (req *RequestData) UploadFile(fieldName string, fileName string, reader io.Reader) (err error) {
|
||||
return req.UploadFileExtra(fieldName, fileName, reader, nil)
|
||||
}
|
||||
|
||||
func (req *RequestData) UploadFileExtra(fieldName string, fileName string, reader io.Reader, extra map[string]string) (err error) {
|
||||
r, w := io.Pipe()
|
||||
|
||||
writer := multipart.NewWriter(w)
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
if err == nil {
|
||||
w.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
for k, v := range extra {
|
||||
err = writer.WriteField(k, v)
|
||||
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
part, err := writer.CreateFormFile(fieldName, fileName)
|
||||
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer writer.Close()
|
||||
|
||||
_, err = io.Copy(part, reader)
|
||||
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
req.ReqReader = r
|
||||
|
||||
if req.Headers == nil {
|
||||
req.Headers = make(http.Header)
|
||||
}
|
||||
|
||||
req.Headers.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
return
|
||||
}
|
29
vendor/github.com/koofr/go-httpclient/transport.go
generated
vendored
Normal file
29
vendor/github.com/koofr/go-httpclient/transport.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var HttpTransport = &http.Transport{
|
||||
DisableCompression: true,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
|
||||
var HttpClient = &http.Client{
|
||||
Transport: HttpTransport,
|
||||
}
|
||||
|
||||
var InsecureTlsConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
var InsecureHttpTransport = &http.Transport{
|
||||
TLSClientConfig: InsecureTlsConfig,
|
||||
DisableCompression: true,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
|
||||
var InsecureHttpClient = &http.Client{
|
||||
Transport: InsecureHttpTransport,
|
||||
}
|
14
vendor/github.com/koofr/go-httpclient/utils.go
generated
vendored
Normal file
14
vendor/github.com/koofr/go-httpclient/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func EscapePath(path string) string {
|
||||
u := url.URL{
|
||||
Path: path,
|
||||
}
|
||||
|
||||
return strings.Replace(u.String(), "+", "%2b", -1)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue