ACME DNS challenges
This commit is contained in:
parent
7a2592b2fa
commit
5bdf8a5ea3
127 changed files with 24386 additions and 739 deletions
21
vendor/github.com/go-resty/resty/LICENSE
generated
vendored
Normal file
21
vendor/github.com/go-resty/resty/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2018 Jeevanandam M., https://myjeeva.com <jeeva@myjeeva.com>
|
||||
|
||||
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.
|
900
vendor/github.com/go-resty/resty/client.go
generated
vendored
Normal file
900
vendor/github.com/go-resty/resty/client.go
generated
vendored
Normal file
|
@ -0,0 +1,900 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// MethodGet HTTP method
|
||||
MethodGet = "GET"
|
||||
|
||||
// MethodPost HTTP method
|
||||
MethodPost = "POST"
|
||||
|
||||
// MethodPut HTTP method
|
||||
MethodPut = "PUT"
|
||||
|
||||
// MethodDelete HTTP method
|
||||
MethodDelete = "DELETE"
|
||||
|
||||
// MethodPatch HTTP method
|
||||
MethodPatch = "PATCH"
|
||||
|
||||
// MethodHead HTTP method
|
||||
MethodHead = "HEAD"
|
||||
|
||||
// MethodOptions HTTP method
|
||||
MethodOptions = "OPTIONS"
|
||||
)
|
||||
|
||||
var (
|
||||
hdrUserAgentKey = http.CanonicalHeaderKey("User-Agent")
|
||||
hdrAcceptKey = http.CanonicalHeaderKey("Accept")
|
||||
hdrContentTypeKey = http.CanonicalHeaderKey("Content-Type")
|
||||
hdrContentLengthKey = http.CanonicalHeaderKey("Content-Length")
|
||||
hdrContentEncodingKey = http.CanonicalHeaderKey("Content-Encoding")
|
||||
hdrAuthorizationKey = http.CanonicalHeaderKey("Authorization")
|
||||
|
||||
plainTextType = "text/plain; charset=utf-8"
|
||||
jsonContentType = "application/json; charset=utf-8"
|
||||
formContentType = "application/x-www-form-urlencoded"
|
||||
|
||||
jsonCheck = regexp.MustCompile(`(?i:(application|text)/(json|.*\+json)(;|$))`)
|
||||
xmlCheck = regexp.MustCompile(`(?i:(application|text)/(xml|.*\+xml)(;|$))`)
|
||||
|
||||
hdrUserAgentValue = "go-resty/%s (https://github.com/go-resty/resty)"
|
||||
bufPool = &sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
|
||||
)
|
||||
|
||||
// Client type is used for HTTP/RESTful global values
|
||||
// for all request raised from the client
|
||||
type Client struct {
|
||||
HostURL string
|
||||
QueryParam url.Values
|
||||
FormData url.Values
|
||||
Header http.Header
|
||||
UserInfo *User
|
||||
Token string
|
||||
Cookies []*http.Cookie
|
||||
Error reflect.Type
|
||||
Debug bool
|
||||
DisableWarn bool
|
||||
AllowGetMethodPayload bool
|
||||
Log *log.Logger
|
||||
RetryCount int
|
||||
RetryWaitTime time.Duration
|
||||
RetryMaxWaitTime time.Duration
|
||||
RetryConditions []RetryConditionFunc
|
||||
JSONMarshal func(v interface{}) ([]byte, error)
|
||||
JSONUnmarshal func(data []byte, v interface{}) error
|
||||
|
||||
jsonEscapeHTML bool
|
||||
httpClient *http.Client
|
||||
setContentLength bool
|
||||
isHTTPMode bool
|
||||
outputDirectory string
|
||||
scheme string
|
||||
proxyURL *url.URL
|
||||
closeConnection bool
|
||||
notParseResponse bool
|
||||
debugBodySizeLimit int64
|
||||
logPrefix string
|
||||
pathParams map[string]string
|
||||
beforeRequest []func(*Client, *Request) error
|
||||
udBeforeRequest []func(*Client, *Request) error
|
||||
preReqHook func(*Client, *Request) error
|
||||
afterResponse []func(*Client, *Response) error
|
||||
}
|
||||
|
||||
// User type is to hold an username and password information
|
||||
type User struct {
|
||||
Username, Password string
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Client methods
|
||||
//___________________________________
|
||||
|
||||
// SetHostURL method is to set Host URL in the client instance. It will be used with request
|
||||
// raised from this client with relative URL
|
||||
// // Setting HTTP address
|
||||
// resty.SetHostURL("http://myjeeva.com")
|
||||
//
|
||||
// // Setting HTTPS address
|
||||
// resty.SetHostURL("https://myjeeva.com")
|
||||
//
|
||||
func (c *Client) SetHostURL(url string) *Client {
|
||||
c.HostURL = strings.TrimRight(url, "/")
|
||||
return c
|
||||
}
|
||||
|
||||
// SetHeader method sets a single header field and its value in the client instance.
|
||||
// These headers will be applied to all requests raised from this client instance.
|
||||
// Also it can be overridden at request level header options, see `resty.R().SetHeader`
|
||||
// or `resty.R().SetHeaders`.
|
||||
//
|
||||
// Example: To set `Content-Type` and `Accept` as `application/json`
|
||||
//
|
||||
// resty.
|
||||
// SetHeader("Content-Type", "application/json").
|
||||
// SetHeader("Accept", "application/json")
|
||||
//
|
||||
func (c *Client) SetHeader(header, value string) *Client {
|
||||
c.Header.Set(header, value)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetHeaders method sets multiple headers field and its values at one go in the client instance.
|
||||
// These headers will be applied to all requests raised from this client instance. Also it can be
|
||||
// overridden at request level headers options, see `resty.R().SetHeaders` or `resty.R().SetHeader`.
|
||||
//
|
||||
// Example: To set `Content-Type` and `Accept` as `application/json`
|
||||
//
|
||||
// resty.SetHeaders(map[string]string{
|
||||
// "Content-Type": "application/json",
|
||||
// "Accept": "application/json",
|
||||
// })
|
||||
//
|
||||
func (c *Client) SetHeaders(headers map[string]string) *Client {
|
||||
for h, v := range headers {
|
||||
c.Header.Set(h, v)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCookieJar method sets custom http.CookieJar in the resty client. Its way to override default.
|
||||
// Example: sometimes we don't want to save cookies in api contacting, we can remove the default
|
||||
// CookieJar in resty client.
|
||||
//
|
||||
// resty.SetCookieJar(nil)
|
||||
//
|
||||
func (c *Client) SetCookieJar(jar http.CookieJar) *Client {
|
||||
c.httpClient.Jar = jar
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCookie method appends a single cookie in the client instance.
|
||||
// These cookies will be added to all the request raised from this client instance.
|
||||
// resty.SetCookie(&http.Cookie{
|
||||
// Name:"go-resty",
|
||||
// Value:"This is cookie value",
|
||||
// Path: "/",
|
||||
// Domain: "sample.com",
|
||||
// MaxAge: 36000,
|
||||
// HttpOnly: true,
|
||||
// Secure: false,
|
||||
// })
|
||||
//
|
||||
func (c *Client) SetCookie(hc *http.Cookie) *Client {
|
||||
c.Cookies = append(c.Cookies, hc)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCookies method sets an array of cookies in the client instance.
|
||||
// These cookies will be added to all the request raised from this client instance.
|
||||
// cookies := make([]*http.Cookie, 0)
|
||||
//
|
||||
// cookies = append(cookies, &http.Cookie{
|
||||
// Name:"go-resty-1",
|
||||
// Value:"This is cookie 1 value",
|
||||
// Path: "/",
|
||||
// Domain: "sample.com",
|
||||
// MaxAge: 36000,
|
||||
// HttpOnly: true,
|
||||
// Secure: false,
|
||||
// })
|
||||
//
|
||||
// cookies = append(cookies, &http.Cookie{
|
||||
// Name:"go-resty-2",
|
||||
// Value:"This is cookie 2 value",
|
||||
// Path: "/",
|
||||
// Domain: "sample.com",
|
||||
// MaxAge: 36000,
|
||||
// HttpOnly: true,
|
||||
// Secure: false,
|
||||
// })
|
||||
//
|
||||
// // Setting a cookies into resty
|
||||
// resty.SetCookies(cookies)
|
||||
//
|
||||
func (c *Client) SetCookies(cs []*http.Cookie) *Client {
|
||||
c.Cookies = append(c.Cookies, cs...)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetQueryParam method sets single parameter and its value in the client instance.
|
||||
// It will be formed as query string for the request. For example: `search=kitchen%20papers&size=large`
|
||||
// in the URL after `?` mark. These query params will be added to all the request raised from
|
||||
// this client instance. Also it can be overridden at request level Query Param options,
|
||||
// see `resty.R().SetQueryParam` or `resty.R().SetQueryParams`.
|
||||
// resty.
|
||||
// SetQueryParam("search", "kitchen papers").
|
||||
// SetQueryParam("size", "large")
|
||||
//
|
||||
func (c *Client) SetQueryParam(param, value string) *Client {
|
||||
c.QueryParam.Set(param, value)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetQueryParams method sets multiple parameters and their values at one go in the client instance.
|
||||
// It will be formed as query string for the request. For example: `search=kitchen%20papers&size=large`
|
||||
// in the URL after `?` mark. These query params will be added to all the request raised from this
|
||||
// client instance. Also it can be overridden at request level Query Param options,
|
||||
// see `resty.R().SetQueryParams` or `resty.R().SetQueryParam`.
|
||||
// resty.SetQueryParams(map[string]string{
|
||||
// "search": "kitchen papers",
|
||||
// "size": "large",
|
||||
// })
|
||||
//
|
||||
func (c *Client) SetQueryParams(params map[string]string) *Client {
|
||||
for p, v := range params {
|
||||
c.SetQueryParam(p, v)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetFormData method sets Form parameters and their values in the client instance.
|
||||
// It's applicable only HTTP method `POST` and `PUT` and requets content type would be set as
|
||||
// `application/x-www-form-urlencoded`. These form data will be added to all the request raised from
|
||||
// this client instance. Also it can be overridden at request level form data, see `resty.R().SetFormData`.
|
||||
// resty.SetFormData(map[string]string{
|
||||
// "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
|
||||
// "user_id": "3455454545",
|
||||
// })
|
||||
//
|
||||
func (c *Client) SetFormData(data map[string]string) *Client {
|
||||
for k, v := range data {
|
||||
c.FormData.Set(k, v)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetBasicAuth method sets the basic authentication header in the HTTP request. Example:
|
||||
// Authorization: Basic <base64-encoded-value>
|
||||
//
|
||||
// Example: To set the header for username "go-resty" and password "welcome"
|
||||
// resty.SetBasicAuth("go-resty", "welcome")
|
||||
//
|
||||
// This basic auth information gets added to all the request rasied from this client instance.
|
||||
// Also it can be overridden or set one at the request level is supported, see `resty.R().SetBasicAuth`.
|
||||
//
|
||||
func (c *Client) SetBasicAuth(username, password string) *Client {
|
||||
c.UserInfo = &User{Username: username, Password: password}
|
||||
return c
|
||||
}
|
||||
|
||||
// SetAuthToken method sets bearer auth token header in the HTTP request. Example:
|
||||
// Authorization: Bearer <auth-token-value-comes-here>
|
||||
//
|
||||
// Example: To set auth token BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F
|
||||
//
|
||||
// resty.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
|
||||
//
|
||||
// This bearer auth token gets added to all the request rasied from this client instance.
|
||||
// Also it can be overridden or set one at the request level is supported, see `resty.R().SetAuthToken`.
|
||||
//
|
||||
func (c *Client) SetAuthToken(token string) *Client {
|
||||
c.Token = token
|
||||
return c
|
||||
}
|
||||
|
||||
// R method creates a request instance, its used for Get, Post, Put, Delete, Patch, Head and Options.
|
||||
func (c *Client) R() *Request {
|
||||
r := &Request{
|
||||
QueryParam: url.Values{},
|
||||
FormData: url.Values{},
|
||||
Header: http.Header{},
|
||||
|
||||
client: c,
|
||||
multipartFiles: []*File{},
|
||||
multipartFields: []*multipartField{},
|
||||
pathParams: map[string]string{},
|
||||
jsonEscapeHTML: true,
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// NewRequest is an alias for R(). Creates a request instance, its used for
|
||||
// Get, Post, Put, Delete, Patch, Head and Options.
|
||||
func (c *Client) NewRequest() *Request {
|
||||
return c.R()
|
||||
}
|
||||
|
||||
// OnBeforeRequest method appends request middleware into the before request chain.
|
||||
// Its gets applied after default `go-resty` request middlewares and before request
|
||||
// been sent from `go-resty` to host server.
|
||||
// resty.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
|
||||
// // Now you have access to Client and Request instance
|
||||
// // manipulate it as per your need
|
||||
//
|
||||
// return nil // if its success otherwise return error
|
||||
// })
|
||||
//
|
||||
func (c *Client) OnBeforeRequest(m func(*Client, *Request) error) *Client {
|
||||
c.udBeforeRequest = append(c.udBeforeRequest, m)
|
||||
return c
|
||||
}
|
||||
|
||||
// OnAfterResponse method appends response middleware into the after response chain.
|
||||
// Once we receive response from host server, default `go-resty` response middleware
|
||||
// gets applied and then user assigened response middlewares applied.
|
||||
// resty.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
|
||||
// // Now you have access to Client and Response instance
|
||||
// // manipulate it as per your need
|
||||
//
|
||||
// return nil // if its success otherwise return error
|
||||
// })
|
||||
//
|
||||
func (c *Client) OnAfterResponse(m func(*Client, *Response) error) *Client {
|
||||
c.afterResponse = append(c.afterResponse, m)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetPreRequestHook method sets the given pre-request function into resty client.
|
||||
// It is called right before the request is fired.
|
||||
//
|
||||
// Note: Only one pre-request hook can be registered. Use `resty.OnBeforeRequest` for mutilple.
|
||||
func (c *Client) SetPreRequestHook(h func(*Client, *Request) error) *Client {
|
||||
if c.preReqHook != nil {
|
||||
c.Log.Printf("Overwriting an existing pre-request hook: %s", functionName(h))
|
||||
}
|
||||
c.preReqHook = h
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDebug method enables the debug mode on `go-resty` client. Client logs details of every request and response.
|
||||
// For `Request` it logs information such as HTTP verb, Relative URL path, Host, Headers, Body if it has one.
|
||||
// For `Response` it logs information such as Status, Response Time, Headers, Body if it has one.
|
||||
// resty.SetDebug(true)
|
||||
//
|
||||
func (c *Client) SetDebug(d bool) *Client {
|
||||
c.Debug = d
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDebugBodyLimit sets the maximum size for which the response body will be logged in debug mode.
|
||||
// resty.SetDebugBodyLimit(1000000)
|
||||
//
|
||||
func (c *Client) SetDebugBodyLimit(sl int64) *Client {
|
||||
c.debugBodySizeLimit = sl
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDisableWarn method disables the warning message on `go-resty` client.
|
||||
// For example: go-resty warns the user when BasicAuth used on HTTP mode.
|
||||
// resty.SetDisableWarn(true)
|
||||
//
|
||||
func (c *Client) SetDisableWarn(d bool) *Client {
|
||||
c.DisableWarn = d
|
||||
return c
|
||||
}
|
||||
|
||||
// SetAllowGetMethodPayload method allows the GET method with payload on `go-resty` client.
|
||||
// For example: go-resty allows the user sends request with a payload on HTTP GET method.
|
||||
// resty.SetAllowGetMethodPayload(true)
|
||||
//
|
||||
func (c *Client) SetAllowGetMethodPayload(a bool) *Client {
|
||||
c.AllowGetMethodPayload = a
|
||||
return c
|
||||
}
|
||||
|
||||
// SetLogger method sets given writer for logging go-resty request and response details.
|
||||
// Default is os.Stderr
|
||||
// file, _ := os.OpenFile("/Users/jeeva/go-resty.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
//
|
||||
// resty.SetLogger(file)
|
||||
//
|
||||
func (c *Client) SetLogger(w io.Writer) *Client {
|
||||
c.Log = getLogger(w)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetContentLength method enables the HTTP header `Content-Length` value for every request.
|
||||
// By default go-resty won't set `Content-Length`.
|
||||
// resty.SetContentLength(true)
|
||||
//
|
||||
// Also you have an option to enable for particular request. See `resty.R().SetContentLength`
|
||||
//
|
||||
func (c *Client) SetContentLength(l bool) *Client {
|
||||
c.setContentLength = l
|
||||
return c
|
||||
}
|
||||
|
||||
// SetTimeout method sets timeout for request raised from client.
|
||||
// resty.SetTimeout(time.Duration(1 * time.Minute))
|
||||
//
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.httpClient.Timeout = timeout
|
||||
return c
|
||||
}
|
||||
|
||||
// SetError method is to register the global or client common `Error` object into go-resty.
|
||||
// It is used for automatic unmarshalling if response status code is greater than 399 and
|
||||
// content type either JSON or XML. Can be pointer or non-pointer.
|
||||
// resty.SetError(&Error{})
|
||||
// // OR
|
||||
// resty.SetError(Error{})
|
||||
//
|
||||
func (c *Client) SetError(err interface{}) *Client {
|
||||
c.Error = typeOf(err)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetRedirectPolicy method sets the client redirect poilicy. go-resty provides ready to use
|
||||
// redirect policies. Wanna create one for yourself refer `redirect.go`.
|
||||
//
|
||||
// resty.SetRedirectPolicy(FlexibleRedirectPolicy(20))
|
||||
//
|
||||
// // Need multiple redirect policies together
|
||||
// resty.SetRedirectPolicy(FlexibleRedirectPolicy(20), DomainCheckRedirectPolicy("host1.com", "host2.net"))
|
||||
//
|
||||
func (c *Client) SetRedirectPolicy(policies ...interface{}) *Client {
|
||||
for _, p := range policies {
|
||||
if _, ok := p.(RedirectPolicy); !ok {
|
||||
c.Log.Printf("ERORR: %v does not implement resty.RedirectPolicy (missing Apply method)",
|
||||
functionName(p))
|
||||
}
|
||||
}
|
||||
|
||||
c.httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||
for _, p := range policies {
|
||||
if err := p.(RedirectPolicy).Apply(req, via); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil // looks good, go ahead
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetRetryCount method enables retry on `go-resty` client and allows you
|
||||
// to set no. of retry count. Resty uses a Backoff mechanism.
|
||||
func (c *Client) SetRetryCount(count int) *Client {
|
||||
c.RetryCount = count
|
||||
return c
|
||||
}
|
||||
|
||||
// SetRetryWaitTime method sets default wait time to sleep before retrying
|
||||
// request.
|
||||
// Default is 100 milliseconds.
|
||||
func (c *Client) SetRetryWaitTime(waitTime time.Duration) *Client {
|
||||
c.RetryWaitTime = waitTime
|
||||
return c
|
||||
}
|
||||
|
||||
// SetRetryMaxWaitTime method sets max wait time to sleep before retrying
|
||||
// request.
|
||||
// Default is 2 seconds.
|
||||
func (c *Client) SetRetryMaxWaitTime(maxWaitTime time.Duration) *Client {
|
||||
c.RetryMaxWaitTime = maxWaitTime
|
||||
return c
|
||||
}
|
||||
|
||||
// AddRetryCondition method adds a retry condition function to array of functions
|
||||
// that are checked to determine if the request is retried. The request will
|
||||
// retry if any of the functions return true and error is nil.
|
||||
func (c *Client) AddRetryCondition(condition RetryConditionFunc) *Client {
|
||||
c.RetryConditions = append(c.RetryConditions, condition)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetHTTPMode method sets go-resty mode to 'http'
|
||||
func (c *Client) SetHTTPMode() *Client {
|
||||
return c.SetMode("http")
|
||||
}
|
||||
|
||||
// SetRESTMode method sets go-resty mode to 'rest'
|
||||
func (c *Client) SetRESTMode() *Client {
|
||||
return c.SetMode("rest")
|
||||
}
|
||||
|
||||
// SetMode method sets go-resty client mode to given value such as 'http' & 'rest'.
|
||||
// 'rest':
|
||||
// - No Redirect
|
||||
// - Automatic response unmarshal if it is JSON or XML
|
||||
// 'http':
|
||||
// - Up to 10 Redirects
|
||||
// - No automatic unmarshall. Response will be treated as `response.String()`
|
||||
//
|
||||
// If you want more redirects, use FlexibleRedirectPolicy
|
||||
// resty.SetRedirectPolicy(FlexibleRedirectPolicy(20))
|
||||
//
|
||||
func (c *Client) SetMode(mode string) *Client {
|
||||
// HTTP
|
||||
if mode == "http" {
|
||||
c.isHTTPMode = true
|
||||
c.SetRedirectPolicy(FlexibleRedirectPolicy(10))
|
||||
c.afterResponse = []func(*Client, *Response) error{
|
||||
responseLogger,
|
||||
saveResponseIntoFile,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// RESTful
|
||||
c.isHTTPMode = false
|
||||
c.SetRedirectPolicy(NoRedirectPolicy())
|
||||
c.afterResponse = []func(*Client, *Response) error{
|
||||
responseLogger,
|
||||
parseResponseBody,
|
||||
saveResponseIntoFile,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Mode method returns the current client mode. Typically its a "http" or "rest".
|
||||
// Default is "rest"
|
||||
func (c *Client) Mode() string {
|
||||
if c.isHTTPMode {
|
||||
return "http"
|
||||
}
|
||||
return "rest"
|
||||
}
|
||||
|
||||
// SetTLSClientConfig method sets TLSClientConfig for underling client Transport.
|
||||
//
|
||||
// Example:
|
||||
// // One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
|
||||
// resty.SetTLSClientConfig(&tls.Config{ RootCAs: roots })
|
||||
//
|
||||
// // or One can disable security check (https)
|
||||
// resty.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })
|
||||
// Note: This method overwrites existing `TLSClientConfig`.
|
||||
//
|
||||
func (c *Client) SetTLSClientConfig(config *tls.Config) *Client {
|
||||
transport, err := c.getTransport()
|
||||
if err != nil {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
return c
|
||||
}
|
||||
transport.TLSClientConfig = config
|
||||
return c
|
||||
}
|
||||
|
||||
// SetProxy method sets the Proxy URL and Port for resty client.
|
||||
// resty.SetProxy("http://proxyserver:8888")
|
||||
//
|
||||
// Alternatives: At request level proxy, see `Request.SetProxy`. OR Without this `SetProxy` method,
|
||||
// you can also set Proxy via environment variable. By default `Go` uses setting from `HTTP_PROXY`.
|
||||
//
|
||||
func (c *Client) SetProxy(proxyURL string) *Client {
|
||||
transport, err := c.getTransport()
|
||||
if err != nil {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
return c
|
||||
}
|
||||
|
||||
if pURL, err := url.Parse(proxyURL); err == nil {
|
||||
c.proxyURL = pURL
|
||||
transport.Proxy = http.ProxyURL(c.proxyURL)
|
||||
} else {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
c.RemoveProxy()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// RemoveProxy method removes the proxy configuration from resty client
|
||||
// resty.RemoveProxy()
|
||||
//
|
||||
func (c *Client) RemoveProxy() *Client {
|
||||
transport, err := c.getTransport()
|
||||
if err != nil {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
return c
|
||||
}
|
||||
c.proxyURL = nil
|
||||
transport.Proxy = nil
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCertificates method helps to set client certificates into resty conveniently.
|
||||
//
|
||||
func (c *Client) SetCertificates(certs ...tls.Certificate) *Client {
|
||||
config, err := c.getTLSConfig()
|
||||
if err != nil {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
return c
|
||||
}
|
||||
config.Certificates = append(config.Certificates, certs...)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetRootCertificate method helps to add one or more root certificates into resty client
|
||||
// resty.SetRootCertificate("/path/to/root/pemFile.pem")
|
||||
//
|
||||
func (c *Client) SetRootCertificate(pemFilePath string) *Client {
|
||||
rootPemData, err := ioutil.ReadFile(pemFilePath)
|
||||
if err != nil {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
return c
|
||||
}
|
||||
|
||||
config, err := c.getTLSConfig()
|
||||
if err != nil {
|
||||
c.Log.Printf("ERROR %v", err)
|
||||
return c
|
||||
}
|
||||
if config.RootCAs == nil {
|
||||
config.RootCAs = x509.NewCertPool()
|
||||
}
|
||||
|
||||
config.RootCAs.AppendCertsFromPEM(rootPemData)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetOutputDirectory method sets output directory for saving HTTP response into file.
|
||||
// If the output directory not exists then resty creates one. This setting is optional one,
|
||||
// if you're planning using absoule path in `Request.SetOutput` and can used together.
|
||||
// resty.SetOutputDirectory("/save/http/response/here")
|
||||
//
|
||||
func (c *Client) SetOutputDirectory(dirPath string) *Client {
|
||||
c.outputDirectory = dirPath
|
||||
return c
|
||||
}
|
||||
|
||||
// SetTransport method sets custom `*http.Transport` or any `http.RoundTripper`
|
||||
// compatible interface implementation in the resty client.
|
||||
//
|
||||
// NOTE:
|
||||
//
|
||||
// - If transport is not type of `*http.Transport` then you may not be able to
|
||||
// take advantage of some of the `resty` client settings.
|
||||
//
|
||||
// - It overwrites the resty client transport instance and it's configurations.
|
||||
//
|
||||
// transport := &http.Transport{
|
||||
// // somthing like Proxying to httptest.Server, etc...
|
||||
// Proxy: func(req *http.Request) (*url.URL, error) {
|
||||
// return url.Parse(server.URL)
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// resty.SetTransport(transport)
|
||||
//
|
||||
func (c *Client) SetTransport(transport http.RoundTripper) *Client {
|
||||
if transport != nil {
|
||||
c.httpClient.Transport = transport
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// SetScheme method sets custom scheme in the resty client. It's way to override default.
|
||||
// resty.SetScheme("http")
|
||||
//
|
||||
func (c *Client) SetScheme(scheme string) *Client {
|
||||
if !IsStringEmpty(scheme) {
|
||||
c.scheme = scheme
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCloseConnection method sets variable `Close` in http request struct with the given
|
||||
// value. More info: https://golang.org/src/net/http/request.go
|
||||
func (c *Client) SetCloseConnection(close bool) *Client {
|
||||
c.closeConnection = close
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
|
||||
// Resty exposes the raw response body as `io.ReadCloser`. Also do not forget to close the body,
|
||||
// otherwise you might get into connection leaks, no connection reuse.
|
||||
//
|
||||
// Please Note: Response middlewares are not applicable, if you use this option. Basically you have
|
||||
// taken over the control of response parsing from `Resty`.
|
||||
func (c *Client) SetDoNotParseResponse(parse bool) *Client {
|
||||
c.notParseResponse = parse
|
||||
return c
|
||||
}
|
||||
|
||||
// SetLogPrefix method sets the Resty logger prefix value.
|
||||
func (c *Client) SetLogPrefix(prefix string) *Client {
|
||||
c.logPrefix = prefix
|
||||
c.Log.SetPrefix(prefix)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetPathParams method sets multiple URL path key-value pairs at one go in the
|
||||
// resty client instance.
|
||||
// resty.SetPathParams(map[string]string{
|
||||
// "userId": "sample@sample.com",
|
||||
// "subAccountId": "100002",
|
||||
// })
|
||||
//
|
||||
// Result:
|
||||
// URL - /v1/users/{userId}/{subAccountId}/details
|
||||
// Composed URL - /v1/users/sample@sample.com/100002/details
|
||||
// It replace the value of the key while composing request URL. Also it can be
|
||||
// overridden at request level Path Params options, see `Request.SetPathParams`.
|
||||
func (c *Client) SetPathParams(params map[string]string) *Client {
|
||||
for p, v := range params {
|
||||
c.pathParams[p] = v
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// SetJSONEscapeHTML method is to enable/disable the HTML escape on JSON marshal.
|
||||
//
|
||||
// NOTE: This option only applicable to standard JSON Marshaller.
|
||||
func (c *Client) SetJSONEscapeHTML(b bool) *Client {
|
||||
c.jsonEscapeHTML = b
|
||||
return c
|
||||
}
|
||||
|
||||
// IsProxySet method returns the true if proxy is set on client otherwise false.
|
||||
func (c *Client) IsProxySet() bool {
|
||||
return c.proxyURL != nil
|
||||
}
|
||||
|
||||
// GetClient method returns the current http.Client used by the resty client.
|
||||
func (c *Client) GetClient() *http.Client {
|
||||
return c.httpClient
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Client Unexported methods
|
||||
//___________________________________
|
||||
|
||||
// executes the given `Request` object and returns response
|
||||
func (c *Client) execute(req *Request) (*Response, error) {
|
||||
defer releaseBuffer(req.bodyBuf)
|
||||
// Apply Request middleware
|
||||
var err error
|
||||
|
||||
// user defined on before request methods
|
||||
// to modify the *resty.Request object
|
||||
for _, f := range c.udBeforeRequest {
|
||||
if err = f(c, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// resty middlewares
|
||||
for _, f := range c.beforeRequest {
|
||||
if err = f(c, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// call pre-request if defined
|
||||
if c.preReqHook != nil {
|
||||
if err = c.preReqHook(c, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if hostHeader := req.Header.Get("Host"); hostHeader != "" {
|
||||
req.RawRequest.Host = hostHeader
|
||||
}
|
||||
|
||||
req.Time = time.Now()
|
||||
resp, err := c.httpClient.Do(req.RawRequest)
|
||||
|
||||
response := &Response{
|
||||
Request: req,
|
||||
RawResponse: resp,
|
||||
receivedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err != nil || req.notParseResponse || c.notParseResponse {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if !req.isSaveResponse {
|
||||
defer closeq(resp.Body)
|
||||
body := resp.Body
|
||||
|
||||
// GitHub #142
|
||||
if strings.EqualFold(resp.Header.Get(hdrContentEncodingKey), "gzip") && resp.ContentLength > 0 {
|
||||
if _, ok := body.(*gzip.Reader); !ok {
|
||||
body, err = gzip.NewReader(body)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
defer closeq(body)
|
||||
}
|
||||
}
|
||||
|
||||
if response.body, err = ioutil.ReadAll(body); err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
response.size = int64(len(response.body))
|
||||
}
|
||||
|
||||
// Apply Response middleware
|
||||
for _, f := range c.afterResponse {
|
||||
if err = f(c, response); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
// enables a log prefix
|
||||
func (c *Client) enableLogPrefix() {
|
||||
c.Log.SetFlags(log.LstdFlags)
|
||||
c.Log.SetPrefix(c.logPrefix)
|
||||
}
|
||||
|
||||
// disables a log prefix
|
||||
func (c *Client) disableLogPrefix() {
|
||||
c.Log.SetFlags(0)
|
||||
c.Log.SetPrefix("")
|
||||
}
|
||||
|
||||
// getting TLS client config if not exists then create one
|
||||
func (c *Client) getTLSConfig() (*tls.Config, error) {
|
||||
transport, err := c.getTransport()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if transport.TLSClientConfig == nil {
|
||||
transport.TLSClientConfig = &tls.Config{}
|
||||
}
|
||||
return transport.TLSClientConfig, nil
|
||||
}
|
||||
|
||||
// returns `*http.Transport` currently in use or error
|
||||
// in case currently used `transport` is not an `*http.Transport`
|
||||
func (c *Client) getTransport() (*http.Transport, error) {
|
||||
if c.httpClient.Transport == nil {
|
||||
c.SetTransport(new(http.Transport))
|
||||
}
|
||||
|
||||
if transport, ok := c.httpClient.Transport.(*http.Transport); ok {
|
||||
return transport, nil
|
||||
}
|
||||
return nil, errors.New("current transport is not an *http.Transport instance")
|
||||
}
|
||||
|
||||
//
|
||||
// File
|
||||
//
|
||||
|
||||
// File represent file information for multipart request
|
||||
type File struct {
|
||||
Name string
|
||||
ParamName string
|
||||
io.Reader
|
||||
}
|
||||
|
||||
// String returns string value of current file details
|
||||
func (f *File) String() string {
|
||||
return fmt.Sprintf("ParamName: %v; FileName: %v", f.ParamName, f.Name)
|
||||
}
|
||||
|
||||
// multipartField represent custom data part for multipart request
|
||||
type multipartField struct {
|
||||
Param string
|
||||
FileName string
|
||||
ContentType string
|
||||
io.Reader
|
||||
}
|
328
vendor/github.com/go-resty/resty/default.go
generated
vendored
Normal file
328
vendor/github.com/go-resty/resty/default.go
generated
vendored
Normal file
|
@ -0,0 +1,328 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
// DefaultClient of resty
|
||||
var DefaultClient *Client
|
||||
|
||||
// New method creates a new go-resty client.
|
||||
func New() *Client {
|
||||
cookieJar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
return createClient(&http.Client{Jar: cookieJar})
|
||||
}
|
||||
|
||||
// NewWithClient method create a new go-resty client with given `http.Client`.
|
||||
func NewWithClient(hc *http.Client) *Client {
|
||||
return createClient(hc)
|
||||
}
|
||||
|
||||
// R creates a new resty request object, it is used form a HTTP/RESTful request
|
||||
// such as GET, POST, PUT, DELETE, HEAD, PATCH and OPTIONS.
|
||||
func R() *Request {
|
||||
return DefaultClient.R()
|
||||
}
|
||||
|
||||
// NewRequest is an alias for R(). Creates a new resty request object, it is used form a HTTP/RESTful request
|
||||
// such as GET, POST, PUT, DELETE, HEAD, PATCH and OPTIONS.
|
||||
func NewRequest() *Request {
|
||||
return R()
|
||||
}
|
||||
|
||||
// SetHostURL sets Host URL. See `Client.SetHostURL for more information.
|
||||
func SetHostURL(url string) *Client {
|
||||
return DefaultClient.SetHostURL(url)
|
||||
}
|
||||
|
||||
// SetHeader sets single header. See `Client.SetHeader` for more information.
|
||||
func SetHeader(header, value string) *Client {
|
||||
return DefaultClient.SetHeader(header, value)
|
||||
}
|
||||
|
||||
// SetHeaders sets multiple headers. See `Client.SetHeaders` for more information.
|
||||
func SetHeaders(headers map[string]string) *Client {
|
||||
return DefaultClient.SetHeaders(headers)
|
||||
}
|
||||
|
||||
// SetCookieJar sets custom http.CookieJar. See `Client.SetCookieJar` for more information.
|
||||
func SetCookieJar(jar http.CookieJar) *Client {
|
||||
return DefaultClient.SetCookieJar(jar)
|
||||
}
|
||||
|
||||
// SetCookie sets single cookie object. See `Client.SetCookie` for more information.
|
||||
func SetCookie(hc *http.Cookie) *Client {
|
||||
return DefaultClient.SetCookie(hc)
|
||||
}
|
||||
|
||||
// SetCookies sets multiple cookie object. See `Client.SetCookies` for more information.
|
||||
func SetCookies(cs []*http.Cookie) *Client {
|
||||
return DefaultClient.SetCookies(cs)
|
||||
}
|
||||
|
||||
// SetQueryParam method sets single parameter and its value. See `Client.SetQueryParam` for more information.
|
||||
func SetQueryParam(param, value string) *Client {
|
||||
return DefaultClient.SetQueryParam(param, value)
|
||||
}
|
||||
|
||||
// SetQueryParams method sets multiple parameters and its value. See `Client.SetQueryParams` for more information.
|
||||
func SetQueryParams(params map[string]string) *Client {
|
||||
return DefaultClient.SetQueryParams(params)
|
||||
}
|
||||
|
||||
// SetFormData method sets Form parameters and its values. See `Client.SetFormData` for more information.
|
||||
func SetFormData(data map[string]string) *Client {
|
||||
return DefaultClient.SetFormData(data)
|
||||
}
|
||||
|
||||
// SetBasicAuth method sets the basic authentication header. See `Client.SetBasicAuth` for more information.
|
||||
func SetBasicAuth(username, password string) *Client {
|
||||
return DefaultClient.SetBasicAuth(username, password)
|
||||
}
|
||||
|
||||
// SetAuthToken method sets bearer auth token header. See `Client.SetAuthToken` for more information.
|
||||
func SetAuthToken(token string) *Client {
|
||||
return DefaultClient.SetAuthToken(token)
|
||||
}
|
||||
|
||||
// OnBeforeRequest method sets request middleware. See `Client.OnBeforeRequest` for more information.
|
||||
func OnBeforeRequest(m func(*Client, *Request) error) *Client {
|
||||
return DefaultClient.OnBeforeRequest(m)
|
||||
}
|
||||
|
||||
// OnAfterResponse method sets response middleware. See `Client.OnAfterResponse` for more information.
|
||||
func OnAfterResponse(m func(*Client, *Response) error) *Client {
|
||||
return DefaultClient.OnAfterResponse(m)
|
||||
}
|
||||
|
||||
// SetPreRequestHook method sets the pre-request hook. See `Client.SetPreRequestHook` for more information.
|
||||
func SetPreRequestHook(h func(*Client, *Request) error) *Client {
|
||||
return DefaultClient.SetPreRequestHook(h)
|
||||
}
|
||||
|
||||
// SetDebug method enables the debug mode. See `Client.SetDebug` for more information.
|
||||
func SetDebug(d bool) *Client {
|
||||
return DefaultClient.SetDebug(d)
|
||||
}
|
||||
|
||||
// SetDebugBodyLimit method sets the response body limit for debug mode. See `Client.SetDebugBodyLimit` for more information.
|
||||
func SetDebugBodyLimit(sl int64) *Client {
|
||||
return DefaultClient.SetDebugBodyLimit(sl)
|
||||
}
|
||||
|
||||
// SetAllowGetMethodPayload method allows the GET method with payload. See `Client.SetAllowGetMethodPayload` for more information.
|
||||
func SetAllowGetMethodPayload(a bool) *Client {
|
||||
return DefaultClient.SetAllowGetMethodPayload(a)
|
||||
}
|
||||
|
||||
// SetRetryCount method sets the retry count. See `Client.SetRetryCount` for more information.
|
||||
func SetRetryCount(count int) *Client {
|
||||
return DefaultClient.SetRetryCount(count)
|
||||
}
|
||||
|
||||
// SetRetryWaitTime method sets the retry wait time. See `Client.SetRetryWaitTime` for more information.
|
||||
func SetRetryWaitTime(waitTime time.Duration) *Client {
|
||||
return DefaultClient.SetRetryWaitTime(waitTime)
|
||||
}
|
||||
|
||||
// SetRetryMaxWaitTime method sets the retry max wait time. See `Client.SetRetryMaxWaitTime` for more information.
|
||||
func SetRetryMaxWaitTime(maxWaitTime time.Duration) *Client {
|
||||
return DefaultClient.SetRetryMaxWaitTime(maxWaitTime)
|
||||
}
|
||||
|
||||
// AddRetryCondition method appends check function for retry. See `Client.AddRetryCondition` for more information.
|
||||
func AddRetryCondition(condition RetryConditionFunc) *Client {
|
||||
return DefaultClient.AddRetryCondition(condition)
|
||||
}
|
||||
|
||||
// SetDisableWarn method disables warning comes from `go-resty` client. See `Client.SetDisableWarn` for more information.
|
||||
func SetDisableWarn(d bool) *Client {
|
||||
return DefaultClient.SetDisableWarn(d)
|
||||
}
|
||||
|
||||
// SetLogger method sets given writer for logging. See `Client.SetLogger` for more information.
|
||||
func SetLogger(w io.Writer) *Client {
|
||||
return DefaultClient.SetLogger(w)
|
||||
}
|
||||
|
||||
// SetContentLength method enables `Content-Length` value. See `Client.SetContentLength` for more information.
|
||||
func SetContentLength(l bool) *Client {
|
||||
return DefaultClient.SetContentLength(l)
|
||||
}
|
||||
|
||||
// SetError method is to register the global or client common `Error` object. See `Client.SetError` for more information.
|
||||
func SetError(err interface{}) *Client {
|
||||
return DefaultClient.SetError(err)
|
||||
}
|
||||
|
||||
// SetRedirectPolicy method sets the client redirect poilicy. See `Client.SetRedirectPolicy` for more information.
|
||||
func SetRedirectPolicy(policies ...interface{}) *Client {
|
||||
return DefaultClient.SetRedirectPolicy(policies...)
|
||||
}
|
||||
|
||||
// SetHTTPMode method sets go-resty mode into HTTP. See `Client.SetMode` for more information.
|
||||
func SetHTTPMode() *Client {
|
||||
return DefaultClient.SetHTTPMode()
|
||||
}
|
||||
|
||||
// SetRESTMode method sets go-resty mode into RESTful. See `Client.SetMode` for more information.
|
||||
func SetRESTMode() *Client {
|
||||
return DefaultClient.SetRESTMode()
|
||||
}
|
||||
|
||||
// Mode method returns the current client mode. See `Client.Mode` for more information.
|
||||
func Mode() string {
|
||||
return DefaultClient.Mode()
|
||||
}
|
||||
|
||||
// SetTLSClientConfig method sets TLSClientConfig for underling client Transport. See `Client.SetTLSClientConfig` for more information.
|
||||
func SetTLSClientConfig(config *tls.Config) *Client {
|
||||
return DefaultClient.SetTLSClientConfig(config)
|
||||
}
|
||||
|
||||
// SetTimeout method sets timeout for request. See `Client.SetTimeout` for more information.
|
||||
func SetTimeout(timeout time.Duration) *Client {
|
||||
return DefaultClient.SetTimeout(timeout)
|
||||
}
|
||||
|
||||
// SetProxy method sets Proxy for request. See `Client.SetProxy` for more information.
|
||||
func SetProxy(proxyURL string) *Client {
|
||||
return DefaultClient.SetProxy(proxyURL)
|
||||
}
|
||||
|
||||
// RemoveProxy method removes the proxy configuration. See `Client.RemoveProxy` for more information.
|
||||
func RemoveProxy() *Client {
|
||||
return DefaultClient.RemoveProxy()
|
||||
}
|
||||
|
||||
// SetCertificates method helps to set client certificates into resty conveniently.
|
||||
// See `Client.SetCertificates` for more information and example.
|
||||
func SetCertificates(certs ...tls.Certificate) *Client {
|
||||
return DefaultClient.SetCertificates(certs...)
|
||||
}
|
||||
|
||||
// SetRootCertificate method helps to add one or more root certificates into resty client.
|
||||
// See `Client.SetRootCertificate` for more information.
|
||||
func SetRootCertificate(pemFilePath string) *Client {
|
||||
return DefaultClient.SetRootCertificate(pemFilePath)
|
||||
}
|
||||
|
||||
// SetOutputDirectory method sets output directory. See `Client.SetOutputDirectory` for more information.
|
||||
func SetOutputDirectory(dirPath string) *Client {
|
||||
return DefaultClient.SetOutputDirectory(dirPath)
|
||||
}
|
||||
|
||||
// SetTransport method sets custom `*http.Transport` or any `http.RoundTripper`
|
||||
// compatible interface implementation in the resty client.
|
||||
// See `Client.SetTransport` for more information.
|
||||
func SetTransport(transport http.RoundTripper) *Client {
|
||||
return DefaultClient.SetTransport(transport)
|
||||
}
|
||||
|
||||
// SetScheme method sets custom scheme in the resty client.
|
||||
// See `Client.SetScheme` for more information.
|
||||
func SetScheme(scheme string) *Client {
|
||||
return DefaultClient.SetScheme(scheme)
|
||||
}
|
||||
|
||||
// SetCloseConnection method sets close connection value in the resty client.
|
||||
// See `Client.SetCloseConnection` for more information.
|
||||
func SetCloseConnection(close bool) *Client {
|
||||
return DefaultClient.SetCloseConnection(close)
|
||||
}
|
||||
|
||||
// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
|
||||
// See `Client.SetDoNotParseResponse` for more information.
|
||||
func SetDoNotParseResponse(parse bool) *Client {
|
||||
return DefaultClient.SetDoNotParseResponse(parse)
|
||||
}
|
||||
|
||||
// SetPathParams method sets the Request path parameter key-value pairs. See
|
||||
// `Client.SetPathParams` for more information.
|
||||
func SetPathParams(params map[string]string) *Client {
|
||||
return DefaultClient.SetPathParams(params)
|
||||
}
|
||||
|
||||
// IsProxySet method returns the true if proxy is set on client otherwise false.
|
||||
// See `Client.IsProxySet` for more information.
|
||||
func IsProxySet() bool {
|
||||
return DefaultClient.IsProxySet()
|
||||
}
|
||||
|
||||
// GetClient method returns the current `http.Client` used by the default resty client.
|
||||
func GetClient() *http.Client {
|
||||
return DefaultClient.httpClient
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Unexported methods
|
||||
//___________________________________
|
||||
|
||||
func createClient(hc *http.Client) *Client {
|
||||
c := &Client{
|
||||
HostURL: "",
|
||||
QueryParam: url.Values{},
|
||||
FormData: url.Values{},
|
||||
Header: http.Header{},
|
||||
UserInfo: nil,
|
||||
Token: "",
|
||||
Cookies: make([]*http.Cookie, 0),
|
||||
Debug: false,
|
||||
Log: getLogger(os.Stderr),
|
||||
RetryCount: 0,
|
||||
RetryWaitTime: defaultWaitTime,
|
||||
RetryMaxWaitTime: defaultMaxWaitTime,
|
||||
JSONMarshal: json.Marshal,
|
||||
JSONUnmarshal: json.Unmarshal,
|
||||
jsonEscapeHTML: true,
|
||||
httpClient: hc,
|
||||
debugBodySizeLimit: math.MaxInt32,
|
||||
pathParams: make(map[string]string),
|
||||
}
|
||||
|
||||
// Log Prefix
|
||||
c.SetLogPrefix("RESTY ")
|
||||
|
||||
// Default redirect policy
|
||||
c.SetRedirectPolicy(NoRedirectPolicy())
|
||||
|
||||
// default before request middlewares
|
||||
c.beforeRequest = []func(*Client, *Request) error{
|
||||
parseRequestURL,
|
||||
parseRequestHeader,
|
||||
parseRequestBody,
|
||||
createHTTPRequest,
|
||||
addCredentials,
|
||||
requestLogger,
|
||||
}
|
||||
|
||||
// user defined request middlewares
|
||||
c.udBeforeRequest = []func(*Client, *Request) error{}
|
||||
|
||||
// default after response middlewares
|
||||
c.afterResponse = []func(*Client, *Response) error{
|
||||
responseLogger,
|
||||
parseResponseBody,
|
||||
saveResponseIntoFile,
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func init() {
|
||||
DefaultClient = New()
|
||||
}
|
453
vendor/github.com/go-resty/resty/middleware.go
generated
vendored
Normal file
453
vendor/github.com/go-resty/resty/middleware.go
generated
vendored
Normal file
|
@ -0,0 +1,453 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Request Middleware(s)
|
||||
//___________________________________
|
||||
|
||||
func parseRequestURL(c *Client, r *Request) error {
|
||||
// GitHub #103 Path Params
|
||||
if len(r.pathParams) > 0 {
|
||||
for p, v := range r.pathParams {
|
||||
r.URL = strings.Replace(r.URL, "{"+p+"}", v, -1)
|
||||
}
|
||||
}
|
||||
if len(c.pathParams) > 0 {
|
||||
for p, v := range c.pathParams {
|
||||
r.URL = strings.Replace(r.URL, "{"+p+"}", v, -1)
|
||||
}
|
||||
}
|
||||
|
||||
// Parsing request URL
|
||||
reqURL, err := url.Parse(r.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If Request.URL is relative path then added c.HostURL into
|
||||
// the request URL otherwise Request.URL will be used as-is
|
||||
if !reqURL.IsAbs() {
|
||||
r.URL = reqURL.String()
|
||||
if len(r.URL) > 0 && r.URL[0] != '/' {
|
||||
r.URL = "/" + r.URL
|
||||
}
|
||||
|
||||
reqURL, err = url.Parse(c.HostURL + r.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Adding Query Param
|
||||
query := make(url.Values)
|
||||
for k, v := range c.QueryParam {
|
||||
for _, iv := range v {
|
||||
query.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.QueryParam {
|
||||
// remove query param from client level by key
|
||||
// since overrides happens for that key in the request
|
||||
query.Del(k)
|
||||
|
||||
for _, iv := range v {
|
||||
query.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub #123 Preserve query string order partially.
|
||||
// Since not feasible in `SetQuery*` resty methods, because
|
||||
// standard package `url.Encode(...)` sorts the query params
|
||||
// alphabetically
|
||||
if len(query) > 0 {
|
||||
if IsStringEmpty(reqURL.RawQuery) {
|
||||
reqURL.RawQuery = query.Encode()
|
||||
} else {
|
||||
reqURL.RawQuery = reqURL.RawQuery + "&" + query.Encode()
|
||||
}
|
||||
}
|
||||
|
||||
r.URL = reqURL.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRequestHeader(c *Client, r *Request) error {
|
||||
hdr := make(http.Header)
|
||||
for k := range c.Header {
|
||||
hdr[k] = append(hdr[k], c.Header[k]...)
|
||||
}
|
||||
|
||||
for k := range r.Header {
|
||||
hdr.Del(k)
|
||||
hdr[k] = append(hdr[k], r.Header[k]...)
|
||||
}
|
||||
|
||||
if IsStringEmpty(hdr.Get(hdrUserAgentKey)) {
|
||||
hdr.Set(hdrUserAgentKey, fmt.Sprintf(hdrUserAgentValue, Version))
|
||||
}
|
||||
|
||||
ct := hdr.Get(hdrContentTypeKey)
|
||||
if IsStringEmpty(hdr.Get(hdrAcceptKey)) && !IsStringEmpty(ct) &&
|
||||
(IsJSONType(ct) || IsXMLType(ct)) {
|
||||
hdr.Set(hdrAcceptKey, hdr.Get(hdrContentTypeKey))
|
||||
}
|
||||
|
||||
r.Header = hdr
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRequestBody(c *Client, r *Request) (err error) {
|
||||
if isPayloadSupported(r.Method, c.AllowGetMethodPayload) {
|
||||
// Handling Multipart
|
||||
if r.isMultiPart && !(r.Method == MethodPatch) {
|
||||
if err = handleMultipart(c, r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
goto CL
|
||||
}
|
||||
|
||||
// Handling Form Data
|
||||
if len(c.FormData) > 0 || len(r.FormData) > 0 {
|
||||
handleFormData(c, r)
|
||||
|
||||
goto CL
|
||||
}
|
||||
|
||||
// Handling Request body
|
||||
if r.Body != nil {
|
||||
handleContentType(c, r)
|
||||
|
||||
if err = handleRequestBody(c, r); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CL:
|
||||
// by default resty won't set content length, you can if you want to :)
|
||||
if (c.setContentLength || r.setContentLength) && r.bodyBuf != nil {
|
||||
r.Header.Set(hdrContentLengthKey, fmt.Sprintf("%d", r.bodyBuf.Len()))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func createHTTPRequest(c *Client, r *Request) (err error) {
|
||||
if r.bodyBuf == nil {
|
||||
if reader, ok := r.Body.(io.Reader); ok {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, reader)
|
||||
} else {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, nil)
|
||||
}
|
||||
} else {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, r.bodyBuf)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Assign close connection option
|
||||
r.RawRequest.Close = c.closeConnection
|
||||
|
||||
// Add headers into http request
|
||||
r.RawRequest.Header = r.Header
|
||||
|
||||
// Add cookies into http request
|
||||
for _, cookie := range c.Cookies {
|
||||
r.RawRequest.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// it's for non-http scheme option
|
||||
if r.RawRequest.URL != nil && r.RawRequest.URL.Scheme == "" {
|
||||
r.RawRequest.URL.Scheme = c.scheme
|
||||
r.RawRequest.URL.Host = r.URL
|
||||
}
|
||||
|
||||
// Use context if it was specified
|
||||
r.addContextIfAvailable()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func addCredentials(c *Client, r *Request) error {
|
||||
var isBasicAuth bool
|
||||
// Basic Auth
|
||||
if r.UserInfo != nil { // takes precedence
|
||||
r.RawRequest.SetBasicAuth(r.UserInfo.Username, r.UserInfo.Password)
|
||||
isBasicAuth = true
|
||||
} else if c.UserInfo != nil {
|
||||
r.RawRequest.SetBasicAuth(c.UserInfo.Username, c.UserInfo.Password)
|
||||
isBasicAuth = true
|
||||
}
|
||||
|
||||
if !c.DisableWarn {
|
||||
if isBasicAuth && !strings.HasPrefix(r.URL, "https") {
|
||||
c.Log.Println("WARNING - Using Basic Auth in HTTP mode is not secure.")
|
||||
}
|
||||
}
|
||||
|
||||
// Token Auth
|
||||
if !IsStringEmpty(r.Token) { // takes precedence
|
||||
r.RawRequest.Header.Set(hdrAuthorizationKey, "Bearer "+r.Token)
|
||||
} else if !IsStringEmpty(c.Token) {
|
||||
r.RawRequest.Header.Set(hdrAuthorizationKey, "Bearer "+c.Token)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func requestLogger(c *Client, r *Request) error {
|
||||
if c.Debug {
|
||||
rr := r.RawRequest
|
||||
reqLog := "\n---------------------- REQUEST LOG -----------------------\n" +
|
||||
fmt.Sprintf("%s %s %s\n", r.Method, rr.URL.RequestURI(), rr.Proto) +
|
||||
fmt.Sprintf("HOST : %s\n", rr.URL.Host) +
|
||||
fmt.Sprintf("HEADERS:\n") +
|
||||
composeHeaders(rr.Header) + "\n" +
|
||||
fmt.Sprintf("BODY :\n%v\n", r.fmtBodyString()) +
|
||||
"----------------------------------------------------------\n"
|
||||
|
||||
c.Log.Print(reqLog)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response Middleware(s)
|
||||
//___________________________________
|
||||
|
||||
func responseLogger(c *Client, res *Response) error {
|
||||
if c.Debug {
|
||||
resLog := "\n---------------------- RESPONSE LOG -----------------------\n" +
|
||||
fmt.Sprintf("STATUS : %s\n", res.Status()) +
|
||||
fmt.Sprintf("RECEIVED AT : %v\n", res.ReceivedAt().Format(time.RFC3339Nano)) +
|
||||
fmt.Sprintf("RESPONSE TIME : %v\n", res.Time()) +
|
||||
"HEADERS:\n" +
|
||||
composeHeaders(res.Header()) + "\n"
|
||||
|
||||
if res.Request.isSaveResponse {
|
||||
resLog += fmt.Sprintf("BODY :\n***** RESPONSE WRITTEN INTO FILE *****\n")
|
||||
} else {
|
||||
resLog += fmt.Sprintf("BODY :\n%v\n", res.fmtBodyString(c.debugBodySizeLimit))
|
||||
}
|
||||
resLog += "----------------------------------------------------------\n"
|
||||
|
||||
c.Log.Print(resLog)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseResponseBody(c *Client, res *Response) (err error) {
|
||||
// Handles only JSON or XML content type
|
||||
ct := firstNonEmpty(res.Header().Get(hdrContentTypeKey), res.Request.fallbackContentType)
|
||||
if IsJSONType(ct) || IsXMLType(ct) {
|
||||
// HTTP status code > 199 and < 300, considered as Result
|
||||
if res.IsSuccess() {
|
||||
if res.Request.Result != nil {
|
||||
err = Unmarshalc(c, ct, res.body, res.Request.Result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP status code > 399, considered as Error
|
||||
if res.IsError() {
|
||||
// global error interface
|
||||
if res.Request.Error == nil && c.Error != nil {
|
||||
res.Request.Error = reflect.New(c.Error).Interface()
|
||||
}
|
||||
|
||||
if res.Request.Error != nil {
|
||||
err = Unmarshalc(c, ct, res.body, res.Request.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleMultipart(c *Client, r *Request) (err error) {
|
||||
r.bodyBuf = acquireBuffer()
|
||||
w := multipart.NewWriter(r.bodyBuf)
|
||||
|
||||
for k, v := range c.FormData {
|
||||
for _, iv := range v {
|
||||
if err = w.WriteField(k, iv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.FormData {
|
||||
for _, iv := range v {
|
||||
if strings.HasPrefix(k, "@") { // file
|
||||
err = addFile(w, k[1:], iv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else { // form value
|
||||
if err = w.WriteField(k, iv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #21 - adding io.Reader support
|
||||
if len(r.multipartFiles) > 0 {
|
||||
for _, f := range r.multipartFiles {
|
||||
err = addFileReader(w, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub #130 adding multipart field support with content type
|
||||
if len(r.multipartFields) > 0 {
|
||||
for _, mf := range r.multipartFields {
|
||||
if err = addMultipartFormField(w, mf); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.Header.Set(hdrContentTypeKey, w.FormDataContentType())
|
||||
err = w.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleFormData(c *Client, r *Request) {
|
||||
formData := url.Values{}
|
||||
|
||||
for k, v := range c.FormData {
|
||||
for _, iv := range v {
|
||||
formData.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.FormData {
|
||||
// remove form data field from client level by key
|
||||
// since overrides happens for that key in the request
|
||||
formData.Del(k)
|
||||
|
||||
for _, iv := range v {
|
||||
formData.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
r.bodyBuf = bytes.NewBuffer([]byte(formData.Encode()))
|
||||
r.Header.Set(hdrContentTypeKey, formContentType)
|
||||
r.isFormData = true
|
||||
}
|
||||
|
||||
func handleContentType(c *Client, r *Request) {
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
if IsStringEmpty(contentType) {
|
||||
contentType = DetectContentType(r.Body)
|
||||
r.Header.Set(hdrContentTypeKey, contentType)
|
||||
}
|
||||
}
|
||||
|
||||
func handleRequestBody(c *Client, r *Request) (err error) {
|
||||
var bodyBytes []byte
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
kind := kindOf(r.Body)
|
||||
r.bodyBuf = nil
|
||||
|
||||
if reader, ok := r.Body.(io.Reader); ok {
|
||||
if c.setContentLength || r.setContentLength { // keep backward compability
|
||||
r.bodyBuf = acquireBuffer()
|
||||
_, err = r.bodyBuf.ReadFrom(reader)
|
||||
r.Body = nil
|
||||
} else {
|
||||
// Otherwise buffer less processing for `io.Reader`, sounds good.
|
||||
return
|
||||
}
|
||||
} else if b, ok := r.Body.([]byte); ok {
|
||||
bodyBytes = b
|
||||
} else if s, ok := r.Body.(string); ok {
|
||||
bodyBytes = []byte(s)
|
||||
} else if IsJSONType(contentType) &&
|
||||
(kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice) {
|
||||
bodyBytes, err = jsonMarshal(c, r, r.Body)
|
||||
} else if IsXMLType(contentType) && (kind == reflect.Struct) {
|
||||
bodyBytes, err = xml.Marshal(r.Body)
|
||||
}
|
||||
|
||||
if bodyBytes == nil && r.bodyBuf == nil {
|
||||
err = errors.New("unsupported 'Body' type/value")
|
||||
}
|
||||
|
||||
// if any errors during body bytes handling, return it
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// []byte into Buffer
|
||||
if bodyBytes != nil && r.bodyBuf == nil {
|
||||
r.bodyBuf = acquireBuffer()
|
||||
_, _ = r.bodyBuf.Write(bodyBytes)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func saveResponseIntoFile(c *Client, res *Response) error {
|
||||
if res.Request.isSaveResponse {
|
||||
file := ""
|
||||
|
||||
if len(c.outputDirectory) > 0 && !filepath.IsAbs(res.Request.outputFile) {
|
||||
file += c.outputDirectory + string(filepath.Separator)
|
||||
}
|
||||
|
||||
file = filepath.Clean(file + res.Request.outputFile)
|
||||
if err := createDirectory(filepath.Dir(file)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outFile, err := os.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeq(outFile)
|
||||
|
||||
// io.Copy reads maximum 32kb size, it is perfect for large file download too
|
||||
defer closeq(res.RawResponse.Body)
|
||||
|
||||
written, err := io.Copy(outFile, res.RawResponse.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.size = written
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
99
vendor/github.com/go-resty/resty/redirect.go
generated
vendored
Normal file
99
vendor/github.com/go-resty/resty/redirect.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// RedirectPolicy to regulate the redirects in the resty client.
|
||||
// Objects implementing the RedirectPolicy interface can be registered as
|
||||
//
|
||||
// Apply function should return nil to continue the redirect jounery, otherwise
|
||||
// return error to stop the redirect.
|
||||
RedirectPolicy interface {
|
||||
Apply(req *http.Request, via []*http.Request) error
|
||||
}
|
||||
|
||||
// The RedirectPolicyFunc type is an adapter to allow the use of ordinary functions as RedirectPolicy.
|
||||
// If f is a function with the appropriate signature, RedirectPolicyFunc(f) is a RedirectPolicy object that calls f.
|
||||
RedirectPolicyFunc func(*http.Request, []*http.Request) error
|
||||
)
|
||||
|
||||
// Apply calls f(req, via).
|
||||
func (f RedirectPolicyFunc) Apply(req *http.Request, via []*http.Request) error {
|
||||
return f(req, via)
|
||||
}
|
||||
|
||||
// NoRedirectPolicy is used to disable redirects in the HTTP client
|
||||
// resty.SetRedirectPolicy(NoRedirectPolicy())
|
||||
func NoRedirectPolicy() RedirectPolicy {
|
||||
return RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
return errors.New("auto redirect is disabled")
|
||||
})
|
||||
}
|
||||
|
||||
// FlexibleRedirectPolicy is convenient method to create No of redirect policy for HTTP client.
|
||||
// resty.SetRedirectPolicy(FlexibleRedirectPolicy(20))
|
||||
func FlexibleRedirectPolicy(noOfRedirect int) RedirectPolicy {
|
||||
return RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
if len(via) >= noOfRedirect {
|
||||
return fmt.Errorf("stopped after %d redirects", noOfRedirect)
|
||||
}
|
||||
|
||||
checkHostAndAddHeaders(req, via[0])
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DomainCheckRedirectPolicy is convenient method to define domain name redirect rule in resty client.
|
||||
// Redirect is allowed for only mentioned host in the policy.
|
||||
// resty.SetRedirectPolicy(DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
|
||||
func DomainCheckRedirectPolicy(hostnames ...string) RedirectPolicy {
|
||||
hosts := make(map[string]bool)
|
||||
for _, h := range hostnames {
|
||||
hosts[strings.ToLower(h)] = true
|
||||
}
|
||||
|
||||
fn := RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
if ok := hosts[getHostname(req.URL.Host)]; !ok {
|
||||
return errors.New("redirect is not allowed as per DomainCheckRedirectPolicy")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
func getHostname(host string) (hostname string) {
|
||||
if strings.Index(host, ":") > 0 {
|
||||
host, _, _ = net.SplitHostPort(host)
|
||||
}
|
||||
hostname = strings.ToLower(host)
|
||||
return
|
||||
}
|
||||
|
||||
// By default Golang will not redirect request headers
|
||||
// after go throughing various discussion comments from thread
|
||||
// https://github.com/golang/go/issues/4800
|
||||
// go-resty will add all the headers during a redirect for the same host
|
||||
func checkHostAndAddHeaders(cur *http.Request, pre *http.Request) {
|
||||
curHostname := getHostname(cur.URL.Host)
|
||||
preHostname := getHostname(pre.URL.Host)
|
||||
if strings.EqualFold(curHostname, preHostname) {
|
||||
for key, val := range pre.Header {
|
||||
cur.Header[key] = val
|
||||
}
|
||||
} else { // only library User-Agent header is added
|
||||
cur.Header.Set(hdrUserAgentKey, fmt.Sprintf(hdrUserAgentValue, Version))
|
||||
}
|
||||
}
|
566
vendor/github.com/go-resty/resty/request.go
generated
vendored
Normal file
566
vendor/github.com/go-resty/resty/request.go
generated
vendored
Normal file
|
@ -0,0 +1,566 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SRVRecord holds the data to query the SRV record for the following service
|
||||
type SRVRecord struct {
|
||||
Service string
|
||||
Domain string
|
||||
}
|
||||
|
||||
// SetHeader method is to set a single header field and its value in the current request.
|
||||
// Example: To set `Content-Type` and `Accept` as `application/json`.
|
||||
// resty.R().
|
||||
// SetHeader("Content-Type", "application/json").
|
||||
// SetHeader("Accept", "application/json")
|
||||
//
|
||||
// Also you can override header value, which was set at client instance level.
|
||||
//
|
||||
func (r *Request) SetHeader(header, value string) *Request {
|
||||
r.Header.Set(header, value)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetHeaders method sets multiple headers field and its values at one go in the current request.
|
||||
// Example: To set `Content-Type` and `Accept` as `application/json`
|
||||
//
|
||||
// resty.R().
|
||||
// SetHeaders(map[string]string{
|
||||
// "Content-Type": "application/json",
|
||||
// "Accept": "application/json",
|
||||
// })
|
||||
// Also you can override header value, which was set at client instance level.
|
||||
//
|
||||
func (r *Request) SetHeaders(headers map[string]string) *Request {
|
||||
for h, v := range headers {
|
||||
r.SetHeader(h, v)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryParam method sets single parameter and its value in the current request.
|
||||
// It will be formed as query string for the request.
|
||||
// Example: `search=kitchen%20papers&size=large` in the URL after `?` mark.
|
||||
// resty.R().
|
||||
// SetQueryParam("search", "kitchen papers").
|
||||
// SetQueryParam("size", "large")
|
||||
// Also you can override query params value, which was set at client instance level
|
||||
//
|
||||
func (r *Request) SetQueryParam(param, value string) *Request {
|
||||
r.QueryParam.Set(param, value)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryParams method sets multiple parameters and its values at one go in the current request.
|
||||
// It will be formed as query string for the request.
|
||||
// Example: `search=kitchen%20papers&size=large` in the URL after `?` mark.
|
||||
// resty.R().
|
||||
// SetQueryParams(map[string]string{
|
||||
// "search": "kitchen papers",
|
||||
// "size": "large",
|
||||
// })
|
||||
// Also you can override query params value, which was set at client instance level
|
||||
//
|
||||
func (r *Request) SetQueryParams(params map[string]string) *Request {
|
||||
for p, v := range params {
|
||||
r.SetQueryParam(p, v)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetMultiValueQueryParams method appends multiple parameters with multi-value
|
||||
// at one go in the current request. It will be formed as query string for the request.
|
||||
// Example: `status=pending&status=approved&status=open` in the URL after `?` mark.
|
||||
// resty.R().
|
||||
// SetMultiValueQueryParams(url.Values{
|
||||
// "status": []string{"pending", "approved", "open"},
|
||||
// })
|
||||
// Also you can override query params value, which was set at client instance level
|
||||
//
|
||||
func (r *Request) SetMultiValueQueryParams(params url.Values) *Request {
|
||||
for p, v := range params {
|
||||
for _, pv := range v {
|
||||
r.QueryParam.Add(p, pv)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryString method provides ability to use string as an input to set URL query string for the request.
|
||||
//
|
||||
// Using String as an input
|
||||
// resty.R().
|
||||
// SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")
|
||||
//
|
||||
func (r *Request) SetQueryString(query string) *Request {
|
||||
params, err := url.ParseQuery(strings.TrimSpace(query))
|
||||
if err == nil {
|
||||
for p, v := range params {
|
||||
for _, pv := range v {
|
||||
r.QueryParam.Add(p, pv)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.client.Log.Printf("ERROR %v", err)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFormData method sets Form parameters and their values in the current request.
|
||||
// It's applicable only HTTP method `POST` and `PUT` and requests content type would be set as
|
||||
// `application/x-www-form-urlencoded`.
|
||||
// resty.R().
|
||||
// SetFormData(map[string]string{
|
||||
// "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
|
||||
// "user_id": "3455454545",
|
||||
// })
|
||||
// Also you can override form data value, which was set at client instance level
|
||||
//
|
||||
func (r *Request) SetFormData(data map[string]string) *Request {
|
||||
for k, v := range data {
|
||||
r.FormData.Set(k, v)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetMultiValueFormData method appends multiple form parameters with multi-value
|
||||
// at one go in the current request.
|
||||
// resty.R().
|
||||
// SetMultiValueFormData(url.Values{
|
||||
// "search_criteria": []string{"book", "glass", "pencil"},
|
||||
// })
|
||||
// Also you can override form data value, which was set at client instance level
|
||||
//
|
||||
func (r *Request) SetMultiValueFormData(params url.Values) *Request {
|
||||
for k, v := range params {
|
||||
for _, kv := range v {
|
||||
r.FormData.Add(k, kv)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetBody method sets the request body for the request. It supports various realtime need easy.
|
||||
// We can say its quite handy or powerful. Supported request body data types is `string`, `[]byte`,
|
||||
// `struct` and `map`. Body value can be pointer or non-pointer. Automatic marshalling
|
||||
// for JSON and XML content type, if it is `struct` or `map`.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Struct as a body input, based on content type, it will be marshalled.
|
||||
// resty.R().
|
||||
// SetBody(User{
|
||||
// Username: "jeeva@myjeeva.com",
|
||||
// Password: "welcome2resty",
|
||||
// })
|
||||
//
|
||||
// Map as a body input, based on content type, it will be marshalled.
|
||||
// resty.R().
|
||||
// SetBody(map[string]interface{}{
|
||||
// "username": "jeeva@myjeeva.com",
|
||||
// "password": "welcome2resty",
|
||||
// "address": &Address{
|
||||
// Address1: "1111 This is my street",
|
||||
// Address2: "Apt 201",
|
||||
// City: "My City",
|
||||
// State: "My State",
|
||||
// ZipCode: 00000,
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// String as a body input. Suitable for any need as a string input.
|
||||
// resty.R().
|
||||
// SetBody(`{
|
||||
// "username": "jeeva@getrightcare.com",
|
||||
// "password": "admin"
|
||||
// }`)
|
||||
//
|
||||
// []byte as a body input. Suitable for raw request such as file upload, serialize & deserialize, etc.
|
||||
// resty.R().
|
||||
// SetBody([]byte("This is my raw request, sent as-is"))
|
||||
//
|
||||
func (r *Request) SetBody(body interface{}) *Request {
|
||||
r.Body = body
|
||||
return r
|
||||
}
|
||||
|
||||
// SetResult method is to register the response `Result` object for automatic unmarshalling in the RESTful mode
|
||||
// if response status code is between 200 and 299 and content type either JSON or XML.
|
||||
//
|
||||
// Note: Result object can be pointer or non-pointer.
|
||||
// resty.R().SetResult(&AuthToken{})
|
||||
// // OR
|
||||
// resty.R().SetResult(AuthToken{})
|
||||
//
|
||||
// Accessing a result value
|
||||
// response.Result().(*AuthToken)
|
||||
//
|
||||
func (r *Request) SetResult(res interface{}) *Request {
|
||||
r.Result = getPointer(res)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetError method is to register the request `Error` object for automatic unmarshalling in the RESTful mode
|
||||
// if response status code is greater than 399 and content type either JSON or XML.
|
||||
//
|
||||
// Note: Error object can be pointer or non-pointer.
|
||||
// resty.R().SetError(&AuthError{})
|
||||
// // OR
|
||||
// resty.R().SetError(AuthError{})
|
||||
//
|
||||
// Accessing a error value
|
||||
// response.Error().(*AuthError)
|
||||
//
|
||||
func (r *Request) SetError(err interface{}) *Request {
|
||||
r.Error = getPointer(err)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFile method is to set single file field name and its path for multipart upload.
|
||||
// resty.R().
|
||||
// SetFile("my_file", "/Users/jeeva/Gas Bill - Sep.pdf")
|
||||
//
|
||||
func (r *Request) SetFile(param, filePath string) *Request {
|
||||
r.isMultiPart = true
|
||||
r.FormData.Set("@"+param, filePath)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFiles method is to set multiple file field name and its path for multipart upload.
|
||||
// resty.R().
|
||||
// SetFiles(map[string]string{
|
||||
// "my_file1": "/Users/jeeva/Gas Bill - Sep.pdf",
|
||||
// "my_file2": "/Users/jeeva/Electricity Bill - Sep.pdf",
|
||||
// "my_file3": "/Users/jeeva/Water Bill - Sep.pdf",
|
||||
// })
|
||||
//
|
||||
func (r *Request) SetFiles(files map[string]string) *Request {
|
||||
r.isMultiPart = true
|
||||
|
||||
for f, fp := range files {
|
||||
r.FormData.Set("@"+f, fp)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFileReader method is to set single file using io.Reader for multipart upload.
|
||||
// resty.R().
|
||||
// SetFileReader("profile_img", "my-profile-img.png", bytes.NewReader(profileImgBytes)).
|
||||
// SetFileReader("notes", "user-notes.txt", bytes.NewReader(notesBytes))
|
||||
//
|
||||
func (r *Request) SetFileReader(param, fileName string, reader io.Reader) *Request {
|
||||
r.isMultiPart = true
|
||||
|
||||
r.multipartFiles = append(r.multipartFiles, &File{
|
||||
Name: fileName,
|
||||
ParamName: param,
|
||||
Reader: reader,
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetMultipartField method is to set custom data using io.Reader for multipart upload.
|
||||
func (r *Request) SetMultipartField(param, fileName, contentType string, reader io.Reader) *Request {
|
||||
r.isMultiPart = true
|
||||
|
||||
r.multipartFields = append(r.multipartFields, &multipartField{
|
||||
Param: param,
|
||||
FileName: fileName,
|
||||
ContentType: contentType,
|
||||
Reader: reader,
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetContentLength method sets the HTTP header `Content-Length` value for current request.
|
||||
// By default go-resty won't set `Content-Length`. Also you have an option to enable for every
|
||||
// request. See `resty.SetContentLength`
|
||||
// resty.R().SetContentLength(true)
|
||||
//
|
||||
func (r *Request) SetContentLength(l bool) *Request {
|
||||
r.setContentLength = true
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetBasicAuth method sets the basic authentication header in the current HTTP request.
|
||||
// For Header example:
|
||||
// Authorization: Basic <base64-encoded-value>
|
||||
//
|
||||
// To set the header for username "go-resty" and password "welcome"
|
||||
// resty.R().SetBasicAuth("go-resty", "welcome")
|
||||
//
|
||||
// This method overrides the credentials set by method `resty.SetBasicAuth`.
|
||||
//
|
||||
func (r *Request) SetBasicAuth(username, password string) *Request {
|
||||
r.UserInfo = &User{Username: username, Password: password}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetAuthToken method sets bearer auth token header in the current HTTP request. Header example:
|
||||
// Authorization: Bearer <auth-token-value-comes-here>
|
||||
//
|
||||
// Example: To set auth token BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F
|
||||
//
|
||||
// resty.R().SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
|
||||
//
|
||||
// This method overrides the Auth token set by method `resty.SetAuthToken`.
|
||||
//
|
||||
func (r *Request) SetAuthToken(token string) *Request {
|
||||
r.Token = token
|
||||
return r
|
||||
}
|
||||
|
||||
// SetOutput method sets the output file for current HTTP request. Current HTTP response will be
|
||||
// saved into given file. It is similar to `curl -o` flag. Absolute path or relative path can be used.
|
||||
// If is it relative path then output file goes under the output directory, as mentioned
|
||||
// in the `Client.SetOutputDirectory`.
|
||||
// resty.R().
|
||||
// SetOutput("/Users/jeeva/Downloads/ReplyWithHeader-v5.1-beta.zip").
|
||||
// Get("http://bit.ly/1LouEKr")
|
||||
//
|
||||
// Note: In this scenario `Response.Body` might be nil.
|
||||
func (r *Request) SetOutput(file string) *Request {
|
||||
r.outputFile = file
|
||||
r.isSaveResponse = true
|
||||
return r
|
||||
}
|
||||
|
||||
// SetSRV method sets the details to query the service SRV record and execute the
|
||||
// request.
|
||||
// resty.R().
|
||||
// SetSRV(SRVRecord{"web", "testservice.com"}).
|
||||
// Get("/get")
|
||||
func (r *Request) SetSRV(srv *SRVRecord) *Request {
|
||||
r.SRV = srv
|
||||
return r
|
||||
}
|
||||
|
||||
// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
|
||||
// Resty exposes the raw response body as `io.ReadCloser`. Also do not forget to close the body,
|
||||
// otherwise you might get into connection leaks, no connection reuse.
|
||||
//
|
||||
// Please Note: Response middlewares are not applicable, if you use this option. Basically you have
|
||||
// taken over the control of response parsing from `Resty`.
|
||||
func (r *Request) SetDoNotParseResponse(parse bool) *Request {
|
||||
r.notParseResponse = parse
|
||||
return r
|
||||
}
|
||||
|
||||
// SetPathParams method sets multiple URL path key-value pairs at one go in the
|
||||
// resty current request instance.
|
||||
// resty.R().SetPathParams(map[string]string{
|
||||
// "userId": "sample@sample.com",
|
||||
// "subAccountId": "100002",
|
||||
// })
|
||||
//
|
||||
// Result:
|
||||
// URL - /v1/users/{userId}/{subAccountId}/details
|
||||
// Composed URL - /v1/users/sample@sample.com/100002/details
|
||||
// It replace the value of the key while composing request URL. Also you can
|
||||
// override Path Params value, which was set at client instance level.
|
||||
func (r *Request) SetPathParams(params map[string]string) *Request {
|
||||
for p, v := range params {
|
||||
r.pathParams[p] = v
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ExpectContentType method allows to provide fallback `Content-Type` for automatic unmarshalling
|
||||
// when `Content-Type` response header is unavailable.
|
||||
func (r *Request) ExpectContentType(contentType string) *Request {
|
||||
r.fallbackContentType = contentType
|
||||
return r
|
||||
}
|
||||
|
||||
// SetJSONEscapeHTML method is to enable/disable the HTML escape on JSON marshal.
|
||||
//
|
||||
// NOTE: This option only applicable to standard JSON Marshaller.
|
||||
func (r *Request) SetJSONEscapeHTML(b bool) *Request {
|
||||
r.jsonEscapeHTML = b
|
||||
return r
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// HTTP verb method starts here
|
||||
//___________________________________
|
||||
|
||||
// Get method does GET HTTP request. It's defined in section 4.3.1 of RFC7231.
|
||||
func (r *Request) Get(url string) (*Response, error) {
|
||||
return r.Execute(MethodGet, url)
|
||||
}
|
||||
|
||||
// Head method does HEAD HTTP request. It's defined in section 4.3.2 of RFC7231.
|
||||
func (r *Request) Head(url string) (*Response, error) {
|
||||
return r.Execute(MethodHead, url)
|
||||
}
|
||||
|
||||
// Post method does POST HTTP request. It's defined in section 4.3.3 of RFC7231.
|
||||
func (r *Request) Post(url string) (*Response, error) {
|
||||
return r.Execute(MethodPost, url)
|
||||
}
|
||||
|
||||
// Put method does PUT HTTP request. It's defined in section 4.3.4 of RFC7231.
|
||||
func (r *Request) Put(url string) (*Response, error) {
|
||||
return r.Execute(MethodPut, url)
|
||||
}
|
||||
|
||||
// Delete method does DELETE HTTP request. It's defined in section 4.3.5 of RFC7231.
|
||||
func (r *Request) Delete(url string) (*Response, error) {
|
||||
return r.Execute(MethodDelete, url)
|
||||
}
|
||||
|
||||
// Options method does OPTIONS HTTP request. It's defined in section 4.3.7 of RFC7231.
|
||||
func (r *Request) Options(url string) (*Response, error) {
|
||||
return r.Execute(MethodOptions, url)
|
||||
}
|
||||
|
||||
// Patch method does PATCH HTTP request. It's defined in section 2 of RFC5789.
|
||||
func (r *Request) Patch(url string) (*Response, error) {
|
||||
return r.Execute(MethodPatch, url)
|
||||
}
|
||||
|
||||
// Execute method performs the HTTP request with given HTTP method and URL
|
||||
// for current `Request`.
|
||||
// resp, err := resty.R().Execute(resty.GET, "http://httpbin.org/get")
|
||||
//
|
||||
func (r *Request) Execute(method, url string) (*Response, error) {
|
||||
var addrs []*net.SRV
|
||||
var err error
|
||||
|
||||
if r.isMultiPart && !(method == MethodPost || method == MethodPut) {
|
||||
return nil, fmt.Errorf("multipart content is not allowed in HTTP verb [%v]", method)
|
||||
}
|
||||
|
||||
if r.SRV != nil {
|
||||
_, addrs, err = net.LookupSRV(r.SRV.Service, "tcp", r.SRV.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
r.Method = method
|
||||
r.URL = r.selectAddr(addrs, url, 0)
|
||||
|
||||
if r.client.RetryCount == 0 {
|
||||
return r.client.execute(r)
|
||||
}
|
||||
|
||||
var resp *Response
|
||||
attempt := 0
|
||||
_ = Backoff(
|
||||
func() (*Response, error) {
|
||||
attempt++
|
||||
|
||||
r.URL = r.selectAddr(addrs, url, attempt)
|
||||
|
||||
resp, err = r.client.execute(r)
|
||||
if err != nil {
|
||||
r.client.Log.Printf("ERROR %v, Attempt %v", err, attempt)
|
||||
if r.isContextCancelledIfAvailable() {
|
||||
// stop Backoff from retrying request if request has been
|
||||
// canceled by context
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
},
|
||||
Retries(r.client.RetryCount),
|
||||
WaitTime(r.client.RetryWaitTime),
|
||||
MaxWaitTime(r.client.RetryMaxWaitTime),
|
||||
RetryConditions(r.client.RetryConditions),
|
||||
)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Request Unexported methods
|
||||
//___________________________________
|
||||
|
||||
func (r *Request) fmtBodyString() (body string) {
|
||||
body = "***** NO CONTENT *****"
|
||||
if isPayloadSupported(r.Method, r.client.AllowGetMethodPayload) {
|
||||
if _, ok := r.Body.(io.Reader); ok {
|
||||
body = "***** BODY IS io.Reader *****"
|
||||
return
|
||||
}
|
||||
|
||||
// multipart or form-data
|
||||
if r.isMultiPart || r.isFormData {
|
||||
body = r.bodyBuf.String()
|
||||
return
|
||||
}
|
||||
|
||||
// request body data
|
||||
if r.Body == nil {
|
||||
return
|
||||
}
|
||||
var prtBodyBytes []byte
|
||||
var err error
|
||||
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
kind := kindOf(r.Body)
|
||||
if canJSONMarshal(contentType, kind) {
|
||||
prtBodyBytes, err = json.MarshalIndent(&r.Body, "", " ")
|
||||
} else if IsXMLType(contentType) && (kind == reflect.Struct) {
|
||||
prtBodyBytes, err = xml.MarshalIndent(&r.Body, "", " ")
|
||||
} else if b, ok := r.Body.(string); ok {
|
||||
if IsJSONType(contentType) {
|
||||
bodyBytes := []byte(b)
|
||||
out := acquireBuffer()
|
||||
defer releaseBuffer(out)
|
||||
if err = json.Indent(out, bodyBytes, "", " "); err == nil {
|
||||
prtBodyBytes = out.Bytes()
|
||||
}
|
||||
} else {
|
||||
body = b
|
||||
return
|
||||
}
|
||||
} else if b, ok := r.Body.([]byte); ok {
|
||||
body = base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
if prtBodyBytes != nil && err == nil {
|
||||
body = string(prtBodyBytes)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Request) selectAddr(addrs []*net.SRV, path string, attempt int) string {
|
||||
if addrs == nil {
|
||||
return path
|
||||
}
|
||||
|
||||
idx := attempt % len(addrs)
|
||||
domain := strings.TrimRight(addrs[idx].Target, ".")
|
||||
path = strings.TrimLeft(path, "/")
|
||||
|
||||
return fmt.Sprintf("%s://%s:%d/%s", r.client.scheme, domain, addrs[idx].Port, path)
|
||||
}
|
63
vendor/github.com/go-resty/resty/request16.go
generated
vendored
Normal file
63
vendor/github.com/go-resty/resty/request16.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
// +build !go1.7
|
||||
|
||||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com)
|
||||
// 2016 Andrew Grigorev (https://github.com/ei-grad)
|
||||
// All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Request type is used to compose and send individual request from client
|
||||
// go-resty is provide option override client level settings such as
|
||||
// Auth Token, Basic Auth credentials, Header, Query Param, Form Data, Error object
|
||||
// and also you can add more options for that particular request
|
||||
type Request struct {
|
||||
URL string
|
||||
Method string
|
||||
Token string
|
||||
QueryParam url.Values
|
||||
FormData url.Values
|
||||
Header http.Header
|
||||
Time time.Time
|
||||
Body interface{}
|
||||
Result interface{}
|
||||
Error interface{}
|
||||
RawRequest *http.Request
|
||||
SRV *SRVRecord
|
||||
UserInfo *User
|
||||
|
||||
isMultiPart bool
|
||||
isFormData bool
|
||||
setContentLength bool
|
||||
isSaveResponse bool
|
||||
notParseResponse bool
|
||||
jsonEscapeHTML bool
|
||||
outputFile string
|
||||
fallbackContentType string
|
||||
pathParams map[string]string
|
||||
client *Client
|
||||
bodyBuf *bytes.Buffer
|
||||
multipartFiles []*File
|
||||
multipartFields []*multipartField
|
||||
}
|
||||
|
||||
func (r *Request) addContextIfAvailable() {
|
||||
// nothing to do for golang<1.7
|
||||
}
|
||||
|
||||
func (r *Request) isContextCancelledIfAvailable() bool {
|
||||
// just always return false golang<1.7
|
||||
return false
|
||||
}
|
||||
|
||||
// for !go1.7
|
||||
var noescapeJSONMarshal = json.Marshal
|
87
vendor/github.com/go-resty/resty/request17.go
generated
vendored
Normal file
87
vendor/github.com/go-resty/resty/request17.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
// +build go1.7 go1.8
|
||||
|
||||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com)
|
||||
// 2016 Andrew Grigorev (https://github.com/ei-grad)
|
||||
// All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Request type is used to compose and send individual request from client
|
||||
// go-resty is provide option override client level settings such as
|
||||
// Auth Token, Basic Auth credentials, Header, Query Param, Form Data, Error object
|
||||
// and also you can add more options for that particular request
|
||||
type Request struct {
|
||||
URL string
|
||||
Method string
|
||||
Token string
|
||||
QueryParam url.Values
|
||||
FormData url.Values
|
||||
Header http.Header
|
||||
Time time.Time
|
||||
Body interface{}
|
||||
Result interface{}
|
||||
Error interface{}
|
||||
RawRequest *http.Request
|
||||
SRV *SRVRecord
|
||||
UserInfo *User
|
||||
|
||||
isMultiPart bool
|
||||
isFormData bool
|
||||
setContentLength bool
|
||||
isSaveResponse bool
|
||||
notParseResponse bool
|
||||
jsonEscapeHTML bool
|
||||
outputFile string
|
||||
fallbackContentType string
|
||||
ctx context.Context
|
||||
pathParams map[string]string
|
||||
client *Client
|
||||
bodyBuf *bytes.Buffer
|
||||
multipartFiles []*File
|
||||
multipartFields []*multipartField
|
||||
}
|
||||
|
||||
// SetContext method sets the context.Context for current Request. It allows
|
||||
// to interrupt the request execution if ctx.Done() channel is closed.
|
||||
// See https://blog.golang.org/context article and the "context" package
|
||||
// documentation.
|
||||
func (r *Request) SetContext(ctx context.Context) *Request {
|
||||
r.ctx = ctx
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) addContextIfAvailable() {
|
||||
if r.ctx != nil {
|
||||
r.RawRequest = r.RawRequest.WithContext(r.ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) isContextCancelledIfAvailable() bool {
|
||||
if r.ctx != nil {
|
||||
if r.ctx.Err() != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// for go1.7+
|
||||
var noescapeJSONMarshal = func(v interface{}) ([]byte, error) {
|
||||
buf := acquireBuffer()
|
||||
defer releaseBuffer(buf)
|
||||
encoder := json.NewEncoder(buf)
|
||||
encoder.SetEscapeHTML(false)
|
||||
err := encoder.Encode(v)
|
||||
return buf.Bytes(), err
|
||||
}
|
150
vendor/github.com/go-resty/resty/response.go
generated
vendored
Normal file
150
vendor/github.com/go-resty/resty/response.go
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Response is an object represents executed request and its values.
|
||||
type Response struct {
|
||||
Request *Request
|
||||
RawResponse *http.Response
|
||||
|
||||
body []byte
|
||||
size int64
|
||||
receivedAt time.Time
|
||||
}
|
||||
|
||||
// Body method returns HTTP response as []byte array for the executed request.
|
||||
// Note: `Response.Body` might be nil, if `Request.SetOutput` is used.
|
||||
func (r *Response) Body() []byte {
|
||||
if r.RawResponse == nil {
|
||||
return []byte{}
|
||||
}
|
||||
return r.body
|
||||
}
|
||||
|
||||
// Status method returns the HTTP status string for the executed request.
|
||||
// Example: 200 OK
|
||||
func (r *Response) Status() string {
|
||||
if r.RawResponse == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return r.RawResponse.Status
|
||||
}
|
||||
|
||||
// StatusCode method returns the HTTP status code for the executed request.
|
||||
// Example: 200
|
||||
func (r *Response) StatusCode() int {
|
||||
if r.RawResponse == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.RawResponse.StatusCode
|
||||
}
|
||||
|
||||
// Result method returns the response value as an object if it has one
|
||||
func (r *Response) Result() interface{} {
|
||||
return r.Request.Result
|
||||
}
|
||||
|
||||
// Error method returns the error object if it has one
|
||||
func (r *Response) Error() interface{} {
|
||||
return r.Request.Error
|
||||
}
|
||||
|
||||
// Header method returns the response headers
|
||||
func (r *Response) Header() http.Header {
|
||||
if r.RawResponse == nil {
|
||||
return http.Header{}
|
||||
}
|
||||
|
||||
return r.RawResponse.Header
|
||||
}
|
||||
|
||||
// Cookies method to access all the response cookies
|
||||
func (r *Response) Cookies() []*http.Cookie {
|
||||
if r.RawResponse == nil {
|
||||
return make([]*http.Cookie, 0)
|
||||
}
|
||||
|
||||
return r.RawResponse.Cookies()
|
||||
}
|
||||
|
||||
// String method returns the body of the server response as String.
|
||||
func (r *Response) String() string {
|
||||
if r.body == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(r.body))
|
||||
}
|
||||
|
||||
// Time method returns the time of HTTP response time that from request we sent and received a request.
|
||||
// See `response.ReceivedAt` to know when client recevied response and see `response.Request.Time` to know
|
||||
// when client sent a request.
|
||||
func (r *Response) Time() time.Duration {
|
||||
return r.receivedAt.Sub(r.Request.Time)
|
||||
}
|
||||
|
||||
// ReceivedAt method returns when response got recevied from server for the request.
|
||||
func (r *Response) ReceivedAt() time.Time {
|
||||
return r.receivedAt
|
||||
}
|
||||
|
||||
// Size method returns the HTTP response size in bytes. Ya, you can relay on HTTP `Content-Length` header,
|
||||
// however it won't be good for chucked transfer/compressed response. Since Resty calculates response size
|
||||
// at the client end. You will get actual size of the http response.
|
||||
func (r *Response) Size() int64 {
|
||||
return r.size
|
||||
}
|
||||
|
||||
// RawBody method exposes the HTTP raw response body. Use this method in-conjunction with `SetDoNotParseResponse`
|
||||
// option otherwise you get an error as `read err: http: read on closed response body`.
|
||||
//
|
||||
// Do not forget to close the body, otherwise you might get into connection leaks, no connection reuse.
|
||||
// Basically you have taken over the control of response parsing from `Resty`.
|
||||
func (r *Response) RawBody() io.ReadCloser {
|
||||
if r.RawResponse == nil {
|
||||
return nil
|
||||
}
|
||||
return r.RawResponse.Body
|
||||
}
|
||||
|
||||
// IsSuccess method returns true if HTTP status code >= 200 and <= 299 otherwise false.
|
||||
func (r *Response) IsSuccess() bool {
|
||||
return r.StatusCode() > 199 && r.StatusCode() < 300
|
||||
}
|
||||
|
||||
// IsError method returns true if HTTP status code >= 400 otherwise false.
|
||||
func (r *Response) IsError() bool {
|
||||
return r.StatusCode() > 399
|
||||
}
|
||||
|
||||
func (r *Response) fmtBodyString(sl int64) string {
|
||||
if r.body != nil {
|
||||
if int64(len(r.body)) > sl {
|
||||
return fmt.Sprintf("***** RESPONSE TOO LARGE (size - %d) *****", len(r.body))
|
||||
}
|
||||
ct := r.Header().Get(hdrContentTypeKey)
|
||||
if IsJSONType(ct) {
|
||||
out := acquireBuffer()
|
||||
defer releaseBuffer(out)
|
||||
if err := json.Indent(out, r.body, "", " "); err == nil {
|
||||
return out.String()
|
||||
}
|
||||
}
|
||||
return r.String()
|
||||
}
|
||||
|
||||
return "***** NO CONTENT *****"
|
||||
}
|
9
vendor/github.com/go-resty/resty/resty.go
generated
vendored
Normal file
9
vendor/github.com/go-resty/resty/resty.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
|
||||
package resty
|
||||
|
||||
// Version # of resty
|
||||
const Version = "1.9.1"
|
114
vendor/github.com/go-resty/resty/retry.go
generated
vendored
Normal file
114
vendor/github.com/go-resty/resty/retry.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxRetries = 3
|
||||
defaultWaitTime = time.Duration(100) * time.Millisecond
|
||||
defaultMaxWaitTime = time.Duration(2000) * time.Millisecond
|
||||
)
|
||||
|
||||
type (
|
||||
// Option is to create convenient retry options like wait time, max retries, etc.
|
||||
Option func(*Options)
|
||||
|
||||
// RetryConditionFunc type is for retry condition function
|
||||
RetryConditionFunc func(*Response) (bool, error)
|
||||
|
||||
// Options to hold go-resty retry values
|
||||
Options struct {
|
||||
maxRetries int
|
||||
waitTime time.Duration
|
||||
maxWaitTime time.Duration
|
||||
retryConditions []RetryConditionFunc
|
||||
}
|
||||
)
|
||||
|
||||
// Retries sets the max number of retries
|
||||
func Retries(value int) Option {
|
||||
return func(o *Options) {
|
||||
o.maxRetries = value
|
||||
}
|
||||
}
|
||||
|
||||
// WaitTime sets the default wait time to sleep between requests
|
||||
func WaitTime(value time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.waitTime = value
|
||||
}
|
||||
}
|
||||
|
||||
// MaxWaitTime sets the max wait time to sleep between requests
|
||||
func MaxWaitTime(value time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.maxWaitTime = value
|
||||
}
|
||||
}
|
||||
|
||||
// RetryConditions sets the conditions that will be checked for retry.
|
||||
func RetryConditions(conditions []RetryConditionFunc) Option {
|
||||
return func(o *Options) {
|
||||
o.retryConditions = conditions
|
||||
}
|
||||
}
|
||||
|
||||
// Backoff retries with increasing timeout duration up until X amount of retries
|
||||
// (Default is 3 attempts, Override with option Retries(n))
|
||||
func Backoff(operation func() (*Response, error), options ...Option) error {
|
||||
// Defaults
|
||||
opts := Options{
|
||||
maxRetries: defaultMaxRetries,
|
||||
waitTime: defaultWaitTime,
|
||||
maxWaitTime: defaultMaxWaitTime,
|
||||
retryConditions: []RetryConditionFunc{},
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
var (
|
||||
resp *Response
|
||||
err error
|
||||
)
|
||||
base := float64(opts.waitTime) // Time to wait between each attempt
|
||||
capLevel := float64(opts.maxWaitTime) // Maximum amount of wait time for the retry
|
||||
for attempt := 0; attempt < opts.maxRetries; attempt++ {
|
||||
resp, err = operation()
|
||||
|
||||
var needsRetry bool
|
||||
var conditionErr error
|
||||
for _, condition := range opts.retryConditions {
|
||||
needsRetry, conditionErr = condition(resp)
|
||||
if needsRetry || conditionErr != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the operation returned no error, there was no condition satisfied and
|
||||
// there was no error caused by the conditional functions.
|
||||
if err == nil && !needsRetry && conditionErr == nil {
|
||||
return nil
|
||||
}
|
||||
// Adding capped exponential backup with jitter
|
||||
// See the following article...
|
||||
// http://www.awsarchitectureblog.com/2015/03/backoff.html
|
||||
temp := math.Min(capLevel, base*math.Exp2(float64(attempt)))
|
||||
sleepDuration := time.Duration(int(temp/2) + rand.Intn(int(temp/2)))
|
||||
|
||||
if sleepDuration < opts.waitTime {
|
||||
sleepDuration = opts.waitTime
|
||||
}
|
||||
time.Sleep(sleepDuration)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
253
vendor/github.com/go-resty/resty/util.go
generated
vendored
Normal file
253
vendor/github.com/go-resty/resty/util.go
generated
vendored
Normal file
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Helper methods
|
||||
//___________________________________
|
||||
|
||||
// IsStringEmpty method tells whether given string is empty or not
|
||||
func IsStringEmpty(str string) bool {
|
||||
return len(strings.TrimSpace(str)) == 0
|
||||
}
|
||||
|
||||
// DetectContentType method is used to figure out `Request.Body` content type for request header
|
||||
func DetectContentType(body interface{}) string {
|
||||
contentType := plainTextType
|
||||
kind := kindOf(body)
|
||||
switch kind {
|
||||
case reflect.Struct, reflect.Map:
|
||||
contentType = jsonContentType
|
||||
case reflect.String:
|
||||
contentType = plainTextType
|
||||
default:
|
||||
if b, ok := body.([]byte); ok {
|
||||
contentType = http.DetectContentType(b)
|
||||
} else if kind == reflect.Slice {
|
||||
contentType = jsonContentType
|
||||
}
|
||||
}
|
||||
|
||||
return contentType
|
||||
}
|
||||
|
||||
// IsJSONType method is to check JSON content type or not
|
||||
func IsJSONType(ct string) bool {
|
||||
return jsonCheck.MatchString(ct)
|
||||
}
|
||||
|
||||
// IsXMLType method is to check XML content type or not
|
||||
func IsXMLType(ct string) bool {
|
||||
return xmlCheck.MatchString(ct)
|
||||
}
|
||||
|
||||
// Unmarshal content into object from JSON or XML
|
||||
// Deprecated: kept for backward compatibility
|
||||
func Unmarshal(ct string, b []byte, d interface{}) (err error) {
|
||||
if IsJSONType(ct) {
|
||||
err = json.Unmarshal(b, d)
|
||||
} else if IsXMLType(ct) {
|
||||
err = xml.Unmarshal(b, d)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Unmarshalc content into object from JSON or XML
|
||||
func Unmarshalc(c *Client, ct string, b []byte, d interface{}) (err error) {
|
||||
if IsJSONType(ct) {
|
||||
err = c.JSONUnmarshal(b, d)
|
||||
} else if IsXMLType(ct) {
|
||||
err = xml.Unmarshal(b, d)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// way to disable the HTML escape as opt-in
|
||||
func jsonMarshal(c *Client, r *Request, d interface{}) ([]byte, error) {
|
||||
if !r.jsonEscapeHTML {
|
||||
return noescapeJSONMarshal(d)
|
||||
} else if !c.jsonEscapeHTML {
|
||||
return noescapeJSONMarshal(d)
|
||||
}
|
||||
return c.JSONMarshal(d)
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Unexported methods
|
||||
//___________________________________
|
||||
|
||||
func firstNonEmpty(v ...string) string {
|
||||
for _, s := range v {
|
||||
if !IsStringEmpty(s) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getLogger(w io.Writer) *log.Logger {
|
||||
return log.New(w, "RESTY ", log.LstdFlags)
|
||||
}
|
||||
|
||||
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
func escapeQuotes(s string) string {
|
||||
return quoteEscaper.Replace(s)
|
||||
}
|
||||
|
||||
func createMultipartHeader(param, fileName, contentType string) textproto.MIMEHeader {
|
||||
hdr := make(textproto.MIMEHeader)
|
||||
hdr.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
|
||||
escapeQuotes(param), escapeQuotes(fileName)))
|
||||
hdr.Set("Content-Type", contentType)
|
||||
return hdr
|
||||
}
|
||||
|
||||
func addMultipartFormField(w *multipart.Writer, mf *multipartField) error {
|
||||
partWriter, err := w.CreatePart(createMultipartHeader(mf.Param, mf.FileName, mf.ContentType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(partWriter, mf.Reader)
|
||||
return err
|
||||
}
|
||||
|
||||
func writeMultipartFormFile(w *multipart.Writer, fieldName, fileName string, r io.Reader) error {
|
||||
// Auto detect actual multipart content type
|
||||
cbuf := make([]byte, 512)
|
||||
size, err := r.Read(cbuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
partWriter, err := w.CreatePart(createMultipartHeader(fieldName, fileName, http.DetectContentType(cbuf)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = partWriter.Write(cbuf[:size]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(partWriter, r)
|
||||
return err
|
||||
}
|
||||
|
||||
func addFile(w *multipart.Writer, fieldName, path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeq(file)
|
||||
return writeMultipartFormFile(w, fieldName, filepath.Base(path), file)
|
||||
}
|
||||
|
||||
func addFileReader(w *multipart.Writer, f *File) error {
|
||||
return writeMultipartFormFile(w, f.ParamName, f.Name, f.Reader)
|
||||
}
|
||||
|
||||
func getPointer(v interface{}) interface{} {
|
||||
vv := valueOf(v)
|
||||
if vv.Kind() == reflect.Ptr {
|
||||
return v
|
||||
}
|
||||
return reflect.New(vv.Type()).Interface()
|
||||
}
|
||||
|
||||
func isPayloadSupported(m string, allowMethodGet bool) bool {
|
||||
return !(m == MethodHead || m == MethodOptions || (m == MethodGet && !allowMethodGet))
|
||||
}
|
||||
|
||||
func typeOf(i interface{}) reflect.Type {
|
||||
return indirect(valueOf(i)).Type()
|
||||
}
|
||||
|
||||
func valueOf(i interface{}) reflect.Value {
|
||||
return reflect.ValueOf(i)
|
||||
}
|
||||
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
return reflect.Indirect(v)
|
||||
}
|
||||
|
||||
func kindOf(v interface{}) reflect.Kind {
|
||||
return typeOf(v).Kind()
|
||||
}
|
||||
|
||||
func createDirectory(dir string) (err error) {
|
||||
if _, err = os.Stat(dir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, 0755); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func canJSONMarshal(contentType string, kind reflect.Kind) bool {
|
||||
return IsJSONType(contentType) && (kind == reflect.Struct || kind == reflect.Map)
|
||||
}
|
||||
|
||||
func functionName(i interface{}) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
|
||||
}
|
||||
|
||||
func acquireBuffer() *bytes.Buffer {
|
||||
return bufPool.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func releaseBuffer(buf *bytes.Buffer) {
|
||||
if buf != nil {
|
||||
buf.Reset()
|
||||
bufPool.Put(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func closeq(v interface{}) {
|
||||
if c, ok := v.(io.Closer); ok {
|
||||
sliently(c.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func sliently(_ ...interface{}) {}
|
||||
|
||||
func composeHeaders(hdrs http.Header) string {
|
||||
var str []string
|
||||
for _, k := range sortHeaderKeys(hdrs) {
|
||||
str = append(str, fmt.Sprintf("%25s: %s", k, strings.Join(hdrs[k], ", ")))
|
||||
}
|
||||
return strings.Join(str, "\n")
|
||||
}
|
||||
|
||||
func sortHeaderKeys(hdrs http.Header) []string {
|
||||
var keys []string
|
||||
for key := range hdrs {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue