// 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 (
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
)

const (
	// MethodGet HTTP method
	MethodGet = "GET"

	// MethodPost HTTP method
	MethodPost = "POST"

	// MethodPut HTTP method
	MethodPut = "PUT"

	// MethodDelete HTTP method
	MethodDelete = "DELETE"

	// MethodPatch HTTP method
	MethodPatch = "PATCH"

	// MethodHead HTTP method
	MethodHead = "HEAD"

	// MethodOptions HTTP method
	MethodOptions = "OPTIONS"
)

var (
	hdrUserAgentKey       = http.CanonicalHeaderKey("User-Agent")
	hdrAcceptKey          = http.CanonicalHeaderKey("Accept")
	hdrContentTypeKey     = http.CanonicalHeaderKey("Content-Type")
	hdrContentLengthKey   = http.CanonicalHeaderKey("Content-Length")
	hdrContentEncodingKey = http.CanonicalHeaderKey("Content-Encoding")
	hdrLocationKey        = http.CanonicalHeaderKey("Location")
	hdrAuthorizationKey   = http.CanonicalHeaderKey("Authorization")
	hdrWwwAuthenticateKey = http.CanonicalHeaderKey("WWW-Authenticate")

	plainTextType   = "text/plain; charset=utf-8"
	jsonContentType = "application/json"
	formContentType = "application/x-www-form-urlencoded"

	jsonCheck = regexp.MustCompile(`(?i:(application|text)/(.*json.*)(;|$))`)
	xmlCheck  = regexp.MustCompile(`(?i:(application|text)/(.*xml.*)(;|$))`)

	hdrUserAgentValue = "go-resty/" + Version + " (https://github.com/go-resty/resty)"
	bufPool           = &sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
)

type (
	// RequestMiddleware type is for request middleware, called before a request is sent
	RequestMiddleware func(*Client, *Request) error

	// ResponseMiddleware type is for response middleware, called after a response has been received
	ResponseMiddleware func(*Client, *Response) error

	// PreRequestHook type is for the request hook, called right before the request is sent
	PreRequestHook func(*Client, *http.Request) error

	// RequestLogCallback type is for request logs, called before the request is logged
	RequestLogCallback func(*RequestLog) error

	// ResponseLogCallback type is for response logs, called before the response is logged
	ResponseLogCallback func(*ResponseLog) error

	// ErrorHook type is for reacting to request errors, called after all retries were attempted
	ErrorHook func(*Request, error)

	// SuccessHook type is for reacting to request success
	SuccessHook func(*Client, *Response)
)

// Client struct is used to create Resty client with client level settings,
// these settings are applicable to all the request raised from the client.
//
// Resty also provides an options to override most of the client settings
// at request level.
type Client struct {
	BaseURL               string
	HostURL               string // Deprecated: use BaseURL instead. To be removed in v3.0.0 release.
	QueryParam            url.Values
	FormData              url.Values
	PathParams            map[string]string
	RawPathParams         map[string]string
	Header                http.Header
	UserInfo              *User
	Token                 string
	AuthScheme            string
	Cookies               []*http.Cookie
	Error                 reflect.Type
	Debug                 bool
	DisableWarn           bool
	AllowGetMethodPayload bool
	RetryCount            int
	RetryWaitTime         time.Duration
	RetryMaxWaitTime      time.Duration
	RetryConditions       []RetryConditionFunc
	RetryHooks            []OnRetryFunc
	RetryAfter            RetryAfterFunc
	RetryResetReaders     bool
	JSONMarshal           func(v interface{}) ([]byte, error)
	JSONUnmarshal         func(data []byte, v interface{}) error
	XMLMarshal            func(v interface{}) ([]byte, error)
	XMLUnmarshal          func(data []byte, v interface{}) error

	// HeaderAuthorizationKey is used to set/access Request Authorization header
	// value when `SetAuthToken` option is used.
	HeaderAuthorizationKey string

	jsonEscapeHTML      bool
	setContentLength    bool
	closeConnection     bool
	notParseResponse    bool
	trace               bool
	debugBodySizeLimit  int64
	outputDirectory     string
	scheme              string
	log                 Logger
	httpClient          *http.Client
	proxyURL            *url.URL
	beforeRequest       []RequestMiddleware
	udBeforeRequest     []RequestMiddleware
	udBeforeRequestLock sync.RWMutex
	preReqHook          PreRequestHook
	successHooks        []SuccessHook
	afterResponse       []ResponseMiddleware
	afterResponseLock   sync.RWMutex
	requestLog          RequestLogCallback
	responseLog         ResponseLogCallback
	errorHooks          []ErrorHook
	invalidHooks        []ErrorHook
	panicHooks          []ErrorHook
	rateLimiter         RateLimiter
}

// User type is to hold an username and password information
type User struct {
	Username, Password string
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Client methods
//___________________________________

// SetHostURL method is to set Host URL in the client instance. It will be used with request
// raised from this client with relative URL
//
//	// Setting HTTP address
//	client.SetHostURL("http://myjeeva.com")
//
//	// Setting HTTPS address
//	client.SetHostURL("https://myjeeva.com")
//
// Deprecated: use SetBaseURL instead. To be removed in v3.0.0 release.
func ( *Client) ( string) *Client {
	.SetBaseURL()
	return 
}

// SetBaseURL method is to set Base URL in the client instance. It will be used with request
// raised from this client with relative URL
//
//	// Setting HTTP address
//	client.SetBaseURL("http://myjeeva.com")
//
//	// Setting HTTPS address
//	client.SetBaseURL("https://myjeeva.com")
//
// Since v2.7.0
func ( *Client) ( string) *Client {
	.BaseURL = strings.TrimRight(, "/")
	.HostURL = .BaseURL
	return 
}

// SetHeader method sets a single header field and its value in the client instance.
// These headers will be applied to all requests raised from this client instance.
// Also it can be overridden at request level header options.
//
// See `Request.SetHeader` or `Request.SetHeaders`.
//
// For Example: To set `Content-Type` and `Accept` as `application/json`
//
//	client.
//		SetHeader("Content-Type", "application/json").
//		SetHeader("Accept", "application/json")
func ( *Client) (,  string) *Client {
	.Header.Set(, )
	return 
}

// SetHeaders method sets multiple headers field and its values at one go in the client instance.
// These headers will be applied to all requests raised from this client instance. Also it can be
// overridden at request level headers options.
//
// See `Request.SetHeaders` or `Request.SetHeader`.
//
// For Example: To set `Content-Type` and `Accept` as `application/json`
//
//	client.SetHeaders(map[string]string{
//			"Content-Type": "application/json",
//			"Accept": "application/json",
//		})
func ( *Client) ( map[string]string) *Client {
	for ,  := range  {
		.Header.Set(, )
	}
	return 
}

// SetHeaderVerbatim method is to set a single header field and its value verbatim in the current request.
//
// For Example: To set `all_lowercase` and `UPPERCASE` as `available`.
//
//	client.R().
//		SetHeaderVerbatim("all_lowercase", "available").
//		SetHeaderVerbatim("UPPERCASE", "available")
//
// Also you can override header value, which was set at client instance level.
//
// Since v2.6.0
func ( *Client) (,  string) *Client {
	.Header[] = []string{}
	return 
}

// SetCookieJar method sets custom http.CookieJar in the resty client. Its way to override default.
//
// For Example: sometimes we don't want to save cookies in api contacting, we can remove the default
// CookieJar in resty client.
//
//	client.SetCookieJar(nil)
func ( *Client) ( http.CookieJar) *Client {
	.httpClient.Jar = 
	return 
}

// SetCookie method appends a single cookie in the client instance.
// These cookies will be added to all the request raised from this client instance.
//
//	client.SetCookie(&http.Cookie{
//				Name:"go-resty",
//				Value:"This is cookie value",
//			})
func ( *Client) ( *http.Cookie) *Client {
	.Cookies = append(.Cookies, )
	return 
}

// SetCookies method sets an array of cookies in the client instance.
// These cookies will be added to all the request raised from this client instance.
//
//	cookies := []*http.Cookie{
//		&http.Cookie{
//			Name:"go-resty-1",
//			Value:"This is cookie 1 value",
//		},
//		&http.Cookie{
//			Name:"go-resty-2",
//			Value:"This is cookie 2 value",
//		},
//	}
//
//	// Setting a cookies into resty
//	client.SetCookies(cookies)
func ( *Client) ( []*http.Cookie) *Client {
	.Cookies = append(.Cookies, ...)
	return 
}

// SetQueryParam method sets single parameter and its value in the client instance.
// It will be formed as query string for the request.
//
// For Example: `search=kitchen%20papers&size=large`
// in the URL after `?` mark. These query params will be added to all the request raised from
// this client instance. Also it can be overridden at request level Query Param options.
//
// See `Request.SetQueryParam` or `Request.SetQueryParams`.
//
//	client.
//		SetQueryParam("search", "kitchen papers").
//		SetQueryParam("size", "large")
func ( *Client) (,  string) *Client {
	.QueryParam.Set(, )
	return 
}

// SetQueryParams method sets multiple parameters and their values at one go in the client instance.
// It will be formed as query string for the request.
//
// For Example: `search=kitchen%20papers&size=large`
// in the URL after `?` mark. These query params will be added to all the request raised from this
// client instance. Also it can be overridden at request level Query Param options.
//
// See `Request.SetQueryParams` or `Request.SetQueryParam`.
//
//	client.SetQueryParams(map[string]string{
//			"search": "kitchen papers",
//			"size": "large",
//		})
func ( *Client) ( map[string]string) *Client {
	for ,  := range  {
		.SetQueryParam(, )
	}
	return 
}

// SetFormData method sets Form parameters and their values in the client instance.
// It's applicable only HTTP method `POST` and `PUT` and request content type would be set as
// `application/x-www-form-urlencoded`. These form data will be added to all the request raised from
// this client instance. Also it can be overridden at request level form data.
//
// See `Request.SetFormData`.
//
//	client.SetFormData(map[string]string{
//			"access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
//			"user_id": "3455454545",
//		})
func ( *Client) ( map[string]string) *Client {
	for ,  := range  {
		.FormData.Set(, )
	}
	return 
}

// SetBasicAuth method sets the basic authentication header in the HTTP request. For Example:
//
//	Authorization: Basic <base64-encoded-value>
//
// For Example: To set the header for username "go-resty" and password "welcome"
//
//	client.SetBasicAuth("go-resty", "welcome")
//
// This basic auth information gets added to all the request raised from this client instance.
// Also it can be overridden or set one at the request level is supported.
//
// See `Request.SetBasicAuth`.
func ( *Client) (,  string) *Client {
	.UserInfo = &User{Username: , Password: }
	return 
}

// SetAuthToken method sets the auth token of the `Authorization` header for all HTTP requests.
// The default auth scheme is `Bearer`, it can be customized with the method `SetAuthScheme`. For Example:
//
//	Authorization: <auth-scheme> <auth-token-value>
//
// For Example: To set auth token BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F
//
//	client.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
//
// This auth token gets added to all the requests raised from this client instance.
// Also it can be overridden or set one at the request level is supported.
//
// See `Request.SetAuthToken`.
func ( *Client) ( string) *Client {
	.Token = 
	return 
}

// SetAuthScheme method sets the auth scheme type in the HTTP request. For Example:
//
//	Authorization: <auth-scheme-value> <auth-token-value>
//
// For Example: To set the scheme to use OAuth
//
//	client.SetAuthScheme("OAuth")
//
// This auth scheme gets added to all the requests raised from this client instance.
// Also it can be overridden or set one at the request level is supported.
//
// Information about auth schemes can be found in RFC7235 which is linked to below
// along with the page containing the currently defined official authentication schemes:
//
//	https://tools.ietf.org/html/rfc7235
//	https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml#authschemes
//
// See `Request.SetAuthToken`.
func ( *Client) ( string) *Client {
	.AuthScheme = 
	return 
}

// SetDigestAuth method sets the Digest Access auth scheme for the client. If a server responds with 401 and sends
// a Digest challenge in the WWW-Authenticate Header, requests will be resent with the appropriate Authorization Header.
//
// For Example: To set the Digest scheme with user "Mufasa" and password "Circle Of Life"
//
//	client.SetDigestAuth("Mufasa", "Circle Of Life")
//
// Information about Digest Access Authentication can be found in RFC7616:
//
//	https://datatracker.ietf.org/doc/html/rfc7616
//
// See `Request.SetDigestAuth`.
func ( *Client) (,  string) *Client {
	 := .httpClient.Transport
	.OnBeforeRequest(func( *Client,  *Request) error {
		.httpClient.Transport = &digestTransport{
			digestCredentials: digestCredentials{, },
			transport:         ,
		}
		return nil
	})
	.OnAfterResponse(func( *Client,  *Response) error {
		.httpClient.Transport = 
		return nil
	})
	return 
}

// R method creates a new request instance, its used for Get, Post, Put, Delete, Patch, Head, Options, etc.
func ( *Client) () *Request {
	 := &Request{
		QueryParam:    url.Values{},
		FormData:      url.Values{},
		Header:        http.Header{},
		Cookies:       make([]*http.Cookie, 0),
		PathParams:    map[string]string{},
		RawPathParams: map[string]string{},
		Debug:         .Debug,

		client:          ,
		multipartFiles:  []*File{},
		multipartFields: []*MultipartField{},
		jsonEscapeHTML:  .jsonEscapeHTML,
		log:             .log,
	}
	return 
}

// NewRequest is an alias for method `R()`. Creates a new request instance, its used for
// Get, Post, Put, Delete, Patch, Head, Options, etc.
func ( *Client) () *Request {
	return .R()
}

// OnBeforeRequest method appends a request middleware into the before request chain.
// The user defined middlewares get applied before the default Resty request middlewares.
// After all middlewares have been applied, the request is sent from Resty to the host server.
//
//	client.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
//			// Now you have access to Client and Request instance
//			// manipulate it as per your need
//
//			return nil 	// if its success otherwise return error
//		})
func ( *Client) ( RequestMiddleware) *Client {
	.udBeforeRequestLock.Lock()
	defer .udBeforeRequestLock.Unlock()

	.udBeforeRequest = append(.udBeforeRequest, )

	return 
}

// OnAfterResponse method appends response middleware into the after response chain.
// Once we receive response from host server, default Resty response middleware
// gets applied and then user assigned response middlewares applied.
//
//	client.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
//			// Now you have access to Client and Response instance
//			// manipulate it as per your need
//
//			return nil 	// if its success otherwise return error
//		})
func ( *Client) ( ResponseMiddleware) *Client {
	.afterResponseLock.Lock()
	defer .afterResponseLock.Unlock()

	.afterResponse = append(.afterResponse, )

	return 
}

// OnError method adds a callback that will be run whenever a request execution fails.
// This is called after all retries have been attempted (if any).
// If there was a response from the server, the error will be wrapped in *ResponseError
// which has the last response received from the server.
//
//	client.OnError(func(req *resty.Request, err error) {
//		if v, ok := err.(*resty.ResponseError); ok {
//			// Do something with v.Response
//		}
//		// Log the error, increment a metric, etc...
//	})
//
// Out of the OnSuccess, OnError, OnInvalid, OnPanic callbacks, exactly one
// set will be invoked for each call to Request.Execute() that completes.
func ( *Client) ( ErrorHook) *Client {
	.errorHooks = append(.errorHooks, )
	return 
}

// OnSuccess method adds a callback that will be run whenever a request execution
// succeeds.  This is called after all retries have been attempted (if any).
//
// Out of the OnSuccess, OnError, OnInvalid, OnPanic callbacks, exactly one
// set will be invoked for each call to Request.Execute() that completes.
//
// Since v2.8.0
func ( *Client) ( SuccessHook) *Client {
	.successHooks = append(.successHooks, )
	return 
}

// OnInvalid method adds a callback that will be run whenever a request execution
// fails before it starts because the request is invalid.
//
// Out of the OnSuccess, OnError, OnInvalid, OnPanic callbacks, exactly one
// set will be invoked for each call to Request.Execute() that completes.
//
// Since v2.8.0
func ( *Client) ( ErrorHook) *Client {
	.invalidHooks = append(.invalidHooks, )
	return 
}

// OnPanic method adds a callback that will be run whenever a request execution
// panics.
//
// Out of the OnSuccess, OnError, OnInvalid, OnPanic callbacks, exactly one
// set will be invoked for each call to Request.Execute() that completes.
// If an OnSuccess, OnError, or OnInvalid callback panics, then the exactly
// one rule can be violated.
//
// Since v2.8.0
func ( *Client) ( ErrorHook) *Client {
	.panicHooks = append(.panicHooks, )
	return 
}

// SetPreRequestHook method sets the given pre-request function into resty client.
// It is called right before the request is fired.
//
// Note: Only one pre-request hook can be registered. Use `client.OnBeforeRequest` for multiple.
func ( *Client) ( PreRequestHook) *Client {
	if .preReqHook != nil {
		.log.Warnf("Overwriting an existing pre-request hook: %s", functionName())
	}
	.preReqHook = 
	return 
}

// SetDebug method enables the debug mode on Resty client. Client logs details of every request and response.
// For `Request` it logs information such as HTTP verb, Relative URL path, Host, Headers, Body if it has one.
// For `Response` it logs information such as Status, Response Time, Headers, Body if it has one.
//
//	client.SetDebug(true)
//
// Also it can be enabled at request level for particular request, see `Request.SetDebug`.
func ( *Client) ( bool) *Client {
	.Debug = 
	return 
}

// SetDebugBodyLimit sets the maximum size for which the response and request body will be logged in debug mode.
//
//	client.SetDebugBodyLimit(1000000)
func ( *Client) ( int64) *Client {
	.debugBodySizeLimit = 
	return 
}

// OnRequestLog method used to set request log callback into Resty. Registered callback gets
// called before the resty actually logs the information.
func ( *Client) ( RequestLogCallback) *Client {
	if .requestLog != nil {
		.log.Warnf("Overwriting an existing on-request-log callback from=%s to=%s",
			functionName(.requestLog), functionName())
	}
	.requestLog = 
	return 
}

// OnResponseLog method used to set response log callback into Resty. Registered callback gets
// called before the resty actually logs the information.
func ( *Client) ( ResponseLogCallback) *Client {
	if .responseLog != nil {
		.log.Warnf("Overwriting an existing on-response-log callback from=%s to=%s",
			functionName(.responseLog), functionName())
	}
	.responseLog = 
	return 
}

// SetDisableWarn method disables the warning message on Resty client.
//
// For Example: Resty warns the user when BasicAuth used on non-TLS mode.
//
//	client.SetDisableWarn(true)
func ( *Client) ( bool) *Client {
	.DisableWarn = 
	return 
}

// SetAllowGetMethodPayload method allows the GET method with payload on Resty client.
//
// For Example: Resty allows the user sends request with a payload on HTTP GET method.
//
//	client.SetAllowGetMethodPayload(true)
func ( *Client) ( bool) *Client {
	.AllowGetMethodPayload = 
	return 
}

// SetLogger method sets given writer for logging Resty request and response details.
//
// Compliant to interface `resty.Logger`.
func ( *Client) ( Logger) *Client {
	.log = 
	return 
}

// SetContentLength method enables the HTTP header `Content-Length` value for every request.
// By default Resty won't set `Content-Length`.
//
//	client.SetContentLength(true)
//
// Also you have an option to enable for particular request. See `Request.SetContentLength`
func ( *Client) ( bool) *Client {
	.setContentLength = 
	return 
}

// SetTimeout method sets timeout for request raised from client.
//
//	client.SetTimeout(time.Duration(1 * time.Minute))
func ( *Client) ( time.Duration) *Client {
	.httpClient.Timeout = 
	return 
}

// SetError method is to register the global or client common `Error` object into Resty.
// It is used for automatic unmarshalling if response status code is greater than 399 and
// content type either JSON or XML. Can be pointer or non-pointer.
//
//	client.SetError(&Error{})
//	// OR
//	client.SetError(Error{})
func ( *Client) ( interface{}) *Client {
	.Error = typeOf()
	return 
}

// SetRedirectPolicy method sets the client redirect policy. Resty provides ready to use
// redirect policies. Wanna create one for yourself refer to `redirect.go`.
//
//	client.SetRedirectPolicy(FlexibleRedirectPolicy(20))
//
//	// Need multiple redirect policies together
//	client.SetRedirectPolicy(FlexibleRedirectPolicy(20), DomainCheckRedirectPolicy("host1.com", "host2.net"))
func ( *Client) ( ...interface{}) *Client {
	for ,  := range  {
		if ,  := .(RedirectPolicy); ! {
			.log.Errorf("%v does not implement resty.RedirectPolicy (missing Apply method)",
				functionName())
		}
	}

	.httpClient.CheckRedirect = func( *http.Request,  []*http.Request) error {
		for ,  := range  {
			if  := .(RedirectPolicy).Apply(, );  != nil {
				return 
			}
		}
		return nil // looks good, go ahead
	}

	return 
}

// SetRetryCount method enables retry on Resty client and allows you
// to set no. of retry count. Resty uses a Backoff mechanism.
func ( *Client) ( int) *Client {
	.RetryCount = 
	return 
}

// SetRetryWaitTime method sets default wait time to sleep before retrying
// request.
//
// Default is 100 milliseconds.
func ( *Client) ( time.Duration) *Client {
	.RetryWaitTime = 
	return 
}

// SetRetryMaxWaitTime method sets max wait time to sleep before retrying
// request.
//
// Default is 2 seconds.
func ( *Client) ( time.Duration) *Client {
	.RetryMaxWaitTime = 
	return 
}

// SetRetryAfter sets callback to calculate wait time between retries.
// Default (nil) implies exponential backoff with jitter
func ( *Client) ( RetryAfterFunc) *Client {
	.RetryAfter = 
	return 
}

// SetJSONMarshaler method sets the JSON marshaler function to marshal the request body.
// By default, Resty uses `encoding/json` package to marshal the request body.
//
// Since v2.8.0
func ( *Client) ( func( interface{}) ([]byte, error)) *Client {
	.JSONMarshal = 
	return 
}

// SetJSONUnmarshaler method sets the JSON unmarshaler function to unmarshal the response body.
// By default, Resty uses `encoding/json` package to unmarshal the response body.
//
// Since v2.8.0
func ( *Client) ( func( []byte,  interface{}) error) *Client {
	.JSONUnmarshal = 
	return 
}

// SetXMLMarshaler method sets the XML marshaler function to marshal the request body.
// By default, Resty uses `encoding/xml` package to marshal the request body.
//
// Since v2.8.0
func ( *Client) ( func( interface{}) ([]byte, error)) *Client {
	.XMLMarshal = 
	return 
}

// SetXMLUnmarshaler method sets the XML unmarshaler function to unmarshal the response body.
// By default, Resty uses `encoding/xml` package to unmarshal the response body.
//
// Since v2.8.0
func ( *Client) ( func( []byte,  interface{}) error) *Client {
	.XMLUnmarshal = 
	return 
}

// AddRetryCondition method adds a retry condition function to array of functions
// that are checked to determine if the request is retried. The request will
// retry if any of the functions return true and error is nil.
//
// Note: These retry conditions are applied on all Request made using this Client.
// For Request specific retry conditions check *Request.AddRetryCondition
func ( *Client) ( RetryConditionFunc) *Client {
	.RetryConditions = append(.RetryConditions, )
	return 
}

// AddRetryAfterErrorCondition adds the basic condition of retrying after encountering
// an error from the http response
//
// Since v2.6.0
func ( *Client) () *Client {
	.AddRetryCondition(func( *Response,  error) bool {
		return .IsError()
	})
	return 
}

// AddRetryHook adds a side-effecting retry hook to an array of hooks
// that will be executed on each retry.
//
// Since v2.6.0
func ( *Client) ( OnRetryFunc) *Client {
	.RetryHooks = append(.RetryHooks, )
	return 
}

// SetRetryResetReaders method enables the Resty client to seek the start of all
// file readers given as multipart files, if the given object implements `io.ReadSeeker`.
//
// Since ...
func ( *Client) ( bool) *Client {
	.RetryResetReaders = 
	return 
}

// SetTLSClientConfig method sets TLSClientConfig for underling client Transport.
//
// For Example:
//
//	// 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 })
//
// Note: This method overwrites existing `TLSClientConfig`.
func ( *Client) ( *tls.Config) *Client {
	,  := .Transport()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}
	.TLSClientConfig = 
	return 
}

// SetProxy method sets the Proxy URL and Port for Resty client.
//
//	client.SetProxy("http://proxyserver:8888")
//
// OR Without this `SetProxy` method, you could also set Proxy via environment variable.
//
// Refer to godoc `http.ProxyFromEnvironment`.
func ( *Client) ( string) *Client {
	,  := .Transport()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}

	,  := url.Parse()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}

	.proxyURL = 
	.Proxy = http.ProxyURL(.proxyURL)
	return 
}

// RemoveProxy method removes the proxy configuration from Resty client
//
//	client.RemoveProxy()
func ( *Client) () *Client {
	,  := .Transport()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}
	.proxyURL = nil
	.Proxy = nil
	return 
}

// SetCertificates method helps to set client certificates into Resty conveniently.
func ( *Client) ( ...tls.Certificate) *Client {
	,  := .tlsConfig()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}
	.Certificates = append(.Certificates, ...)
	return 
}

// SetRootCertificate method helps to add one or more root certificates into Resty client
//
//	client.SetRootCertificate("/path/to/root/pemFile.pem")
func ( *Client) ( string) *Client {
	,  := os.ReadFile()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}

	,  := .tlsConfig()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}
	if .RootCAs == nil {
		.RootCAs = x509.NewCertPool()
	}

	.RootCAs.AppendCertsFromPEM()
	return 
}

// SetRootCertificateFromString method helps to add one or more root certificates into Resty client
//
//	client.SetRootCertificateFromString("pem file content")
func ( *Client) ( string) *Client {
	,  := .tlsConfig()
	if  != nil {
		.log.Errorf("%v", )
		return 
	}
	if .RootCAs == nil {
		.RootCAs = x509.NewCertPool()
	}

	.RootCAs.AppendCertsFromPEM([]byte())
	return 
}

// SetOutputDirectory method sets output directory for saving HTTP response into file.
// If the output directory not exists then resty creates one. This setting is optional one,
// if you're planning using absolute path in `Request.SetOutput` and can used together.
//
//	client.SetOutputDirectory("/save/http/response/here")
func ( *Client) ( string) *Client {
	.outputDirectory = 
	return 
}

// SetRateLimiter sets an optional `RateLimiter`. If set the rate limiter will control
// all requests made with this client.
//
// Since v2.9.0
func ( *Client) ( RateLimiter) *Client {
	.rateLimiter = 
	return 
}

// SetTransport method sets custom `*http.Transport` or any `http.RoundTripper`
// compatible interface implementation in the resty client.
//
// Note:
//
// - If transport is not type of `*http.Transport` then you may not be able to
// take advantage of some of the Resty client settings.
//
// - It overwrites the Resty client transport instance and it's configurations.
//
//	transport := &http.Transport{
//		// something like Proxying to httptest.Server, etc...
//		Proxy: func(req *http.Request) (*url.URL, error) {
//			return url.Parse(server.URL)
//		},
//	}
//
//	client.SetTransport(transport)
func ( *Client) ( http.RoundTripper) *Client {
	if  != nil {
		.httpClient.Transport = 
	}
	return 
}

// SetScheme method sets custom scheme in the Resty client. It's way to override default.
//
//	client.SetScheme("http")
func ( *Client) ( string) *Client {
	if !IsStringEmpty() {
		.scheme = strings.TrimSpace()
	}
	return 
}

// SetCloseConnection method sets variable `Close` in http request struct with the given
// value. More info: https://golang.org/src/net/http/request.go
func ( *Client) ( bool) *Client {
	.closeConnection = 
	return 
}

// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
// Resty exposes the raw response body as `io.ReadCloser`. Also do not forget to close the body,
// otherwise you might get into connection leaks, no connection reuse.
//
// Note: Response middlewares are not applicable, if you use this option. Basically you have
// taken over the control of response parsing from `Resty`.
func ( *Client) ( bool) *Client {
	.notParseResponse = 
	return 
}

// SetPathParam method sets single URL path key-value pair in the
// Resty client instance.
//
//	client.SetPathParam("userId", "sample@sample.com")
//
//	Result:
//	   URL - /v1/users/{userId}/details
//	   Composed URL - /v1/users/sample@sample.com/details
//
// It replaces the value of the key while composing the request URL.
// The value will be escaped using `url.PathEscape` function.
//
// Also it can be overridden at request level Path Params options,
// see `Request.SetPathParam` or `Request.SetPathParams`.
func ( *Client) (,  string) *Client {
	.PathParams[] = 
	return 
}

// SetPathParams method sets multiple URL path key-value pairs at one go in the
// Resty client instance.
//
//	client.SetPathParams(map[string]string{
//		"userId":       "sample@sample.com",
//		"subAccountId": "100002",
//		"path":         "groups/developers",
//	})
//
//	Result:
//	   URL - /v1/users/{userId}/{subAccountId}/{path}/details
//	   Composed URL - /v1/users/sample@sample.com/100002/groups%2Fdevelopers/details
//
// It replaces the value of the key while composing the request URL.
// The values will be escaped using `url.PathEscape` function.
//
// Also it can be overridden at request level Path Params options,
// see `Request.SetPathParam` or `Request.SetPathParams`.
func ( *Client) ( map[string]string) *Client {
	for ,  := range  {
		.SetPathParam(, )
	}
	return 
}

// SetRawPathParam method sets single URL path key-value pair in the
// Resty client instance.
//
//	client.SetPathParam("userId", "sample@sample.com")
//
//	Result:
//	   URL - /v1/users/{userId}/details
//	   Composed URL - /v1/users/sample@sample.com/details
//
//	client.SetPathParam("path", "groups/developers")
//
//	Result:
//	   URL - /v1/users/{userId}/details
//	   Composed URL - /v1/users/groups%2Fdevelopers/details
//
// It replaces the value of the key while composing the request URL.
// The value will be used as it is and will not be escaped.
//
// Also it can be overridden at request level Path Params options,
// see `Request.SetPathParam` or `Request.SetPathParams`.
//
// Since v2.8.0
func ( *Client) (,  string) *Client {
	.RawPathParams[] = 
	return 
}

// SetRawPathParams method sets multiple URL path key-value pairs at one go in the
// Resty client instance.
//
//	client.SetPathParams(map[string]string{
//		"userId":       "sample@sample.com",
//		"subAccountId": "100002",
//		"path":         "groups/developers",
//	})
//
//	Result:
//	   URL - /v1/users/{userId}/{subAccountId}/{path}/details
//	   Composed URL - /v1/users/sample@sample.com/100002/groups/developers/details
//
// It replaces the value of the key while composing the request URL.
// The values will be used as they are and will not be escaped.
//
// Also it can be overridden at request level Path Params options,
// see `Request.SetPathParam` or `Request.SetPathParams`.
//
// Since v2.8.0
func ( *Client) ( map[string]string) *Client {
	for ,  := range  {
		.SetRawPathParam(, )
	}
	return 
}

// SetJSONEscapeHTML method is to enable/disable the HTML escape on JSON marshal.
//
// Note: This option only applicable to standard JSON Marshaller.
func ( *Client) ( bool) *Client {
	.jsonEscapeHTML = 
	return 
}

// EnableTrace method enables the Resty client trace for the requests fired from
// the client using `httptrace.ClientTrace` and provides insights.
//
//	client := resty.New().EnableTrace()
//
//	resp, err := client.R().Get("https://httpbin.org/get")
//	fmt.Println("Error:", err)
//	fmt.Println("Trace Info:", resp.Request.TraceInfo())
//
// Also `Request.EnableTrace` available too to get trace info for single request.
//
// Since v2.0.0
func ( *Client) () *Client {
	.trace = true
	return 
}

// DisableTrace method disables the Resty client trace. Refer to `Client.EnableTrace`.
//
// Since v2.0.0
func ( *Client) () *Client {
	.trace = false
	return 
}

// IsProxySet method returns the true is proxy is set from resty client otherwise
// false. By default proxy is set from environment, refer to `http.ProxyFromEnvironment`.
func ( *Client) () bool {
	return .proxyURL != nil
}

// GetClient method returns the current `http.Client` used by the resty client.
func ( *Client) () *http.Client {
	return .httpClient
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Client Unexported methods
//_______________________________________________________________________

// Executes method executes the given `Request` object and returns response
// error.
func ( *Client) ( *Request) (*Response, error) {
	// Lock the user-defined pre-request hooks.
	.udBeforeRequestLock.RLock()
	defer .udBeforeRequestLock.RUnlock()

	// Lock the post-request hooks.
	.afterResponseLock.RLock()
	defer .afterResponseLock.RUnlock()

	// Apply Request middleware
	var  error

	// user defined on before request methods
	// to modify the *resty.Request object
	for ,  := range .udBeforeRequest {
		if  = (, );  != nil {
			return nil, wrapNoRetryErr()
		}
	}

	// If there is a rate limiter set for this client, the Execute call
	// will return an error if the rate limit is exceeded.
	if .client.rateLimiter != nil {
		if !.client.rateLimiter.Allow() {
			return nil, wrapNoRetryErr(ErrRateLimitExceeded)
		}
	}

	// resty middlewares
	for ,  := range .beforeRequest {
		if  = (, );  != nil {
			return nil, wrapNoRetryErr()
		}
	}

	if  := .Header.Get("Host");  != "" {
		.RawRequest.Host = 
	}

	// call pre-request if defined
	if .preReqHook != nil {
		if  = .preReqHook(, .RawRequest);  != nil {
			return nil, wrapNoRetryErr()
		}
	}

	if  = requestLogger(, );  != nil {
		return nil, wrapNoRetryErr()
	}

	.RawRequest.Body = newRequestBodyReleaser(.RawRequest.Body, .bodyBuf)

	.Time = time.Now()
	,  := .httpClient.Do(.RawRequest)

	 := &Response{
		Request:     ,
		RawResponse: ,
	}

	if  != nil || .notParseResponse || .notParseResponse {
		.setReceivedAt()
		return , 
	}

	if !.isSaveResponse {
		defer closeq(.Body)
		 := .Body

		// GitHub #142 & #187
		if strings.EqualFold(.Header.Get(hdrContentEncodingKey), "gzip") && .ContentLength != 0 {
			if ,  := .(*gzip.Reader); ! {
				,  = gzip.NewReader()
				if  != nil {
					.setReceivedAt()
					return , 
				}
				defer closeq()
			}
		}

		if .body,  = io.ReadAll();  != nil {
			.setReceivedAt()
			return , 
		}

		.size = int64(len(.body))
	}

	.setReceivedAt() // after we read the body

	// Apply Response middleware
	for ,  := range .afterResponse {
		if  = (, );  != nil {
			break
		}
	}

	return , wrapNoRetryErr()
}

// getting TLS client config if not exists then create one
func ( *Client) () (*tls.Config, error) {
	,  := .Transport()
	if  != nil {
		return nil, 
	}
	if .TLSClientConfig == nil {
		.TLSClientConfig = &tls.Config{}
	}
	return .TLSClientConfig, nil
}

// Transport method returns `*http.Transport` currently in use or error
// in case currently used `transport` is not a `*http.Transport`.
//
// Since v2.8.0 become exported method.
func ( *Client) () (*http.Transport, error) {
	if ,  := .httpClient.Transport.(*http.Transport);  {
		return , nil
	}
	return nil, errors.New("current transport is not an *http.Transport instance")
}

// just an internal helper method
func ( *Client) ( io.Writer) *Client {
	.log.(*logger).l.SetOutput()
	return 
}

// ResponseError is a wrapper for including the server response with an error.
// Neither the err nor the response should be nil.
type ResponseError struct {
	Response *Response
	Err      error
}

func ( *ResponseError) () string {
	return .Err.Error()
}

func ( *ResponseError) () error {
	return .Err
}

// Helper to run errorHooks hooks.
// It wraps the error in a ResponseError if the resp is not nil
// so hooks can access it.
func ( *Client) ( *Request,  *Response,  error) {
	if  != nil {
		if  != nil { // wrap with ResponseError
			 = &ResponseError{Response: , Err: }
		}
		for ,  := range .errorHooks {
			(, )
		}
	} else {
		for ,  := range .successHooks {
			(, )
		}
	}
}

// Helper to run panicHooks hooks.
func ( *Client) ( *Request,  error) {
	for ,  := range .panicHooks {
		(, )
	}
}

// Helper to run invalidHooks hooks.
func ( *Client) ( *Request,  error) {
	for ,  := range .invalidHooks {
		(, )
	}
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// File struct and its methods
//_______________________________________________________________________

// File struct represent file information for multipart request
type File struct {
	Name      string
	ParamName string
	io.Reader
}

// String returns string value of current file details
func ( *File) () string {
	return fmt.Sprintf("ParamName: %v; FileName: %v", .ParamName, .Name)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// MultipartField struct
//_______________________________________________________________________

// MultipartField struct represent custom data part for multipart request
type MultipartField struct {
	Param       string
	FileName    string
	ContentType string
	io.Reader
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Unexported package methods
//_______________________________________________________________________

func createClient( *http.Client) *Client {
	if .Transport == nil {
		.Transport = createTransport(nil)
	}

	 := &Client{ // not setting lang default values
		QueryParam:             url.Values{},
		FormData:               url.Values{},
		Header:                 http.Header{},
		Cookies:                make([]*http.Cookie, 0),
		RetryWaitTime:          defaultWaitTime,
		RetryMaxWaitTime:       defaultMaxWaitTime,
		PathParams:             make(map[string]string),
		RawPathParams:          make(map[string]string),
		JSONMarshal:            json.Marshal,
		JSONUnmarshal:          json.Unmarshal,
		XMLMarshal:             xml.Marshal,
		XMLUnmarshal:           xml.Unmarshal,
		HeaderAuthorizationKey: http.CanonicalHeaderKey("Authorization"),

		jsonEscapeHTML:     true,
		httpClient:         ,
		debugBodySizeLimit: math.MaxInt32,
	}

	// Logger
	.SetLogger(createLogger())

	// default before request middlewares
	.beforeRequest = []RequestMiddleware{
		parseRequestURL,
		parseRequestHeader,
		parseRequestBody,
		createHTTPRequest,
		addCredentials,
	}

	// user defined request middlewares
	.udBeforeRequest = []RequestMiddleware{}

	// default after response middlewares
	.afterResponse = []ResponseMiddleware{
		responseLogger,
		parseResponseBody,
		saveResponseIntoFile,
	}

	return 
}