Add new vendor libraries for newrelic provider

This commit is contained in:
Paul Tyng 2016-11-23 15:55:39 -05:00 committed by stack72
parent c2322b1e55
commit f39cfe61ce
No known key found for this signature in database
GPG Key ID: 8619A619B085CB16
28 changed files with 14248 additions and 0 deletions

201
vendor/github.com/paultyng/go-newrelic/LICENSE generated vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,87 @@
package api
import (
"fmt"
"net/url"
)
func (c *Client) queryAlertChannels() ([]AlertChannel, error) {
channels := []AlertChannel{}
reqURL, err := url.Parse("/alerts_channels.json")
if err != nil {
return nil, err
}
nextPath := reqURL.String()
for nextPath != "" {
resp := struct {
Channels []AlertChannel `json:"channels,omitempty"`
}{}
nextPath, err = c.Do("GET", nextPath, nil, &resp)
if err != nil {
return nil, err
}
channels = append(channels, resp.Channels...)
}
return channels, nil
}
// GetAlertChannel returns a specific alert channel by ID
func (c *Client) GetAlertChannel(id int) (*AlertChannel, error) {
channels, err := c.queryAlertChannels()
if err != nil {
return nil, err
}
for _, channel := range channels {
if channel.ID == id {
return &channel, nil
}
}
return nil, ErrNotFound
}
// ListAlertChannels returns all alert policies for the account.
func (c *Client) ListAlertChannels() ([]AlertChannel, error) {
return c.queryAlertChannels()
}
func (c *Client) CreateAlertChannel(channel AlertChannel) (*AlertChannel, error) {
// TODO: support attaching policy ID's here?
// qs := map[string]string{
// "policy_ids[]": channel.Links.PolicyIDs,
// }
if len(channel.Links.PolicyIDs) > 0 {
return nil, fmt.Errorf("You cannot create an alert channel with policy IDs, you must attach polidy IDs after creation.")
}
req := struct {
Channel AlertChannel `json:"channel"`
}{
Channel: channel,
}
resp := struct {
Channels []AlertChannel `json:"channels,omitempty"`
}{}
_, err := c.Do("POST", "/alerts_channels.json", req, &resp)
if err != nil {
return nil, err
}
return &resp.Channels[0], nil
}
func (c *Client) DeleteAlertChannel(id int) error {
u := &url.URL{Path: fmt.Sprintf("/alerts_channels/%v.json", id)}
_, err := c.Do("DELETE", u.String(), nil, nil)
return err
}

View File

@ -0,0 +1,117 @@
package api
import (
"fmt"
"net/url"
"strconv"
)
func (c *Client) queryAlertConditions(policyID int) ([]AlertCondition, error) {
conditions := []AlertCondition{}
reqURL, err := url.Parse("/alerts_conditions.json")
if err != nil {
return nil, err
}
qs := reqURL.Query()
qs.Set("policy_id", strconv.Itoa(policyID))
reqURL.RawQuery = qs.Encode()
nextPath := reqURL.String()
for nextPath != "" {
resp := struct {
Conditions []AlertCondition `json:"conditions,omitempty"`
}{}
nextPath, err = c.Do("GET", nextPath, nil, &resp)
if err != nil {
return nil, err
}
for _, c := range resp.Conditions {
c.PolicyID = policyID
}
conditions = append(conditions, resp.Conditions...)
}
return conditions, nil
}
func (c *Client) GetAlertCondition(policyID int, id int) (*AlertCondition, error) {
conditions, err := c.queryAlertConditions(policyID)
if err != nil {
return nil, err
}
for _, condition := range conditions {
if condition.ID == id {
return &condition, nil
}
}
return nil, ErrNotFound
}
// ListAlertConditions returns alert conditions for the specified policy.
func (c *Client) ListAlertConditions(policyID int) ([]AlertCondition, error) {
return c.queryAlertConditions(policyID)
}
func (c *Client) CreateAlertCondition(condition AlertCondition) (*AlertCondition, error) {
policyID := condition.PolicyID
req := struct {
Condition AlertCondition `json:"condition"`
}{
Condition: condition,
}
resp := struct {
Condition AlertCondition `json:"condition,omitempty"`
}{}
u := &url.URL{Path: fmt.Sprintf("/alerts_conditions/policies/%v.json", policyID)}
_, err := c.Do("POST", u.String(), req, &resp)
if err != nil {
return nil, err
}
resp.Condition.PolicyID = policyID
return &resp.Condition, nil
}
func (c *Client) UpdateAlertCondition(condition AlertCondition) (*AlertCondition, error) {
policyID := condition.PolicyID
id := condition.ID
req := struct {
Condition AlertCondition `json:"condition"`
}{
Condition: condition,
}
resp := struct {
Condition AlertCondition `json:"condition,omitempty"`
}{}
u := &url.URL{Path: fmt.Sprintf("/alerts_conditions/%v.json", id)}
_, err := c.Do("PUT", u.String(), req, &resp)
if err != nil {
return nil, err
}
resp.Condition.PolicyID = policyID
return &resp.Condition, nil
}
func (c *Client) DeleteAlertCondition(policyID int, id int) error {
u := &url.URL{Path: fmt.Sprintf("/alerts_conditions/%v.json", id)}
_, err := c.Do("DELETE", u.String(), nil, nil)
return err
}

View File

@ -0,0 +1,86 @@
package api
import (
"fmt"
"net/url"
)
func (c *Client) queryAlertPolicies(name *string) ([]AlertPolicy, error) {
policies := []AlertPolicy{}
reqURL, err := url.Parse("/alerts_policies.json")
if err != nil {
return nil, err
}
qs := reqURL.Query()
if name != nil {
qs.Set("filter[name]", *name)
}
reqURL.RawQuery = qs.Encode()
nextPath := reqURL.String()
for nextPath != "" {
resp := struct {
Policies []AlertPolicy `json:"policies,omitempty"`
}{}
nextPath, err = c.Do("GET", nextPath, nil, &resp)
if err != nil {
return nil, err
}
policies = append(policies, resp.Policies...)
}
return policies, nil
}
// GetAlertPolicy returns a specific alert policy by ID
func (c *Client) GetAlertPolicy(id int) (*AlertPolicy, error) {
policies, err := c.queryAlertPolicies(nil)
if err != nil {
return nil, err
}
for _, policy := range policies {
if policy.ID == id {
return &policy, nil
}
}
return nil, ErrNotFound
}
// ListAlertPolicies returns all alert policies for the account.
func (c *Client) ListAlertPolicies() ([]AlertPolicy, error) {
return c.queryAlertPolicies(nil)
}
// CreateAlertPolicy creates a new alert policy for the account.
func (c *Client) CreateAlertPolicy(policy AlertPolicy) (*AlertPolicy, error) {
req := struct {
Policy AlertPolicy `json:"policy"`
}{
Policy: policy,
}
resp := struct {
Policy AlertPolicy `json:"policy,omitempty"`
}{}
_, err := c.Do("POST", "/alerts_policies.json", req, &resp)
if err != nil {
return nil, err
}
return &resp.Policy, nil
}
// DeleteAlertPolicy deletes an existing alert policy from the account.
func (c *Client) DeleteAlertPolicy(id int) error {
u := &url.URL{Path: fmt.Sprintf("/alerts_policies/%v.json", id)}
_, err := c.Do("DELETE", u.String(), nil, nil)
return err
}

View File

@ -0,0 +1,64 @@
package api
import (
"net/url"
"regexp"
"strconv"
)
func (c *Client) UpdateAlertPolicyChannels(policyID int, channelIDs []int) error {
channelIDStrings := make([]string, len(channelIDs))
for i, channelID := range channelIDs {
channelIDStrings[i] = strconv.Itoa(channelID)
}
reqURL, err := url.Parse("/alerts_policy_channels.json")
if err != nil {
return err
}
qs := url.Values{
"policy_id": []string{strconv.Itoa(policyID)},
"channel_ids": channelIDStrings,
}
reqURL.RawQuery = qs.Encode()
nextPath := reqURL.String()
_, err = c.Do("PUT", nextPath, nil, nil)
return err
}
func (c *Client) DeleteAlertPolicyChannel(policyID int, channelID int) error {
reqURL, err := url.Parse("/alerts_policy_channels.json")
if err != nil {
return err
}
qs := url.Values{
"policy_id": []string{strconv.Itoa(policyID)},
"channel_id": []string{strconv.Itoa(channelID)},
}
reqURL.RawQuery = qs.Encode()
nextPath := reqURL.String()
_, err = c.Do("DELETE", nextPath, nil, nil)
if err != nil {
if apiErr, ok := err.(*ErrorResponse); ok {
matched, err := regexp.MatchString("Alerts policy with ID: \\d+ is not valid.", apiErr.Detail.Title)
if err != nil {
return err
}
if matched {
return ErrNotFound
}
}
return err
}
return nil
}

View File

@ -0,0 +1,58 @@
package api
import (
"net/url"
"strconv"
)
type applicationsFilters struct {
Name *string
Host *string
IDs []int
Language *string
}
func (c *Client) queryApplications(filters applicationsFilters) ([]Application, error) {
applications := []Application{}
reqURL, err := url.Parse("/applications.json")
if err != nil {
return nil, err
}
qs := reqURL.Query()
if filters.Name != nil {
qs.Set("filter[name]", *filters.Name)
}
if filters.Host != nil {
qs.Set("filter[host]", *filters.Host)
}
for _, id := range filters.IDs {
qs.Add("filter[ids]", strconv.Itoa(id))
}
if filters.Language != nil {
qs.Set("filter[language]", *filters.Language)
}
reqURL.RawQuery = qs.Encode()
nextPath := reqURL.String()
for nextPath != "" {
resp := struct {
Applications []Application `json:"applications,omitempty"`
}{}
nextPath, err = c.Do("GET", nextPath, nil, &resp)
if err != nil {
return nil, err
}
applications = append(applications, resp.Applications...)
}
return applications, nil
}
func (c *Client) ListApplications() ([]Application, error) {
return c.queryApplications(applicationsFilters{})
}

108
vendor/github.com/paultyng/go-newrelic/api/client.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
package api
import (
"fmt"
"github.com/tomnomnom/linkheader"
resty "gopkg.in/resty.v0"
)
// Client represents the client state for the API.
type Client struct {
RestyClient *resty.Client
}
type ErrorResponse struct {
Detail *ErrorDetail `json:"error,omitempty"`
}
func (e *ErrorResponse) Error() string {
if e != nil && e.Detail != nil {
return e.Detail.Title
}
return "Unknown error"
}
type ErrorDetail struct {
Title string `json:"title,omitempty"`
}
// Config contains all the configuration data for the API Client
type Config struct {
APIKey string
BaseURL string
Debug bool
}
// New returns a new Client for the specified apiKey.
func New(config Config) Client {
r := resty.New()
baseURL := config.BaseURL
if baseURL == "" {
baseURL = "https://api.newrelic.com/v2"
}
r.SetHeader("X-Api-Key", config.APIKey)
r.SetHostURL(baseURL)
if config.Debug {
r.SetDebug(true)
}
c := Client{
RestyClient: r,
}
return c
}
// Do exectes an API request with the specified parameters.
func (c *Client) Do(method string, path string, body interface{}, response interface{}) (string, error) {
r := c.RestyClient.R().
SetError(&ErrorResponse{})
if body != nil {
r = r.SetBody(body)
}
if response != nil {
r = r.SetResult(response)
}
apiResponse, err := r.Execute(method, path)
if err != nil {
return "", err
}
nextPath := ""
header := apiResponse.Header().Get("Link")
if header != "" {
links := linkheader.Parse(header)
for _, link := range links.FilterByRel("next") {
nextPath = link.URL
break
}
}
statusClass := apiResponse.StatusCode() / 100 % 10
if statusClass == 2 {
return nextPath, nil
}
rawError := apiResponse.Error()
if rawError != nil {
apiError := rawError.(*ErrorResponse)
if apiError.Detail != nil {
return "", apiError
}
}
return "", fmt.Errorf("Unexpected status %v returned from API", apiResponse.StatusCode())
}

79
vendor/github.com/paultyng/go-newrelic/api/labels.go generated vendored Normal file
View File

@ -0,0 +1,79 @@
package api
import (
"fmt"
"net/url"
)
func (c *Client) queryLabels() ([]Label, error) {
labels := []Label{}
reqURL, err := url.Parse("/labels.json")
if err != nil {
return nil, err
}
nextPath := reqURL.String()
for nextPath != "" {
resp := struct {
Labels []Label `json:"labels,omitempty"`
}{}
nextPath, err = c.Do("GET", nextPath, nil, &resp)
if err != nil {
return nil, err
}
labels = append(labels, resp.Labels...)
}
return labels, nil
}
func (c *Client) GetLabel(key string) (*Label, error) {
labels, err := c.queryLabels()
if err != nil {
return nil, err
}
for _, label := range labels {
if label.Key == key {
return &label, nil
}
}
return nil, ErrNotFound
}
// ListLabels returns the labels for the account.
func (c *Client) ListLabels() ([]Label, error) {
return c.queryLabels()
}
// CreateLabel creates a new label for the account.
func (c *Client) CreateLabel(label Label) error {
if label.Links.Applications == nil {
label.Links.Applications = make([]int, 0)
}
if label.Links.Servers == nil {
label.Links.Servers = make([]int, 0)
}
req := struct {
Label Label `json:"label,omitempty"`
}{
Label: label,
}
_, err := c.Do("PUT", "/labels.json", req, nil)
return err
}
// DeleteLabel deletes a label on the account specified by key.
func (c *Client) DeleteLabel(key string) error {
u := &url.URL{Path: fmt.Sprintf("/labels/%v.json", key)}
_, err := c.Do("DELETE", u.String(), nil, nil)
return err
}

120
vendor/github.com/paultyng/go-newrelic/api/types.go generated vendored Normal file
View File

@ -0,0 +1,120 @@
package api
import "errors"
var (
ErrNotFound = errors.New("newrelic: Resource not found")
)
// LabelLinks represents external references on the Label.
type LabelLinks struct {
Applications []int `json:"applications"`
Servers []int `json:"servers"`
}
// Label represents a New Relic label.
type Label struct {
Key string `json:"key,omitempty"`
Category string `json:"category,omitempty"`
Name string `json:"name,omitempty"`
Links LabelLinks `json:"links,omitempty"`
}
// AlertPolicy represents a New Relic alert policy.
type AlertPolicy struct {
ID int `json:"id,omitempty"`
IncidentPreference string `json:"incident_preference,omitempty"`
Name string `json:"name,omitempty"`
CreatedAt int `json:"created_at,omitempty"`
UpdatedAt int `json:"updated_at,omitempty"`
}
// AlertConditionUserDefined represents user defined metrics for the New Relic alert condition.
type AlertConditionUserDefined struct {
Metric string `json:"metric,omitempty"`
ValueFunction string `json:"value_function,omitempty"`
}
// AlertConditionTerm represents the terms of a New Relic alert condition.
type AlertConditionTerm struct {
Duration int `json:"duration,string,omitempty"`
Operator string `json:"operator,omitempty"`
Priority string `json:"priority,omitempty"`
Threshold float64 `json:"threshold,string,omitempty"`
TimeFunction string `json:"time_function,omitempty"`
}
// AlertCondition represents a New Relic alert condition.
// TODO: custom unmarshal entities to ints?
// TODO: handle unmarshaling .75 for float (not just 0.75)
type AlertCondition struct {
PolicyID int `json:"-"`
ID int `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Enabled bool `json:"enabled,omitempty"`
Entities []string `json:"entities,omitempty"`
Metric string `json:"metric,omitempty"`
RunbookURL string `json:"runbook_url,omitempty"`
Terms []AlertConditionTerm `json:"terms,omitempty"`
UserDefined AlertConditionUserDefined `json:"uder_defined,omitempty"`
}
// AlertChannelLinks represent the links between policies and alert channels
type AlertChannelLinks struct {
PolicyIDs []int `json:"policy_ids,omitempty"`
}
// AlertChannel represents a New Relic alert notification channel
type AlertChannel struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Configuration map[string]interface{} `json:"configuration,omitempty"`
Links AlertChannelLinks `json:"links,omitempty"`
}
type ApplicationSummary struct {
ResponseTime float64 `json:"response_time"`
Throughput float64 `json:"throughput"`
ErrorRate float64 `json:"error_rate"`
ApdexTarget float64 `json:"apdex_target"`
ApdexScore float64 `json:"apdex_score"`
HostCount int `json:"host_count"`
InstanceCount int `json:"instance_count"`
ConcurrentInstanceCount int `json:"concurrent_instance_count"`
}
type ApplicationEndUserSummary struct {
ResponseTime float64 `json:"response_time"`
Throughput float64 `json:"throughput"`
ApdexTarget float64 `json:"apdex_target"`
ApdexScore float64 `json:"apdex_score"`
}
type ApplicationSettings struct {
AppApdexThreshold float64 `json:"app_apdex_threshold,omitempty"`
EndUserApdexThreshold float64 `json:"end_user_apdex_threshold,omitempty"`
EnableRealUserMonitoring bool `json:"enable_real_user_monitoring,omitempty"`
UseServerSideConfig bool `json:"use_server_side_config,omitempty"`
}
type ApplicationLinks struct {
ServerIDs []int `json:"servers,omitempty"`
HostIDs []int `json:"application_hosts,omitempty"`
InstanceIDs []int `json:"application_instances,omitempty"`
AlertPolicyID int `json:"alert_policy"`
}
type Application struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Language string `json:"language,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
Reporting bool `json:"reporting,omitempty"`
LastReportedAt string `json:"last_reported_at,omitempty"`
Summary ApplicationSummary `json:"application_summary,omitempty"`
EndUserSummary ApplicationEndUserSummary `json:"end_user_summary,omitempty"`
Settings ApplicationSettings `json:"settings,omitempty"`
Links ApplicationLinks `json:"links,omitempty"`
}

View File

@ -0,0 +1,10 @@
# Contributing
* Raise an issue if appropriate
* Fork the repo
* Bootstrap the dev dependencies (run `./script/bootstrap`)
* Make your changes
* Use [gofmt](https://golang.org/cmd/gofmt/)
* Make sure the tests pass (run `./script/test`)
* Make sure the linters pass (run `./script/lint`)
* Issue a pull request

21
vendor/github.com/tomnomnom/linkheader/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Tom Hudson
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.

35
vendor/github.com/tomnomnom/linkheader/README.mkd generated vendored Normal file
View File

@ -0,0 +1,35 @@
# Golang Link Header Parser
Library for parsing HTTP Link headers. Requires Go 1.2 or higher.
Docs can be found on [the GoDoc page](https://godoc.org/github.com/tomnomnom/linkheader).
[![Build Status](https://travis-ci.org/tomnomnom/linkheader.svg)](https://travis-ci.org/tomnomnom/linkheader)
## Basic Example
```go
package main
import (
"fmt"
"github.com/tomnomnom/linkheader"
)
func main() {
header := "<https://api.github.com/user/58276/repos?page=2>; rel=\"next\"," +
"<https://api.github.com/user/58276/repos?page=2>; rel=\"last\""
links := linkheader.Parse(header)
for _, link := range links {
fmt.Printf("URL: %s; Rel: %s\n", link.URL, link.Rel)
}
}
// Output:
// URL: https://api.github.com/user/58276/repos?page=2; Rel: next
// URL: https://api.github.com/user/58276/repos?page=2; Rel: last
```

143
vendor/github.com/tomnomnom/linkheader/main.go generated vendored Normal file
View File

@ -0,0 +1,143 @@
// Package linkheader provides functions for parsing HTTP Link headers
package linkheader
import (
"fmt"
"strings"
)
// A Link is a single URL and related parameters
type Link struct {
URL string
Rel string
Params map[string]string
}
// HasParam returns if a Link has a particular parameter or not
func (l Link) HasParam(key string) bool {
for p := range l.Params {
if p == key {
return true
}
}
return false
}
// Param returns the value of a parameter if it exists
func (l Link) Param(key string) string {
for k, v := range l.Params {
if key == k {
return v
}
}
return ""
}
// String returns the string representation of a link
func (l Link) String() string {
p := make([]string, 0, len(l.Params))
for k, v := range l.Params {
p = append(p, fmt.Sprintf("%s=\"%s\"", k, v))
}
if l.Rel != "" {
p = append(p, fmt.Sprintf("%s=\"%s\"", "rel", l.Rel))
}
return fmt.Sprintf("<%s>; %s", l.URL, strings.Join(p, "; "))
}
// Links is a slice of Link structs
type Links []Link
// FilterByRel filters a group of Links by the provided Rel attribute
func (l Links) FilterByRel(r string) Links {
links := make(Links, 0)
for _, link := range l {
if link.Rel == r {
links = append(links, link)
}
}
return links
}
// String returns the string representation of multiple Links
// for use in HTTP responses etc
func (l Links) String() string {
var strs []string
for _, link := range l {
strs = append(strs, link.String())
}
return strings.Join(strs, ", ")
}
// Parse parses a raw Link header in the form:
// <url>; rel="foo", <url>; rel="bar"; wat="dis"
// returning a slice of Link structs
func Parse(raw string) Links {
links := make(Links, 0)
// One chunk: <url>; rel="foo"
for _, chunk := range strings.Split(raw, ",") {
link := Link{URL: "", Rel: "", Params: make(map[string]string)}
// Figure out what each piece of the chunk is
for _, piece := range strings.Split(chunk, ";") {
piece = strings.Trim(piece, " ")
if piece == "" {
continue
}
// URL
if piece[0] == '<' && piece[len(piece)-1] == '>' {
link.URL = strings.Trim(piece, "<>")
continue
}
// Params
key, val := parseParam(piece)
if key == "" {
continue
}
// Special case for rel
if strings.ToLower(key) == "rel" {
link.Rel = val
}
link.Params[key] = val
}
links = append(links, link)
}
return links
}
// ParseMultiple is like Parse, but accepts a slice of headers
// rather than just one header string
func ParseMultiple(headers []string) Links {
links := make(Links, 0)
for _, header := range headers {
links = append(links, Parse(header)...)
}
return links
}
// parseParam takes a raw param in the form key="val" and
// returns the key and value as seperate strings
func parseParam(raw string) (key, val string) {
parts := strings.SplitN(raw, "=", 2)
if len(parts) != 2 {
return "", ""
}
key = parts[0]
val = strings.Trim(parts[1], "\"")
return key, val
}

68
vendor/golang.org/x/net/idna/idna.go generated vendored Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package idna implements IDNA2008 (Internationalized Domain Names for
// Applications), defined in RFC 5890, RFC 5891, RFC 5892, RFC 5893 and
// RFC 5894.
package idna // import "golang.org/x/net/idna"
import (
"strings"
"unicode/utf8"
)
// TODO(nigeltao): specify when errors occur. For example, is ToASCII(".") or
// ToASCII("foo\x00") an error? See also http://www.unicode.org/faq/idn.html#11
// acePrefix is the ASCII Compatible Encoding prefix.
const acePrefix = "xn--"
// ToASCII converts a domain or domain label to its ASCII form. For example,
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
// ToASCII("golang") is "golang".
func ToASCII(s string) (string, error) {
if ascii(s) {
return s, nil
}
labels := strings.Split(s, ".")
for i, label := range labels {
if !ascii(label) {
a, err := encode(acePrefix, label)
if err != nil {
return "", err
}
labels[i] = a
}
}
return strings.Join(labels, "."), nil
}
// ToUnicode converts a domain or domain label to its Unicode form. For example,
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
// ToUnicode("golang") is "golang".
func ToUnicode(s string) (string, error) {
if !strings.Contains(s, acePrefix) {
return s, nil
}
labels := strings.Split(s, ".")
for i, label := range labels {
if strings.HasPrefix(label, acePrefix) {
u, err := decode(label[len(acePrefix):])
if err != nil {
return "", err
}
labels[i] = u
}
}
return strings.Join(labels, "."), nil
}
func ascii(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] >= utf8.RuneSelf {
return false
}
}
return true
}

200
vendor/golang.org/x/net/idna/punycode.go generated vendored Normal file
View File

@ -0,0 +1,200 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package idna
// This file implements the Punycode algorithm from RFC 3492.
import (
"fmt"
"math"
"strings"
"unicode/utf8"
)
// These parameter values are specified in section 5.
//
// All computation is done with int32s, so that overflow behavior is identical
// regardless of whether int is 32-bit or 64-bit.
const (
base int32 = 36
damp int32 = 700
initialBias int32 = 72
initialN int32 = 128
skew int32 = 38
tmax int32 = 26
tmin int32 = 1
)
// decode decodes a string as specified in section 6.2.
func decode(encoded string) (string, error) {
if encoded == "" {
return "", nil
}
pos := 1 + strings.LastIndex(encoded, "-")
if pos == 1 {
return "", fmt.Errorf("idna: invalid label %q", encoded)
}
if pos == len(encoded) {
return encoded[:len(encoded)-1], nil
}
output := make([]rune, 0, len(encoded))
if pos != 0 {
for _, r := range encoded[:pos-1] {
output = append(output, r)
}
}
i, n, bias := int32(0), initialN, initialBias
for pos < len(encoded) {
oldI, w := i, int32(1)
for k := base; ; k += base {
if pos == len(encoded) {
return "", fmt.Errorf("idna: invalid label %q", encoded)
}
digit, ok := decodeDigit(encoded[pos])
if !ok {
return "", fmt.Errorf("idna: invalid label %q", encoded)
}
pos++
i += digit * w
if i < 0 {
return "", fmt.Errorf("idna: invalid label %q", encoded)
}
t := k - bias
if t < tmin {
t = tmin
} else if t > tmax {
t = tmax
}
if digit < t {
break
}
w *= base - t
if w >= math.MaxInt32/base {
return "", fmt.Errorf("idna: invalid label %q", encoded)
}
}
x := int32(len(output) + 1)
bias = adapt(i-oldI, x, oldI == 0)
n += i / x
i %= x
if n > utf8.MaxRune || len(output) >= 1024 {
return "", fmt.Errorf("idna: invalid label %q", encoded)
}
output = append(output, 0)
copy(output[i+1:], output[i:])
output[i] = n
i++
}
return string(output), nil
}
// encode encodes a string as specified in section 6.3 and prepends prefix to
// the result.
//
// The "while h < length(input)" line in the specification becomes "for
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
func encode(prefix, s string) (string, error) {
output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
copy(output, prefix)
delta, n, bias := int32(0), initialN, initialBias
b, remaining := int32(0), int32(0)
for _, r := range s {
if r < 0x80 {
b++
output = append(output, byte(r))
} else {
remaining++
}
}
h := b
if b > 0 {
output = append(output, '-')
}
for remaining != 0 {
m := int32(0x7fffffff)
for _, r := range s {
if m > r && r >= n {
m = r
}
}
delta += (m - n) * (h + 1)
if delta < 0 {
return "", fmt.Errorf("idna: invalid label %q", s)
}
n = m
for _, r := range s {
if r < n {
delta++
if delta < 0 {
return "", fmt.Errorf("idna: invalid label %q", s)
}
continue
}
if r > n {
continue
}
q := delta
for k := base; ; k += base {
t := k - bias
if t < tmin {
t = tmin
} else if t > tmax {
t = tmax
}
if q < t {
break
}
output = append(output, encodeDigit(t+(q-t)%(base-t)))
q = (q - t) / (base - t)
}
output = append(output, encodeDigit(q))
bias = adapt(delta, h+1, h == b)
delta = 0
h++
remaining--
}
delta++
n++
}
return string(output), nil
}
func decodeDigit(x byte) (digit int32, ok bool) {
switch {
case '0' <= x && x <= '9':
return int32(x - ('0' - 26)), true
case 'A' <= x && x <= 'Z':
return int32(x - 'A'), true
case 'a' <= x && x <= 'z':
return int32(x - 'a'), true
}
return 0, false
}
func encodeDigit(digit int32) byte {
switch {
case 0 <= digit && digit < 26:
return byte(digit + 'a')
case 26 <= digit && digit < 36:
return byte(digit + ('0' - 26))
}
panic("idna: internal error in punycode encoding")
}
// adapt is the bias adaptation function specified in section 6.1.
func adapt(delta, numPoints int32, firstTime bool) int32 {
if firstTime {
delta /= damp
} else {
delta /= 2
}
delta += delta / numPoints
k := int32(0)
for delta > ((base-tmin)*tmax)/2 {
delta /= base - tmin
k += base
}
return k + (base-tmin+1)*delta/(delta+skew)
}

713
vendor/golang.org/x/net/publicsuffix/gen.go generated vendored Normal file
View File

@ -0,0 +1,713 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
// This program generates table.go and table_test.go based on the authoritative
// public suffix list at https://publicsuffix.org/list/effective_tld_names.dat
//
// The version is derived from
// https://api.github.com/repos/publicsuffix/list/commits?path=public_suffix_list.dat
// and a human-readable form is at
// https://github.com/publicsuffix/list/commits/master/public_suffix_list.dat
//
// To fetch a particular git revision, such as 5c70ccd250, pass
// -url "https://raw.githubusercontent.com/publicsuffix/list/5c70ccd250/public_suffix_list.dat"
// and -version "an explicit version string".
import (
"bufio"
"bytes"
"flag"
"fmt"
"go/format"
"io"
"io/ioutil"
"net/http"
"os"
"regexp"
"sort"
"strings"
"golang.org/x/net/idna"
)
const (
// These sum of these four values must be no greater than 32.
nodesBitsChildren = 9
nodesBitsICANN = 1
nodesBitsTextOffset = 15
nodesBitsTextLength = 6
// These sum of these four values must be no greater than 32.
childrenBitsWildcard = 1
childrenBitsNodeType = 2
childrenBitsHi = 14
childrenBitsLo = 14
)
var (
maxChildren int
maxTextOffset int
maxTextLength int
maxHi uint32
maxLo uint32
)
func max(a, b int) int {
if a < b {
return b
}
return a
}
func u32max(a, b uint32) uint32 {
if a < b {
return b
}
return a
}
const (
nodeTypeNormal = 0
nodeTypeException = 1
nodeTypeParentOnly = 2
numNodeType = 3
)
func nodeTypeStr(n int) string {
switch n {
case nodeTypeNormal:
return "+"
case nodeTypeException:
return "!"
case nodeTypeParentOnly:
return "o"
}
panic("unreachable")
}
const (
defaultURL = "https://publicsuffix.org/list/effective_tld_names.dat"
gitCommitURL = "https://api.github.com/repos/publicsuffix/list/commits?path=public_suffix_list.dat"
)
var (
labelEncoding = map[string]uint32{}
labelsList = []string{}
labelsMap = map[string]bool{}
rules = []string{}
// validSuffixRE is used to check that the entries in the public suffix
// list are in canonical form (after Punycode encoding). Specifically,
// capital letters are not allowed.
validSuffixRE = regexp.MustCompile(`^[a-z0-9_\!\*\-\.]+$`)
shaRE = regexp.MustCompile(`"sha":"([^"]+)"`)
dateRE = regexp.MustCompile(`"committer":{[^{]+"date":"([^"]+)"`)
comments = flag.Bool("comments", false, "generate table.go comments, for debugging")
subset = flag.Bool("subset", false, "generate only a subset of the full table, for debugging")
url = flag.String("url", defaultURL, "URL of the publicsuffix.org list. If empty, stdin is read instead")
v = flag.Bool("v", false, "verbose output (to stderr)")
version = flag.String("version", "", "the effective_tld_names.dat version")
)
func main() {
if err := main1(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func main1() error {
flag.Parse()
if nodesBitsTextLength+nodesBitsTextOffset+nodesBitsICANN+nodesBitsChildren > 32 {
return fmt.Errorf("not enough bits to encode the nodes table")
}
if childrenBitsLo+childrenBitsHi+childrenBitsNodeType+childrenBitsWildcard > 32 {
return fmt.Errorf("not enough bits to encode the children table")
}
if *version == "" {
if *url != defaultURL {
return fmt.Errorf("-version was not specified, and the -url is not the default one")
}
sha, date, err := gitCommit()
if err != nil {
return err
}
*version = fmt.Sprintf("publicsuffix.org's public_suffix_list.dat, git revision %s (%s)", sha, date)
}
var r io.Reader = os.Stdin
if *url != "" {
res, err := http.Get(*url)
if err != nil {
return err
}
if res.StatusCode != http.StatusOK {
return fmt.Errorf("bad GET status for %s: %d", *url, res.Status)
}
r = res.Body
defer res.Body.Close()
}
var root node
icann := false
br := bufio.NewReader(r)
for {
s, err := br.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
return err
}
s = strings.TrimSpace(s)
if strings.Contains(s, "BEGIN ICANN DOMAINS") {
icann = true
continue
}
if strings.Contains(s, "END ICANN DOMAINS") {
icann = false
continue
}
if s == "" || strings.HasPrefix(s, "//") {
continue
}
s, err = idna.ToASCII(s)
if err != nil {
return err
}
if !validSuffixRE.MatchString(s) {
return fmt.Errorf("bad publicsuffix.org list data: %q", s)
}
if *subset {
switch {
case s == "ac.jp" || strings.HasSuffix(s, ".ac.jp"):
case s == "ak.us" || strings.HasSuffix(s, ".ak.us"):
case s == "ao" || strings.HasSuffix(s, ".ao"):
case s == "ar" || strings.HasSuffix(s, ".ar"):
case s == "arpa" || strings.HasSuffix(s, ".arpa"):
case s == "cy" || strings.HasSuffix(s, ".cy"):
case s == "dyndns.org" || strings.HasSuffix(s, ".dyndns.org"):
case s == "jp":
case s == "kobe.jp" || strings.HasSuffix(s, ".kobe.jp"):
case s == "kyoto.jp" || strings.HasSuffix(s, ".kyoto.jp"):
case s == "om" || strings.HasSuffix(s, ".om"):
case s == "uk" || strings.HasSuffix(s, ".uk"):
case s == "uk.com" || strings.HasSuffix(s, ".uk.com"):
case s == "tw" || strings.HasSuffix(s, ".tw"):
case s == "zw" || strings.HasSuffix(s, ".zw"):
case s == "xn--p1ai" || strings.HasSuffix(s, ".xn--p1ai"):
// xn--p1ai is Russian-Cyrillic "рф".
default:
continue
}
}
rules = append(rules, s)
nt, wildcard := nodeTypeNormal, false
switch {
case strings.HasPrefix(s, "*."):
s, nt = s[2:], nodeTypeParentOnly
wildcard = true
case strings.HasPrefix(s, "!"):
s, nt = s[1:], nodeTypeException
}
labels := strings.Split(s, ".")
for n, i := &root, len(labels)-1; i >= 0; i-- {
label := labels[i]
n = n.child(label)
if i == 0 {
if nt != nodeTypeParentOnly && n.nodeType == nodeTypeParentOnly {
n.nodeType = nt
}
n.icann = n.icann && icann
n.wildcard = n.wildcard || wildcard
}
labelsMap[label] = true
}
}
labelsList = make([]string, 0, len(labelsMap))
for label := range labelsMap {
labelsList = append(labelsList, label)
}
sort.Strings(labelsList)
if err := generate(printReal, &root, "table.go"); err != nil {
return err
}
if err := generate(printTest, &root, "table_test.go"); err != nil {
return err
}
return nil
}
func generate(p func(io.Writer, *node) error, root *node, filename string) error {
buf := new(bytes.Buffer)
if err := p(buf, root); err != nil {
return err
}
b, err := format.Source(buf.Bytes())
if err != nil {
return err
}
return ioutil.WriteFile(filename, b, 0644)
}
func gitCommit() (sha, date string, retErr error) {
res, err := http.Get(gitCommitURL)
if err != nil {
return "", "", err
}
if res.StatusCode != http.StatusOK {
return "", "", fmt.Errorf("bad GET status for %s: %d", gitCommitURL, res.Status)
}
defer res.Body.Close()
b, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", "", err
}
if m := shaRE.FindSubmatch(b); m != nil {
sha = string(m[1])
}
if m := dateRE.FindSubmatch(b); m != nil {
date = string(m[1])
}
if sha == "" || date == "" {
retErr = fmt.Errorf("could not find commit SHA and date in %s", gitCommitURL)
}
return sha, date, retErr
}
func printTest(w io.Writer, n *node) error {
fmt.Fprintf(w, "// generated by go run gen.go; DO NOT EDIT\n\n")
fmt.Fprintf(w, "package publicsuffix\n\nvar rules = [...]string{\n")
for _, rule := range rules {
fmt.Fprintf(w, "%q,\n", rule)
}
fmt.Fprintf(w, "}\n\nvar nodeLabels = [...]string{\n")
if err := n.walk(w, printNodeLabel); err != nil {
return err
}
fmt.Fprintf(w, "}\n")
return nil
}
func printReal(w io.Writer, n *node) error {
const header = `// generated by go run gen.go; DO NOT EDIT
package publicsuffix
const version = %q
const (
nodesBitsChildren = %d
nodesBitsICANN = %d
nodesBitsTextOffset = %d
nodesBitsTextLength = %d
childrenBitsWildcard = %d
childrenBitsNodeType = %d
childrenBitsHi = %d
childrenBitsLo = %d
)
const (
nodeTypeNormal = %d
nodeTypeException = %d
nodeTypeParentOnly = %d
)
// numTLD is the number of top level domains.
const numTLD = %d
`
fmt.Fprintf(w, header, *version,
nodesBitsChildren, nodesBitsICANN, nodesBitsTextOffset, nodesBitsTextLength,
childrenBitsWildcard, childrenBitsNodeType, childrenBitsHi, childrenBitsLo,
nodeTypeNormal, nodeTypeException, nodeTypeParentOnly, len(n.children))
text := combineText(labelsList)
if text == "" {
return fmt.Errorf("internal error: makeText returned no text")
}
for _, label := range labelsList {
offset, length := strings.Index(text, label), len(label)
if offset < 0 {
return fmt.Errorf("internal error: could not find %q in text %q", label, text)
}
maxTextOffset, maxTextLength = max(maxTextOffset, offset), max(maxTextLength, length)
if offset >= 1<<nodesBitsTextOffset {
return fmt.Errorf("text offset %d is too large, or nodeBitsTextOffset is too small", offset)
}
if length >= 1<<nodesBitsTextLength {
return fmt.Errorf("text length %d is too large, or nodeBitsTextLength is too small", length)
}
labelEncoding[label] = uint32(offset)<<nodesBitsTextLength | uint32(length)
}
fmt.Fprintf(w, "// Text is the combined text of all labels.\nconst text = ")
for len(text) > 0 {
n, plus := len(text), ""
if n > 64 {
n, plus = 64, " +"
}
fmt.Fprintf(w, "%q%s\n", text[:n], plus)
text = text[n:]
}
if err := n.walk(w, assignIndexes); err != nil {
return err
}
fmt.Fprintf(w, `
// nodes is the list of nodes. Each node is represented as a uint32, which
// encodes the node's children, wildcard bit and node type (as an index into
// the children array), ICANN bit and text.
//
// If the table was generated with the -comments flag, there is a //-comment
// after each node's data. In it is the nodes-array indexes of the children,
// formatted as (n0x1234-n0x1256), with * denoting the wildcard bit. The
// nodeType is printed as + for normal, ! for exception, and o for parent-only
// nodes that have children but don't match a domain label in their own right.
// An I denotes an ICANN domain.
//
// The layout within the uint32, from MSB to LSB, is:
// [%2d bits] unused
// [%2d bits] children index
// [%2d bits] ICANN bit
// [%2d bits] text index
// [%2d bits] text length
var nodes = [...]uint32{
`,
32-nodesBitsChildren-nodesBitsICANN-nodesBitsTextOffset-nodesBitsTextLength,
nodesBitsChildren, nodesBitsICANN, nodesBitsTextOffset, nodesBitsTextLength)
if err := n.walk(w, printNode); err != nil {
return err
}
fmt.Fprintf(w, `}
// children is the list of nodes' children, the parent's wildcard bit and the
// parent's node type. If a node has no children then their children index
// will be in the range [0, 6), depending on the wildcard bit and node type.
//
// The layout within the uint32, from MSB to LSB, is:
// [%2d bits] unused
// [%2d bits] wildcard bit
// [%2d bits] node type
// [%2d bits] high nodes index (exclusive) of children
// [%2d bits] low nodes index (inclusive) of children
var children=[...]uint32{
`,
32-childrenBitsWildcard-childrenBitsNodeType-childrenBitsHi-childrenBitsLo,
childrenBitsWildcard, childrenBitsNodeType, childrenBitsHi, childrenBitsLo)
for i, c := range childrenEncoding {
s := "---------------"
lo := c & (1<<childrenBitsLo - 1)
hi := (c >> childrenBitsLo) & (1<<childrenBitsHi - 1)
if lo != hi {
s = fmt.Sprintf("n0x%04x-n0x%04x", lo, hi)
}
nodeType := int(c>>(childrenBitsLo+childrenBitsHi)) & (1<<childrenBitsNodeType - 1)
wildcard := c>>(childrenBitsLo+childrenBitsHi+childrenBitsNodeType) != 0
if *comments {
fmt.Fprintf(w, "0x%08x, // c0x%04x (%s)%s %s\n",
c, i, s, wildcardStr(wildcard), nodeTypeStr(nodeType))
} else {
fmt.Fprintf(w, "0x%x,\n", c)
}
}
fmt.Fprintf(w, "}\n\n")
fmt.Fprintf(w, "// max children %d (capacity %d)\n", maxChildren, 1<<nodesBitsChildren-1)
fmt.Fprintf(w, "// max text offset %d (capacity %d)\n", maxTextOffset, 1<<nodesBitsTextOffset-1)
fmt.Fprintf(w, "// max text length %d (capacity %d)\n", maxTextLength, 1<<nodesBitsTextLength-1)
fmt.Fprintf(w, "// max hi %d (capacity %d)\n", maxHi, 1<<childrenBitsHi-1)
fmt.Fprintf(w, "// max lo %d (capacity %d)\n", maxLo, 1<<childrenBitsLo-1)
return nil
}
type node struct {
label string
nodeType int
icann bool
wildcard bool
// nodesIndex and childrenIndex are the index of this node in the nodes
// and the index of its children offset/length in the children arrays.
nodesIndex, childrenIndex int
// firstChild is the index of this node's first child, or zero if this
// node has no children.
firstChild int
// children are the node's children, in strictly increasing node label order.
children []*node
}
func (n *node) walk(w io.Writer, f func(w1 io.Writer, n1 *node) error) error {
if err := f(w, n); err != nil {
return err
}
for _, c := range n.children {
if err := c.walk(w, f); err != nil {
return err
}
}
return nil
}
// child returns the child of n with the given label. The child is created if
// it did not exist beforehand.
func (n *node) child(label string) *node {
for _, c := range n.children {
if c.label == label {
return c
}
}
c := &node{
label: label,
nodeType: nodeTypeParentOnly,
icann: true,
}
n.children = append(n.children, c)
sort.Sort(byLabel(n.children))
return c
}
type byLabel []*node
func (b byLabel) Len() int { return len(b) }
func (b byLabel) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byLabel) Less(i, j int) bool { return b[i].label < b[j].label }
var nextNodesIndex int
// childrenEncoding are the encoded entries in the generated children array.
// All these pre-defined entries have no children.
var childrenEncoding = []uint32{
0 << (childrenBitsLo + childrenBitsHi), // Without wildcard bit, nodeTypeNormal.
1 << (childrenBitsLo + childrenBitsHi), // Without wildcard bit, nodeTypeException.
2 << (childrenBitsLo + childrenBitsHi), // Without wildcard bit, nodeTypeParentOnly.
4 << (childrenBitsLo + childrenBitsHi), // With wildcard bit, nodeTypeNormal.
5 << (childrenBitsLo + childrenBitsHi), // With wildcard bit, nodeTypeException.
6 << (childrenBitsLo + childrenBitsHi), // With wildcard bit, nodeTypeParentOnly.
}
var firstCallToAssignIndexes = true
func assignIndexes(w io.Writer, n *node) error {
if len(n.children) != 0 {
// Assign nodesIndex.
n.firstChild = nextNodesIndex
for _, c := range n.children {
c.nodesIndex = nextNodesIndex
nextNodesIndex++
}
// The root node's children is implicit.
if firstCallToAssignIndexes {
firstCallToAssignIndexes = false
return nil
}
// Assign childrenIndex.
maxChildren = max(maxChildren, len(childrenEncoding))
if len(childrenEncoding) >= 1<<nodesBitsChildren {
return fmt.Errorf("children table size %d is too large, or nodeBitsChildren is too small", len(childrenEncoding))
}
n.childrenIndex = len(childrenEncoding)
lo := uint32(n.firstChild)
hi := lo + uint32(len(n.children))
maxLo, maxHi = u32max(maxLo, lo), u32max(maxHi, hi)
if lo >= 1<<childrenBitsLo {
return fmt.Errorf("children lo %d is too large, or childrenBitsLo is too small", lo)
}
if hi >= 1<<childrenBitsHi {
return fmt.Errorf("children hi %d is too large, or childrenBitsHi is too small", hi)
}
enc := hi<<childrenBitsLo | lo
enc |= uint32(n.nodeType) << (childrenBitsLo + childrenBitsHi)
if n.wildcard {
enc |= 1 << (childrenBitsLo + childrenBitsHi + childrenBitsNodeType)
}
childrenEncoding = append(childrenEncoding, enc)
} else {
n.childrenIndex = n.nodeType
if n.wildcard {
n.childrenIndex += numNodeType
}
}
return nil
}
func printNode(w io.Writer, n *node) error {
for _, c := range n.children {
s := "---------------"
if len(c.children) != 0 {
s = fmt.Sprintf("n0x%04x-n0x%04x", c.firstChild, c.firstChild+len(c.children))
}
encoding := labelEncoding[c.label]
if c.icann {
encoding |= 1 << (nodesBitsTextLength + nodesBitsTextOffset)
}
encoding |= uint32(c.childrenIndex) << (nodesBitsTextLength + nodesBitsTextOffset + nodesBitsICANN)
if *comments {
fmt.Fprintf(w, "0x%08x, // n0x%04x c0x%04x (%s)%s %s %s %s\n",
encoding, c.nodesIndex, c.childrenIndex, s, wildcardStr(c.wildcard),
nodeTypeStr(c.nodeType), icannStr(c.icann), c.label,
)
} else {
fmt.Fprintf(w, "0x%x,\n", encoding)
}
}
return nil
}
func printNodeLabel(w io.Writer, n *node) error {
for _, c := range n.children {
fmt.Fprintf(w, "%q,\n", c.label)
}
return nil
}
func icannStr(icann bool) string {
if icann {
return "I"
}
return " "
}
func wildcardStr(wildcard bool) string {
if wildcard {
return "*"
}
return " "
}
// combineText combines all the strings in labelsList to form one giant string.
// Overlapping strings will be merged: "arpa" and "parliament" could yield
// "arparliament".
func combineText(labelsList []string) string {
beforeLength := 0
for _, s := range labelsList {
beforeLength += len(s)
}
text := crush(removeSubstrings(labelsList))
if *v {
fmt.Fprintf(os.Stderr, "crushed %d bytes to become %d bytes\n", beforeLength, len(text))
}
return text
}
type byLength []string
func (s byLength) Len() int { return len(s) }
func (s byLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) }
// removeSubstrings returns a copy of its input with any strings removed
// that are substrings of other provided strings.
func removeSubstrings(input []string) []string {
// Make a copy of input.
ss := append(make([]string, 0, len(input)), input...)
sort.Sort(byLength(ss))
for i, shortString := range ss {
// For each string, only consider strings higher than it in sort order, i.e.
// of equal length or greater.
for _, longString := range ss[i+1:] {
if strings.Contains(longString, shortString) {
ss[i] = ""
break
}
}
}
// Remove the empty strings.
sort.Strings(ss)
for len(ss) > 0 && ss[0] == "" {
ss = ss[1:]
}
return ss
}
// crush combines a list of strings, taking advantage of overlaps. It returns a
// single string that contains each input string as a substring.
func crush(ss []string) string {
maxLabelLen := 0
for _, s := range ss {
if maxLabelLen < len(s) {
maxLabelLen = len(s)
}
}
for prefixLen := maxLabelLen; prefixLen > 0; prefixLen-- {
prefixes := makePrefixMap(ss, prefixLen)
for i, s := range ss {
if len(s) <= prefixLen {
continue
}
mergeLabel(ss, i, prefixLen, prefixes)
}
}
return strings.Join(ss, "")
}
// mergeLabel merges the label at ss[i] with the first available matching label
// in prefixMap, where the last "prefixLen" characters in ss[i] match the first
// "prefixLen" characters in the matching label.
// It will merge ss[i] repeatedly until no more matches are available.
// All matching labels merged into ss[i] are replaced by "".
func mergeLabel(ss []string, i, prefixLen int, prefixes prefixMap) {
s := ss[i]
suffix := s[len(s)-prefixLen:]
for _, j := range prefixes[suffix] {
// Empty strings mean "already used." Also avoid merging with self.
if ss[j] == "" || i == j {
continue
}
if *v {
fmt.Fprintf(os.Stderr, "%d-length overlap at (%4d,%4d): %q and %q share %q\n",
prefixLen, i, j, ss[i], ss[j], suffix)
}
ss[i] += ss[j][prefixLen:]
ss[j] = ""
// ss[i] has a new suffix, so merge again if possible.
// Note: we only have to merge again at the same prefix length. Shorter
// prefix lengths will be handled in the next iteration of crush's for loop.
// Can there be matches for longer prefix lengths, introduced by the merge?
// I believe that any such matches would by necessity have been eliminated
// during substring removal or merged at a higher prefix length. For
// instance, in crush("abc", "cde", "bcdef"), combining "abc" and "cde"
// would yield "abcde", which could be merged with "bcdef." However, in
// practice "cde" would already have been elimintated by removeSubstrings.
mergeLabel(ss, i, prefixLen, prefixes)
return
}
}
// prefixMap maps from a prefix to a list of strings containing that prefix. The
// list of strings is represented as indexes into a slice of strings stored
// elsewhere.
type prefixMap map[string][]int
// makePrefixMap constructs a prefixMap from a slice of strings.
func makePrefixMap(ss []string, prefixLen int) prefixMap {
prefixes := make(prefixMap)
for i, s := range ss {
// We use < rather than <= because if a label matches on a prefix equal to
// its full length, that's actually a substring match handled by
// removeSubstrings.
if prefixLen < len(s) {
prefix := s[:prefixLen]
prefixes[prefix] = append(prefixes[prefix], i)
}
}
return prefixes
}

135
vendor/golang.org/x/net/publicsuffix/list.go generated vendored Normal file
View File

@ -0,0 +1,135 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go
// Package publicsuffix provides a public suffix list based on data from
// http://publicsuffix.org/. A public suffix is one under which Internet users
// can directly register names.
package publicsuffix // import "golang.org/x/net/publicsuffix"
// TODO: specify case sensitivity and leading/trailing dot behavior for
// func PublicSuffix and func EffectiveTLDPlusOne.
import (
"fmt"
"net/http/cookiejar"
"strings"
)
// List implements the cookiejar.PublicSuffixList interface by calling the
// PublicSuffix function.
var List cookiejar.PublicSuffixList = list{}
type list struct{}
func (list) PublicSuffix(domain string) string {
ps, _ := PublicSuffix(domain)
return ps
}
func (list) String() string {
return version
}
// PublicSuffix returns the public suffix of the domain using a copy of the
// publicsuffix.org database compiled into the library.
//
// icann is whether the public suffix is managed by the Internet Corporation
// for Assigned Names and Numbers. If not, the public suffix is privately
// managed. For example, foo.org and foo.co.uk are ICANN domains,
// foo.dyndns.org and foo.blogspot.co.uk are private domains.
//
// Use cases for distinguishing ICANN domains like foo.com from private
// domains like foo.appspot.com can be found at
// https://wiki.mozilla.org/Public_Suffix_List/Use_Cases
func PublicSuffix(domain string) (publicSuffix string, icann bool) {
lo, hi := uint32(0), uint32(numTLD)
s, suffix, wildcard := domain, len(domain), false
loop:
for {
dot := strings.LastIndex(s, ".")
if wildcard {
suffix = 1 + dot
}
if lo == hi {
break
}
f := find(s[1+dot:], lo, hi)
if f == notFound {
break
}
u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength)
icann = u&(1<<nodesBitsICANN-1) != 0
u >>= nodesBitsICANN
u = children[u&(1<<nodesBitsChildren-1)]
lo = u & (1<<childrenBitsLo - 1)
u >>= childrenBitsLo
hi = u & (1<<childrenBitsHi - 1)
u >>= childrenBitsHi
switch u & (1<<childrenBitsNodeType - 1) {
case nodeTypeNormal:
suffix = 1 + dot
case nodeTypeException:
suffix = 1 + len(s)
break loop
}
u >>= childrenBitsNodeType
wildcard = u&(1<<childrenBitsWildcard-1) != 0
if dot == -1 {
break
}
s = s[:dot]
}
if suffix == len(domain) {
// If no rules match, the prevailing rule is "*".
return domain[1+strings.LastIndex(domain, "."):], icann
}
return domain[suffix:], icann
}
const notFound uint32 = 1<<32 - 1
// find returns the index of the node in the range [lo, hi) whose label equals
// label, or notFound if there is no such node. The range is assumed to be in
// strictly increasing node label order.
func find(label string, lo, hi uint32) uint32 {
for lo < hi {
mid := lo + (hi-lo)/2
s := nodeLabel(mid)
if s < label {
lo = mid + 1
} else if s == label {
return mid
} else {
hi = mid
}
}
return notFound
}
// nodeLabel returns the label for the i'th node.
func nodeLabel(i uint32) string {
x := nodes[i]
length := x & (1<<nodesBitsTextLength - 1)
x >>= nodesBitsTextLength
offset := x & (1<<nodesBitsTextOffset - 1)
return text[offset : offset+length]
}
// EffectiveTLDPlusOne returns the effective top level domain plus one more
// label. For example, the eTLD+1 for "foo.bar.golang.org" is "golang.org".
func EffectiveTLDPlusOne(domain string) (string, error) {
suffix, _ := PublicSuffix(domain)
if len(domain) <= len(suffix) {
return "", fmt.Errorf("publicsuffix: cannot derive eTLD+1 for domain %q", domain)
}
i := len(domain) - len(suffix) - 1
if domain[i] != '.' {
return "", fmt.Errorf("publicsuffix: invalid public suffix %q for domain %q", suffix, domain)
}
return domain[1+strings.LastIndex(domain[:i], "."):], nil
}

9074
vendor/golang.org/x/net/publicsuffix/table.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

22
vendor/gopkg.in/resty.v0/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-2016 Jeevanandam M (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.

584
vendor/gopkg.in/resty.v0/README.md generated vendored Normal file
View File

@ -0,0 +1,584 @@
# resty [![Build Status](https://travis-ci.org/go-resty/resty.svg?branch=master)](https://travis-ci.org/go-resty/resty) [![codecov](https://codecov.io/gh/go-resty/resty/branch/master/graph/badge.svg)](https://codecov.io/gh/go-resty/resty/branch/master) [![GoReport](https://goreportcard.com/badge/go-resty/resty)](https://goreportcard.com/report/go-resty/resty) [![GoDoc](https://godoc.org/github.com/go-resty/resty?status.svg)](https://godoc.org/github.com/go-resty/resty) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
Simple HTTP and REST client for Go inspired by Ruby rest-client. [Features](#features) section describes in detail about resty capabilities.
***v0.9 [released](https://github.com/go-resty/resty/releases/latest) and tagged on Nov 01, 2016.***
*Since Go v1.6 HTTP/2 & HTTP/1.1 protocol is used transparently. `Resty` works fine with HTTP/2 and HTTP/1.1.*
#### Roadmap
***v0.10***
I will be focusing on golint, etc. code quality improvements (may have very minor breaking change due to golint)
***v1.0 (Around New Year)***
Go Resty first released on Sep 15, 2015 then go-resty grew gradually as a very handy and helpful library of HTTP & REST Client in the golang community. I'm planning to freeze API and make v1.0 release.
#### Features
* GET, POST, PUT, DELETE, HEAD, PATCH and OPTIONS
* Simple and chainable methods for settings and request
* Request Body can be `string`, `[]byte`, `struct`, `map`, `slice` and `io.Reader` too
* Auto detects `Content-Type`
* [Response](https://godoc.org/github.com/go-resty/resty#Response) object gives you more possibility
* Access as `[]byte` array - `response.Body()` OR Access as `string` - `response.String()`
* Know your `response.Time()` and when we `response.ReceivedAt()`
* Automatic marshal and unmarshal for `JSON` and `XML` content type
* Default is `JSON`, if you supply `struct/map` without header `Content-Type`
* Easy to upload one or more file(s) via `multipart/form-data`
* Backoff Retry Mechanism with retry condition function [reference](retry_test.go)
* resty client [Request](https://godoc.org/github.com/go-resty/resty#Client.OnBeforeRequest) and [Response](https://godoc.org/github.com/go-resty/resty#Client.OnAfterResponse) middlewares
* Authorization option of `BasicAuth` and `Bearer` token
* Set request `ContentLength` value for all request or particular request
* Choose between HTTP and REST mode. Default is `REST`
* `HTTP` - default up to 10 redirects and no automatic response unmarshal
* `REST` - defaults to no redirects and automatic response marshal/unmarshal for `JSON` & `XML`
* Custom [Root Certificates](https://godoc.org/github.com/go-resty/resty#Client.SetRootCertificate) and Client [Certificates](https://godoc.org/github.com/go-resty/resty#Client.SetCertificates)
* Download/Save HTTP response directly into File, like `curl -o` flag. See [SetOutputDirectory](https://godoc.org/github.com/go-resty/resty#Client.SetOutputDirectory) & [SetOutput](https://godoc.org/github.com/go-resty/resty#Request.SetOutput).
* Cookies for your request and CookieJar support
* Client settings like `Timeout`, `RedirectPolicy`, `Proxy`, `TLSClientConfig`, `Transport`, etc.
* Client API design
* Have client level settings & options and also override at Request level if you want to
* Create Multiple clients if want to `resty.New()`
* goroutine concurrent safe
* Debug mode - clean and informative logging presentation
* Gzip - I'm not doing anything here. Go does it automatically
* Well tested client library
resty tested with Go `v1.2` and above.
#### Included Batteries
* Redirect Policies - see [how to use in action](#redirect-policy)
* NoRedirectPolicy
* FlexibleRedirectPolicy
* DomainCheckRedirectPolicy
* etc. [more info](redirect.go)
* Backoff Retry Mechanism with retry condition function [reference](retry_test.go)
* etc (upcoming - throw your idea's [here](https://github.com/go-resty/resty/issues)).
## Installation
#### Stable - Version
Please refer section [Versioning](#versioning) for detailed info.
```sh
# install the library
go get -u gopkg.in/resty.v0
```
#### Latest
```sh
# install the latest & greatest library
go get -u github.com/go-resty/resty
```
## Usage
Following samples will assist you to become as much comfortable as possible with resty library. Resty comes with ready to use DefaultClient.
Import resty into your code and refer it as `resty`.
```go
import (
"gopkg.in/resty.v0"
)
```
#### Simple GET
```go
// GET request
resp, err := resty.R().Get("http://httpbin.org/get")
// explore response object
fmt.Printf("\nError: %v", err)
fmt.Printf("\nResponse Status Code: %v", resp.StatusCode())
fmt.Printf("\nResponse Status: %v", resp.Status())
fmt.Printf("\nResponse Time: %v", resp.Time())
fmt.Printf("\nResponse Recevied At: %v", resp.ReceivedAt())
fmt.Printf("\nResponse Body: %v", resp) // or resp.String() or string(resp.Body())
// more...
/* Output
Error: <nil>
Response Status Code: 200
Response Status: 200 OK
Response Time: 644.290186ms
Response Recevied At: 2015-09-15 12:05:28.922780103 -0700 PDT
Response Body: {
"args": {},
"headers": {
"Accept-Encoding": "gzip",
"Host": "httpbin.org",
"User-Agent": "go-resty v0.1 - https://github.com/go-resty/resty"
},
"origin": "0.0.0.0",
"url": "http://httpbin.org/get"
}
*/
```
#### Enhanced GET
```go
resp, err := resty.R().
SetQueryParams(map[string]string{
"page_no": "1",
"limit": "20",
"sort":"name",
"order": "asc",
"random":strconv.FormatInt(time.Now().Unix(), 10),
}).
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/search_result")
// Sample of using Request.SetQueryString method
resp, err := resty.R().
SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/show_product")
```
#### Various POST method combinations
```go
// POST JSON string
// No need to set content type, if you have client level setting
resp, err := resty.R().
SetHeader("Content-Type", "application/json").
SetBody(`{"username":"testuser", "password":"testpass"}`).
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
Post("https://myapp.com/login")
// POST []byte array
// No need to set content type, if you have client level setting
resp, err := resty.R().
SetHeader("Content-Type", "application/json").
SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
Post("https://myapp.com/login")
// POST Struct, default is JSON content type. No need to set one
resp, err := resty.R().
SetBody(User{Username: "testuser", Password: "testpass"}).
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
SetError(&AuthError{}). // or SetError(AuthError{}).
Post("https://myapp.com/login")
// POST Map, default is JSON content type. No need to set one
resp, err := resty.R().
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
SetError(&AuthError{}). // or SetError(AuthError{}).
Post("https://myapp.com/login")
// POST of raw bytes for file upload. For example: upload file to Dropbox
fileBytes, _ := ioutil.ReadFile("/Users/jeeva/mydocument.pdf")
// See we are not setting content-type header, since go-resty automatically detects Content-Type for you
resp, err := resty.R().
SetBody(fileBytes).
SetContentLength(true). // Dropbox expects this value
SetAuthToken("<your-auth-token>").
SetError(&DropboxError{}). // or SetError(DropboxError{}).
Post("https://content.dropboxapi.com/1/files_put/auto/resty/mydocument.pdf") // for upload Dropbox supports PUT too
// Note: resty detects Content-Type for request body/payload if content type header is not set.
// * For struct and map data type defaults to 'application/json'
// * Fallback is plain text content type
```
#### Sample PUT
You can use various combinations of `PUT` method call like demonstrated for `POST`.
```go
// Note: This is one sample of PUT method usage, refer POST for more combination
// Request goes as JSON content type
// No need to set auth token, error, if you have client level settings
resp, err := resty.R().
SetBody(Article{
Title: "go-resty",
Content: "This is my article content, oh ya!",
Author: "Jeevanandam M",
Tags: []string{"article", "sample", "resty"},
}).
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&Error{}). // or SetError(Error{}).
Put("https://myapp.com/article/1234")
```
#### Sample PATCH
You can use various combinations of `PATCH` method call like demonstrated for `POST`.
```go
// Note: This is one sample of PUT method usage, refer POST for more combination
// Request goes as JSON content type
// No need to set auth token, error, if you have client level settings
resp, err := resty.R().
SetBody(Article{
Tags: []string{"new tag1", "new tag2"},
}).
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&Error{}). // or SetError(Error{}).
Patch("https://myapp.com/articles/1234")
```
#### Sample DELETE, HEAD, OPTIONS
```go
// DELETE a article
// No need to set auth token, error, if you have client level settings
resp, err := resty.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&Error{}). // or SetError(Error{}).
Delete("https://myapp.com/articles/1234")
// DELETE a articles with payload/body as a JSON string
// No need to set auth token, error, if you have client level settings
resp, err := resty.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&Error{}). // or SetError(Error{}).
SetHeader("Content-Type", "application/json").
SetBody(`{article_ids: [1002, 1006, 1007, 87683, 45432] }`).
Delete("https://myapp.com/articles")
// HEAD of resource
// No need to set auth token, if you have client level settings
resp, err := resty.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
Head("https://myapp.com/videos/hi-res-video")
// OPTIONS of resource
// No need to set auth token, if you have client level settings
resp, err := resty.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
Options("https://myapp.com/servers/nyc-dc-01")
```
### Multipart File(s) upload
#### Using io.Reader
```go
profileImgBytes, _ := ioutil.ReadFile("/Users/jeeva/test-img.png")
notesBytes, _ := ioutil.ReadFile("/Users/jeeva/text-file.txt")
resp, err := dclr().
SetFileReader("profile_img", "test-img.png", bytes.NewReader(profileImgBytes)).
SetFileReader("notes", "text-file.txt", bytes.NewReader(notesBytes)).
SetFormData(map[string]string{
"first_name": "Jeevanandam",
"last_name": "M",
}).
Post(t"http://myapp.com/upload")
```
#### Using File directly from Path
```go
// Single file scenario
resp, err := resty.R().
SetFile("profile_img", "/Users/jeeva/test-img.png").
Post("http://myapp.com/upload")
// Multiple files scenario
resp, err := resty.R().
SetFiles(map[string]string{
"profile_img": "/Users/jeeva/test-img.png",
"notes": "/Users/jeeva/text-file.txt",
}).
Post("http://myapp.com/upload")
// Multipart of form fields and files
resp, err := resty.R().
SetFiles(map[string]string{
"profile_img": "/Users/jeeva/test-img.png",
"notes": "/Users/jeeva/text-file.txt",
}).
SetFormData(map[string]string{
"first_name": "Jeevanandam",
"last_name": "M",
"zip_code": "00001",
"city": "my city",
"access_token": "C6A79608-782F-4ED0-A11D-BD82FAD829CD",
}).
Post("http://myapp.com/profile")
```
#### Sample Form submision
```go
// just mentioning about POST as an example with simple flow
// User Login
resp, err := resty.R().
SetFormData(map[string]string{
"username": "jeeva",
"password": "mypass",
}).
Post("http://myapp.com/login")
// Followed by profile update
resp, err := resty.R().
SetFormData(map[string]string{
"first_name": "Jeevanandam",
"last_name": "M",
"zip_code": "00001",
"city": "new city update",
}).
Post("http://myapp.com/profile")
// Multi value form data
criteria := url.Values{
"search_criteria": []string{"book", "glass", "pencil"},
}
resp, err := resty.R().
SetMultiValueFormData(criteria).
Post("http://myapp.com/search")
```
#### Save HTTP Response into File
```go
// Setting output directory path, If directory not exists then resty creates one!
// This is optional one, if you're planning using absoule path in
// `Request.SetOutput` and can used together.
resty.SetOutputDirectory("/Users/jeeva/Downloads")
// HTTP response gets saved into file, similar to curl -o flag
_, err := resty.R().
SetOutput("plugin/ReplyWithHeader-v5.1-beta.zip").
Get("http://bit.ly/1LouEKr")
// OR using absolute path
// Note: output directory path is not used for absoulte path
_, err := resty.R().
SetOutput("/MyDownloads/plugin/ReplyWithHeader-v5.1-beta.zip").
Get("http://bit.ly/1LouEKr")
```
#### Request and Response Middleware
Resty provides middleware ability to manipulate for Request and Response. It is more flexible than callback approach.
```go
// Registering Request Middleware
resty.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
// Now you have access to Client and current Request object
// manipulate it as per your need
return nil // if its success otherwise return error
})
// Registering Response Middleware
resty.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
// Now you have access to Client and current Response object
// manipulate it as per your need
return nil // if its success otherwise return error
})
```
#### Redirect Policy
Resty provides few ready to use redirect policy(s) also it supports multiple policies together.
```go
// Assign Client Redirect Policy. Create one as per you need
resty.SetRedirectPolicy(resty.FlexibleRedirectPolicy(15))
// Wanna multiple policies such as redirect count, domain name check, etc
resty.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20),
resty.DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
```
##### Custom Redirect Policy
Implement [RedirectPolicy](redirect.go#L20) interface and register it with resty client. Have a look [redirect.go](redirect.go) for more information.
```go
// Using raw func into resty.SetRedirectPolicy
resty.SetRedirectPolicy(resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
// Implement your logic here
// return nil for continue redirect otherwise return error to stop/prevent redirect
return nil
}))
//---------------------------------------------------
// Using struct create more flexible redirect policy
type CustomRedirectPolicy struct {
// variables goes here
}
func (c *CustomRedirectPolicy) Apply(req *http.Request, via []*http.Request) error {
// Implement your logic here
// return nil for continue redirect otherwise return error to stop/prevent redirect
return nil
}
// Registering in resty
resty.SetRedirectPolicy(CustomRedirectPolicy{/* initialize variables */})
```
#### Custom Root Certificates and Client Certifcates
```go
// Custom Root certificates, just supply .pem file.
// you can add one or more root certificates, its get appended
resty.SetRootCertificate("/path/to/root/pemFile1.pem")
resty.SetRootCertificate("/path/to/root/pemFile2.pem")
// ... and so on!
// Adding Client Certificates, you add one or more certificates
// Sample for creating certificate object
// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
cert1, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
if err != nil {
log.Fatalf("ERROR client certificate: %s", err)
}
// ...
// You add one or more certificates
resty.SetCertificates(cert1, cert2, cert3)
```
#### Proxy Settings - Client as well as at Request Level
Default `Go` supports Proxy via environment variable `HTTP_PROXY`. Resty provides support via `SetProxy` & `RemoveProxy`.
Choose as per your need.
**Client Level Proxy** settings applied to all the request
```go
// Setting a Proxy URL and Port
resty.SetProxy("http://proxyserver:8888")
// Want to remove proxy setting
resty.RemoveProxy()
```
**Request Level Proxy** settings, gives control to override at individal request level
```go
// Set proxy for current request
resp, err := c.R().
SetProxy("http://sampleproxy:8888").
Get("http://httpbin.org/get")
```
#### Choose REST or HTTP mode
```go
// REST mode. This is Default.
resty.SetRESTMode()
// HTTP mode
resty.SetHTTPMode()
```
#### Wanna Multiple Clients
```go
// Here you go!
// Client 1
client1 := resty.New()
client1.R().Get("http://httpbin.org")
// ...
// Client 2
client2 := resty.New()
client1.R().Head("http://httpbin.org")
// ...
// Bend it as per your need!!!
```
#### Remaining Client Settings & its Options
```go
// Unique settings at Client level
//--------------------------------
// Enable debug mode
resty.SetDebug(true)
// Using you custom log writer
logFile, _ := os.OpenFile("/Users/jeeva/go-resty.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
resty.SetLogger(logFile)
// Assign Client TLSClientConfig
// 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 })
// Set client timeout as per your need
resty.SetTimeout(time.Duration(1 * time.Minute))
// You can override all below settings and options at request level if you want to
//--------------------------------------------------------------------------------
// Host URL for all request. So you can use relative URL in the request
resty.SetHostURL("http://httpbin.org")
// Headers for all request
resty.SetHeader("Accept", "application/json")
resty.SetHeaders(map[string]string{
"Content-Type": "application/json",
"User-Agent": "My custom User Agent String",
})
// Cookies for all request
resty.SetCookie(&http.Cookie{
Name:"go-resty",
Value:"This is cookie value",
Path: "/",
Domain: "sample.com",
MaxAge: 36000,
HttpOnly: true,
Secure: false,
})
resty.SetCookies(cookies)
// URL query parameters for all request
resty.SetQueryParam("user_id", "00001")
resty.SetQueryParams(map[string]string{ // sample of those who use this manner
"api_key": "api-key-here",
"api_secert": "api-secert",
})
resty.R().SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")
// Form data for all request. Typically used with POST and PUT
resty.SetFormData(map[string]string{
"access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
})
// Basic Auth for all request
resty.SetBasicAuth("myuser", "mypass")
// Bearer Auth Token for all request
resty.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
// Enabling Content length value for all request
resty.SetContentLength(true)
// Registering global Error object structure for JSON/XML request
resty.SetError(&Error{}) // or resty.SetError(Error{})
```
#### Unix Socket
```go
unixSocket := "unix:///var/run/my_socket.sock"
// Create a Go's http.Transport so we can set it in resty.
transport := http.Transport{
Dial: func(_, _ string) (net.Conn, error) {
return net.Dial("unix", unixSocket)
},
}
// Set the previous transport that we created, set the scheme of the communication to the
// socket and set the unixSocket as the HostURL.
r := resty.New().SetTransport(transport).SetScheme("http").SetHostURL(unixSocket)
// No need to write the host's URL on the request, just the path.
r.R().Get("/index.html")
```
## Versioning
resty releases versions according to [Semantic Versioning](http://semver.org)
`gopkg.in/resty.vX` points to appropriate tag versions; `X` denotes version number and it's a stable release. It's recommended to use version, for eg. `gopkg.in/resty.v0`. Development takes place at the master branch. Although the code in master should always compile and test successfully, it might break API's. We aim to maintain backwards compatibility, but API's and behaviour might be changed to fix a bug.
## Contributing
Welcome! If you find any improvement or issue you want to fix, feel free to send a pull request, I like pull requests that include test cases for fix/enhancement. I have done my best to bring pretty good code coverage. Feel free to write tests.
BTW, I'd like to know what you think about go-resty. Kindly open an issue or send me an email; it'd mean a lot to me.
## Author
Jeevanandam M. - jeeva@myjeeva.com
## Contributors
Have a look on [Contributors](https://github.com/go-resty/resty/graphs/contributors) page.
## License
resty released under MIT license, refer [LICENSE](LICENSE) file.

931
vendor/gopkg.in/resty.v0/client.go generated vendored Normal file
View File

@ -0,0 +1,931 @@
// Copyright (c) 2015-2016 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"
"crypto/tls"
"crypto/x509"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strings"
"sync"
"time"
)
const (
// GET HTTP method
GET = "GET"
// POST HTTP method
POST = "POST"
// PUT HTTP method
PUT = "PUT"
// DELETE HTTP method
DELETE = "DELETE"
// PATCH HTTP method
PATCH = "PATCH"
// HEAD HTTP method
HEAD = "HEAD"
// OPTIONS HTTP method
OPTIONS = "OPTIONS"
)
var (
hdrUserAgentKey = http.CanonicalHeaderKey("User-Agent")
hdrAcceptKey = http.CanonicalHeaderKey("Accept")
hdrContentTypeKey = http.CanonicalHeaderKey("Content-Type")
hdrContentLengthKey = http.CanonicalHeaderKey("Content-Length")
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)")
xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)")
hdrUserAgentValue = "go-resty v%s - https://github.com/go-resty/resty"
)
// 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
Log *log.Logger
RetryCount int
RetryConditions []RetryConditionFunc
httpClient *http.Client
transport *http.Transport
setContentLength bool
isHTTPMode bool
outputDirectory string
scheme string
proxyURL *url.URL
mutex *sync.Mutex
closeConnection bool
beforeRequest []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
}
// 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
}
// SetCookie method sets 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 paramater 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.Add(param, value)
return c
}
// SetQueryParams method sets multiple paramaters and its 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.QueryParam.Add(p, v)
}
return c
}
// SetFormData method sets Form parameters and its 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.Add(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{
URL: "",
Method: "",
QueryParam: url.Values{},
FormData: url.Values{},
Header: http.Header{},
Body: nil,
Result: nil,
Error: nil,
RawRequest: nil,
client: c,
bodyBuf: nil,
proxyURL: nil,
multipartFiles: []*File{},
}
return r
}
// OnBeforeRequest method sets 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.beforeRequest[len(c.beforeRequest)-1] = m
c.beforeRequest = append(c.beforeRequest, requestLogger)
return c
}
// OnAfterResponse method sets 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
}
// 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
}
// 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
}
// 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
}
// 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)",
runtime.FuncForPC(reflect.ValueOf(p).Pointer()).Name())
}
}
c.httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
for _, p := range policies {
err := p.(RedirectPolicy).Apply(req, via)
if 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
}
// 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 into HTTP
func (c *Client) SetHTTPMode() *Client {
return c.SetMode("http")
}
// SetRESTMode method sets go-resty mode into RESTful
func (c *Client) SetRESTMode() *Client {
return c.SetMode("rest")
}
// SetMode method sets go-resty client mode to given value such as 'http' & 'rest'.
// RESTful:
// - No Redirect
// - Automatic response unmarshal if it is JSON or XML
// HTML:
// - 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 {
if mode == "http" {
c.isHTTPMode = true
c.SetRedirectPolicy(FlexibleRedirectPolicy(10))
c.afterResponse = []func(*Client, *Response) error{
responseLogger,
saveResponseIntoFile,
}
} else { // 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 {
c.transport.TLSClientConfig = config
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.transport.Dial = func(network, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(network, addr, timeout)
if err != nil {
c.Log.Printf("ERROR [%v]", err)
return nil, err
}
conn.SetDeadline(time.Now().Add(timeout))
return conn, nil
}
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 {
if pURL, err := url.Parse(proxyURL); err == nil {
c.proxyURL = pURL
} else {
c.Log.Printf("ERROR [%v]", err)
c.proxyURL = nil
}
return c
}
// RemoveProxy method removes the proxy configuration from resty client
// resty.RemoveProxy()
//
func (c *Client) RemoveProxy() *Client {
c.proxyURL = nil
return c
}
// SetCertificates method helps to set client certificates into resty conveniently.
//
func (c *Client) SetCertificates(certs ...tls.Certificate) *Client {
config := c.getTLSConfig()
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 := c.getTLSConfig()
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 {
err := createDirectory(dirPath)
if err != nil {
c.Log.Printf("ERROR [%v]", err)
}
c.outputDirectory = dirPath
return c
}
// SetTransport method sets custom *http.Transport in the resty client. Its way to override default.
//
// **Note:** It overwrites the default resty transport instance and its 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.Transport) *Client {
if transport != nil {
c.transport = transport
}
return c
}
// SetScheme method sets custom scheme in the resty client. Its way to override default.
// resty.SetScheme("http")
//
func (c *Client) SetScheme(scheme string) *Client {
if c.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
}
// executes the given `Request` object and returns response
func (c *Client) execute(req *Request) (*Response, error) {
// Apply Request middleware
var err error
for _, f := range c.beforeRequest {
err = f(c, req)
if err != nil {
return nil, err
}
}
c.mutex.Lock()
if req.proxyURL != nil {
c.transport.Proxy = http.ProxyURL(req.proxyURL)
} else if c.proxyURL != nil {
c.transport.Proxy = http.ProxyURL(c.proxyURL)
}
req.Time = time.Now()
c.httpClient.Transport = c.transport
resp, err := c.httpClient.Do(req.RawRequest)
c.mutex.Unlock()
response := &Response{
Request: req,
RawResponse: resp,
receivedAt: time.Now(),
}
if err != nil {
return response, err
}
if !req.isSaveResponse {
defer resp.Body.Close()
response.body, err = ioutil.ReadAll(resp.Body)
if err != nil {
return response, err
}
response.size = int64(len(response.body))
}
// Apply Response middleware
for _, f := range c.afterResponse {
err = f(c, response)
if err != nil {
break
}
}
return response, err
}
// enables a log prefix
func (c *Client) enableLogPrefix() {
c.Log.SetFlags(log.LstdFlags)
c.Log.SetPrefix("RESTY ")
}
// 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 {
if c.transport.TLSClientConfig == nil {
c.transport.TLSClientConfig = &tls.Config{}
}
return c.transport.TLSClientConfig
}
//
// Response
//
// 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 {
return r.body
}
// Status method returns the HTTP status string for the executed request.
// Example: 200 OK
func (r *Response) Status() string {
return r.RawResponse.Status
}
// StatusCode method returns the HTTP status code for the executed request.
// Example: 200
func (r *Response) StatusCode() int {
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 {
return r.RawResponse.Header
}
// Cookies method to access all the response cookies
func (r *Response) Cookies() []*http.Cookie {
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
}
func (r *Response) fmtBodyString() string {
bodyStr := "***** NO CONTENT *****"
if r.body != nil {
ct := r.Header().Get(hdrContentTypeKey)
if IsJSONType(ct) {
var out bytes.Buffer
if err := json.Indent(&out, r.body, "", " "); err == nil {
bodyStr = string(out.Bytes())
}
} else {
bodyStr = r.String()
}
}
return bodyStr
}
//
// 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)
}
//
// 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
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
}
func getLogger(w io.Writer) *log.Logger {
return log.New(w, "RESTY ", log.LstdFlags)
}
func addFile(w *multipart.Writer, fieldName, path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
part, err := w.CreateFormFile(fieldName, filepath.Base(path))
if err != nil {
return err
}
_, err = io.Copy(part, file)
return err
}
func addFileReader(w *multipart.Writer, f *File) error {
part, err := w.CreateFormFile(f.ParamName, f.Name)
if err != nil {
return err
}
_, err = io.Copy(part, f.Reader)
return err
}
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) bool {
return (m == POST || m == PUT || m == DELETE || m == PATCH)
}
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
}

244
vendor/gopkg.in/resty.v0/default.go generated vendored Normal file
View File

@ -0,0 +1,244 @@
// Copyright (c) 2015-2016 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"
"io"
"net/http"
"net/http/cookiejar"
"net/url"
"os"
"sync"
"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})
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),
httpClient: &http.Client{Jar: cookieJar},
transport: &http.Transport{},
mutex: &sync.Mutex{},
RetryCount: 0,
}
// Default redirect policy
c.SetRedirectPolicy(NoRedirectPolicy())
// default before request middlewares
c.beforeRequest = []func(*Client, *Request) error{
parseRequestURL,
parseRequestHeader,
parseRequestBody,
createHTTPRequest,
addCredentials,
requestLogger,
}
// default after response middlewares
c.afterResponse = []func(*Client, *Response) error{
responseLogger,
parseResponseBody,
saveResponseIntoFile,
}
return c
}
// 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()
}
// 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)
}
// 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 paramater and its value. See `Client.SetQueryParam` for more information.
func SetQueryParam(param, value string) *Client {
return DefaultClient.SetQueryParam(param, value)
}
// SetQueryParams method sets multiple paramaters 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)
}
// SetDebug method enables the debug mode. See `Client.SetDebug` for more information.
func SetDebug(d bool) *Client {
return DefaultClient.SetDebug(d)
}
// SetRetryCount method set the retry count. See `Client.SetRetryCount` for more information.
func SetRetryCount(count int) *Client {
return DefaultClient.SetRetryCount(count)
}
// 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 in the resty client.
// See `Client.SetTransport` for more information.
func SetTransport(transport *http.Transport) *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)
}
func init() {
DefaultClient = New()
}

406
vendor/gopkg.in/resty.v0/middleware.go generated vendored Normal file
View File

@ -0,0 +1,406 @@
// Copyright (c) 2015-2016 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"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"path/filepath"
"reflect"
"strings"
)
//
// Request Middleware(s)
//
func parseRequestURL(c *Client, r *Request) error {
// 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() {
if !strings.HasPrefix(r.URL, "/") {
r.URL = "/" + r.URL
}
reqURL, err = url.Parse(c.HostURL + r.URL)
if err != nil {
return err
}
}
// Adding Query Param
query := reqURL.Query()
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)
}
}
reqURL.RawQuery = query.Encode()
r.URL = reqURL.String()
return nil
}
func parseRequestHeader(c *Client, r *Request) error {
hdr := http.Header{}
for k := range c.Header {
hdr.Set(k, c.Header.Get(k))
}
for k := range r.Header {
hdr.Set(k, r.Header.Get(k))
}
if IsStringEmpty(hdr.Get(hdrUserAgentKey)) {
hdr.Set(hdrUserAgentKey, fmt.Sprintf(hdrUserAgentValue, Version))
} else {
hdr.Set("X-"+hdrUserAgentKey, fmt.Sprintf(hdrUserAgentValue, Version))
}
if IsStringEmpty(hdr.Get(hdrAcceptKey)) && !IsStringEmpty(hdr.Get(hdrContentTypeKey)) {
hdr.Set(hdrAcceptKey, hdr.Get(hdrContentTypeKey))
}
r.Header = hdr
return nil
}
func parseRequestBody(c *Client, r *Request) (err error) {
if isPayloadSupported(r.Method) {
// Handling Multipart
if r.isMultiPart && !(r.Method == PATCH) {
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
}
}
} else {
r.Header.Del(hdrContentTypeKey)
}
CL:
// by default resty won't set content length, you can if you want to :)
if c.setContentLength || r.setContentLength {
r.Header.Set(hdrContentLengthKey, fmt.Sprintf("%d", r.bodyBuf.Len()))
}
return
}
func createHTTPRequest(c *Client, r *Request) (err error) {
if r.bodyBuf == nil {
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
}
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
c.Log.Println()
c.disableLogPrefix()
c.Log.Println("---------------------- REQUEST LOG -----------------------")
c.Log.Printf("%s %s %s\n", r.Method, rr.URL.RequestURI(), rr.Proto)
c.Log.Printf("HOST : %s", rr.URL.Host)
c.Log.Println("HEADERS:")
for h, v := range rr.Header {
c.Log.Printf("%25s: %v", h, strings.Join(v, ", "))
}
c.Log.Printf("BODY :\n%v", r.fmtBodyString())
c.Log.Println("----------------------------------------------------------")
c.enableLogPrefix()
}
return nil
}
//
// Response Middleware(s)
//
func responseLogger(c *Client, res *Response) error {
if c.Debug {
c.Log.Println()
c.disableLogPrefix()
c.Log.Println("---------------------- RESPONSE LOG -----------------------")
c.Log.Printf("STATUS : %s", res.Status())
c.Log.Printf("RECEIVED AT : %v", res.ReceivedAt())
c.Log.Printf("RESPONSE TIME : %v", res.Time())
c.Log.Println("HEADERS:")
for h, v := range res.Header() {
c.Log.Printf("%30s: %v", h, strings.Join(v, ", "))
}
if res.Request.isSaveResponse {
c.Log.Printf("BODY :\n***** RESPONSE WRITTEN INTO FILE *****")
} else {
c.Log.Printf("BODY :\n%v", res.fmtBodyString())
}
c.Log.Println("----------------------------------------------------------")
c.enableLogPrefix()
}
return nil
}
func parseResponseBody(c *Client, res *Response) (err error) {
// Handles only JSON or XML content type
ct := res.Header().Get(hdrContentTypeKey)
if IsJSONType(ct) || IsXMLType(ct) {
// Considered as Result
if res.StatusCode() > 199 && res.StatusCode() < 300 {
if res.Request.Result != nil {
err = Unmarshal(ct, res.body, res.Request.Result)
}
}
// Considered as Error
if res.StatusCode() > 399 {
// 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 = Unmarshal(ct, res.body, res.Request.Error)
}
}
}
return
}
func handleMultipart(c *Client, r *Request) (err error) {
r.bodyBuf = &bytes.Buffer{}
w := multipart.NewWriter(r.bodyBuf)
for k, v := range c.FormData {
for _, iv := range v {
w.WriteField(k, iv)
}
}
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
w.WriteField(k, iv)
}
}
}
// #21 - adding io.Reader support
if len(r.multipartFiles) > 0 {
for _, f := range r.multipartFiles {
err = addFileReader(w, f)
if 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)
if reader, ok := r.Body.(io.Reader); ok {
r.bodyBuf = &bytes.Buffer{}
r.bodyBuf.ReadFrom(reader)
} 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 = json.Marshal(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 = bytes.NewBuffer(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)
err := createDirectory(filepath.Dir(file))
if err != nil {
return err
}
outFile, err := os.Create(file)
if err != nil {
return err
}
defer outFile.Close()
// io.Copy reads maximum 32kb size, it is perfect for large file download too
defer res.RawResponse.Body.Close()
written, err := io.Copy(outFile, res.RawResponse.Body)
if err != nil {
return err
}
res.size = written
}
return nil
}

99
vendor/gopkg.in/resty.v0/redirect.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright (c) 2015 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"
)
// 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.
type 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.
type 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)
} else {
hostname = strings.ToLower(host)
}
return
}
// By default Golang will not redirect request headers
// after go throughing various discussion commments 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))
}
}

494
vendor/gopkg.in/resty.v0/request.go generated vendored Normal file
View File

@ -0,0 +1,494 @@
// Copyright (c) 2015-2016 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/base64"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"net/http"
"net/url"
"reflect"
"strings"
"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
QueryParam url.Values
FormData url.Values
Header http.Header
UserInfo *User
Token string
Body interface{}
Result interface{}
Error interface{}
Time time.Time
RawRequest *http.Request
client *Client
bodyBuf *bytes.Buffer
isMultiPart bool
isFormData bool
setContentLength bool
isSaveResponse bool
outputFile string
proxyURL *url.URL
multipartFiles []*File
}
// 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.Header.Set(h, v)
}
return r
}
// SetQueryParam method sets single paramater 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.Add(param, value)
return r
}
// SetQueryParams method sets multiple paramaters 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.QueryParam.Add(p, v)
}
return r
}
// SetMultiValueQueryParams method sets multiple paramaters 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 {
values, err := url.ParseQuery(strings.TrimSpace(query))
if err == nil {
for k := range values {
r.QueryParam.Add(k, values.Get(k))
}
} else {
r.client.Log.Printf("ERROR [%v]", err)
}
return r
}
// SetFormData method sets Form parameters and its values in the current request.
// It's applicable only HTTP method `POST` and `PUT` and requets 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.Add(k, v)
}
return r
}
// SetMultiValueFormData method sets multiple form paramaters 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
}
// 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. Absoulte 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
}
// SetProxy method sets the Proxy URL for current Request. It does not affect client level
// proxy settings. Request level proxy settings takes higher priority, even though client
// level proxy settings exists.
// resty.R().
// SetProxy("http://proxyserver:8888").
// Get("http://httpbin.org/get")
//
func (r *Request) SetProxy(proxyURL string) *Request {
if pURL, err := url.Parse(proxyURL); err == nil {
r.proxyURL = pURL
} else {
r.client.Log.Printf("ERROR [%v]", err)
r.proxyURL = nil
}
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(GET, 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(HEAD, 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(POST, 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(PUT, 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(DELETE, 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(OPTIONS, 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(PATCH, 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) {
if r.isMultiPart && !(method == POST || method == PUT) {
return nil, fmt.Errorf("Multipart content is not allowed in HTTP verb [%v]", method)
}
r.Method = method
r.URL = url
if r.client.RetryCount == 0 {
return r.client.execute(r)
}
var resp *Response
var err error
attempt := 0
_ = Backoff(func() (*Response, error) {
attempt++
resp, err = r.client.execute(r)
if err != nil {
r.client.Log.Printf("ERROR [%v] Attempt [%v]", err, attempt)
}
return resp, err
}, Retries(r.client.RetryCount), RetryConditions(r.client.RetryConditions))
return resp, err
}
func (r *Request) fmtBodyString() (body string) {
body = "***** NO CONTENT *****"
if isPayloadSupported(r.Method) {
// multipart or form-data
if r.isMultiPart || r.isFormData {
body = string(r.bodyBuf.Bytes())
return
}
// request body data
if r.Body != nil {
var prtBodyBytes []byte
var err error
contentType := r.Header.Get(hdrContentTypeKey)
kind := kindOf(r.Body)
if IsJSONType(contentType) && (kind == reflect.Struct || kind == reflect.Map) {
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)
var out bytes.Buffer
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 {
body = string(prtBodyBytes)
}
}
}
return
}

9
vendor/gopkg.in/resty.v0/resty.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// Copyright (c) 2015-2016 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 go-resty
var Version = "0.9"

110
vendor/gopkg.in/resty.v0/retry.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
// Copyright (c) 2015-2016 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 = 100 // base Milliseconds
defaultMaxWaitTime = 2000 // cap level Milliseconds
)
// Option is to create convenient retry options like wait time, max retries, etc.
type Option func(*Options)
// RetryConditionFunc type is for retry condition function
type RetryConditionFunc func(*Response) (bool, error)
// Options to hold go-resty retry values
type Options struct {
maxRetries int
waitTime int
maxWaitTime int
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 int) Option {
return func(o *Options) {
o.waitTime = value
}
}
// MaxWaitTime sets the max wait time to sleep between requests
func MaxWaitTime(value int) 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)))
sleepTime := int(temp/2) + rand.Intn(int(temp/2))
sleepDuration := time.Duration(sleepTime) * time.Millisecond
time.Sleep(sleepDuration)
}
return err
}

30
vendor/vendor.json vendored
View File

@ -2139,6 +2139,12 @@
"revision": "7cd5fed006859e86dd5641a6cf9812e855b7574a",
"revisionTime": "2016-08-11T16:27:25Z"
},
{
"checksumSHA1": "lOEkLP94OsQSLFp+38rY1GjnMtk=",
"path": "github.com/paultyng/go-newrelic/api",
"revision": "81a8e05b0e494285f1322f99f3c6f93c8f1192b1",
"revisionTime": "2016-11-29T00:49:55Z"
},
{
"path": "github.com/pborman/uuid",
"revision": "dee7705ef7b324f27ceb85a121c61f2c2e8ce988"
@ -2232,6 +2238,12 @@
"path": "github.com/tent/http-link-go",
"revision": "ac974c61c2f990f4115b119354b5e0b47550e888"
},
{
"checksumSHA1": "y1hkty5dgBN9elK4gP1TtVjT4e8=",
"path": "github.com/tomnomnom/linkheader",
"revision": "236df730ed7334edb33cb10ba79407491fb4e147",
"revisionTime": "2016-06-19T23:20:27Z"
},
{
"checksumSHA1": "jfIUoeCY4uLz1zCgnCxndi5/UNE=",
"path": "github.com/ugorji/go/codec",
@ -2365,6 +2377,18 @@
"path": "golang.org/x/net/context/ctxhttp",
"revision": "04b9de9b512f58addf28c9853d50ebef61c3953e"
},
{
"checksumSHA1": "GIGmSrYACByf5JDIP9ByBZksY80=",
"path": "golang.org/x/net/idna",
"revision": "4971afdc2f162e82d185353533d3cf16188a9f4e",
"revisionTime": "2016-11-15T21:05:04Z"
},
{
"checksumSHA1": "AmZIW67T/HUlTTflTmOIy6jdq74=",
"path": "golang.org/x/net/publicsuffix",
"revision": "4971afdc2f162e82d185353533d3cf16188a9f4e",
"revisionTime": "2016-11-15T21:05:04Z"
},
{
"path": "golang.org/x/oauth2",
"revision": "2897dcade18a126645f1368de827f1e613a60049"
@ -2505,6 +2529,12 @@
"comment": "v1.8.5",
"path": "gopkg.in/ini.v1",
"revision": "77178f22699a4ecafce485fb8d86b7afeb7e3e28"
},
{
"checksumSHA1": "mkLQOQwQwoUc9Kr9+PaVGrKUzI4=",
"path": "gopkg.in/resty.v0",
"revision": "24dc7ba4bc1ef9215048b28e7248f99c42901db5",
"revisionTime": "2016-11-01T17:03:53Z"
}
],
"rootPath": "github.com/hashicorp/terraform"