Source File
request.go
Belonging Package
github.com/go-resty/resty/v2
// 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 restyimport ()//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾// Request struct and methods//_______________________________________________________________________// Request struct is used to compose and fire individual request from// resty client. Request provides an options to override client level// settings and also an options for the request composition.type Request struct {URL stringMethod stringToken stringAuthScheme stringQueryParam url.ValuesFormData url.ValuesPathParams map[string]stringRawPathParams map[string]stringHeader http.HeaderTime time.TimeBody interface{}Result interface{}Error interface{}RawRequest *http.RequestSRV *SRVRecordUserInfo *UserCookies []*http.CookieDebug bool// Attempt is to represent the request attempt made during a Resty// request execution flow, including retry count.//// Since v2.4.0Attempt intisMultiPart boolisFormData boolsetContentLength boolisSaveResponse boolnotParseResponse booljsonEscapeHTML booltrace booloutputFile stringfallbackContentType stringforceContentType stringctx context.Contextvalues map[string]interface{}client *ClientbodyBuf *bytes.BufferclientTrace *clientTracelog LoggermultipartFiles []*FilemultipartFields []*MultipartFieldretryConditions []RetryConditionFunc}// Context method returns the Context if its already set in request// otherwise it creates new one using `context.Background()`.func ( *Request) () context.Context {if .ctx == nil {return context.Background()}return .ctx}// SetContext method sets the context.Context for current Request. It allows// to interrupt the request execution if ctx.Done() channel is closed.// See https://blog.golang.org/context article and the "context" package// documentation.func ( *Request) ( context.Context) *Request {.ctx =return}// SetHeader method is to set a single header field and its value in the current request.//// For Example: To set `Content-Type` and `Accept` as `application/json`.//// client.R().// SetHeader("Content-Type", "application/json").// SetHeader("Accept", "application/json")//// Also you can override header value, which was set at client instance level.func ( *Request) (, string) *Request {.Header.Set(, )return}// SetHeaders method sets multiple headers field and its values at one go in the current request.//// For Example: To set `Content-Type` and `Accept` as `application/json`//// client.R().// SetHeaders(map[string]string{// "Content-Type": "application/json",// "Accept": "application/json",// })//// Also you can override header value, which was set at client instance level.func ( *Request) ( map[string]string) *Request {for , := range {.SetHeader(, )}return}// SetHeaderMultiValues sets multiple headers fields and its values is list of strings at one go in the current request.//// For Example: To set `Accept` as `text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8`//// client.R().// SetHeaderMultiValues(map[string][]string{// "Accept": []string{"text/html", "application/xhtml+xml", "application/xml;q=0.9", "image/webp", "*/*;q=0.8"},// })//// Also you can override header value, which was set at client instance level.func ( *Request) ( map[string][]string) *Request {for , := range {.SetHeader(, strings.Join(, ", "))}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.0func ( *Request) (, string) *Request {.Header[] = []string{}return}// SetQueryParam method sets single parameter and its value in the current request.// It will be formed as query string for the request.//// For Example: `search=kitchen%20papers&size=large` in the URL after `?` mark.//// client.R().// SetQueryParam("search", "kitchen papers").// SetQueryParam("size", "large")//// Also you can override query params value, which was set at client instance level.func ( *Request) (, string) *Request {.QueryParam.Set(, )return}// SetQueryParams method sets multiple parameters and its values at one go in the current request.// It will be formed as query string for the request.//// For Example: `search=kitchen%20papers&size=large` in the URL after `?` mark.//// client.R().// SetQueryParams(map[string]string{// "search": "kitchen papers",// "size": "large",// })//// Also you can override query params value, which was set at client instance level.func ( *Request) ( map[string]string) *Request {for , := range {.SetQueryParam(, )}return}// SetQueryParamsFromValues method appends multiple parameters with multi-value// (`url.Values`) at one go in the current request. It will be formed as// query string for the request.//// For Example: `status=pending&status=approved&status=open` in the URL after `?` mark.//// client.R().// SetQueryParamsFromValues(url.Values{// "status": []string{"pending", "approved", "open"},// })//// Also you can override query params value, which was set at client instance level.func ( *Request) ( url.Values) *Request {for , := range {for , := range {.QueryParam.Add(, )}}return}// SetQueryString method provides ability to use string as an input to set URL query string for the request.//// Using String as an input//// client.R().// SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")func ( *Request) ( string) *Request {, := url.ParseQuery(strings.TrimSpace())if == nil {for , := range {for , := range {.QueryParam.Add(, )}}} else {.log.Errorf("%v", )}return}// SetFormData method sets Form parameters and their values in the current request.// It's applicable only HTTP method `POST` and `PUT` and requests content type would be set as// `application/x-www-form-urlencoded`.//// client.R().// SetFormData(map[string]string{// "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",// "user_id": "3455454545",// })//// Also you can override form data value, which was set at client instance level.func ( *Request) ( map[string]string) *Request {for , := range {.FormData.Set(, )}return}// SetFormDataFromValues method appends multiple form parameters with multi-value// (`url.Values`) at one go in the current request.//// client.R().// SetFormDataFromValues(url.Values{// "search_criteria": []string{"book", "glass", "pencil"},// })//// Also you can override form data value, which was set at client instance level.func ( *Request) ( url.Values) *Request {for , := range {for , := range {.FormData.Add(, )}}return}// SetBody method sets the request body for the request. It supports various realtime needs as easy.// We can say its quite handy or powerful. Supported request body data types is `string`,// `[]byte`, `struct`, `map`, `slice` and `io.Reader`. Body value can be pointer or non-pointer.// Automatic marshalling for JSON and XML content type, if it is `struct`, `map`, or `slice`.//// Note: `io.Reader` is processed as bufferless mode while sending request.//// For Example: Struct as a body input, based on content type, it will be marshalled.//// client.R().// SetBody(User{// Username: "jeeva@myjeeva.com",// Password: "welcome2resty",// })//// Map as a body input, based on content type, it will be marshalled.//// client.R().// SetBody(map[string]interface{}{// "username": "jeeva@myjeeva.com",// "password": "welcome2resty",// "address": &Address{// Address1: "1111 This is my street",// Address2: "Apt 201",// City: "My City",// State: "My State",// ZipCode: 00000,// },// })//// String as a body input. Suitable for any need as a string input.//// client.R().// SetBody(`{// "username": "jeeva@getrightcare.com",// "password": "admin"// }`)//// []byte as a body input. Suitable for raw request such as file upload, serialize & deserialize, etc.//// client.R().// SetBody([]byte("This is my raw request, sent as-is"))func ( *Request) ( interface{}) *Request {.Body =return}// SetResult method is to register the response `Result` object for automatic unmarshalling for the request,// if response status code is between 200 and 299 and content type either JSON or XML.//// Note: Result object can be pointer or non-pointer.//// client.R().SetResult(&AuthToken{})// // OR// client.R().SetResult(AuthToken{})//// Accessing a result value from response instance.//// response.Result().(*AuthToken)func ( *Request) ( interface{}) *Request {if != nil {.Result = getPointer()}return}// SetError method is to register the request `Error` object for automatic unmarshalling for the request,// if response status code is greater than 399 and content type either JSON or XML.//// Note: Error object can be pointer or non-pointer.//// client.R().SetError(&AuthError{})// // OR// client.R().SetError(AuthError{})//// Accessing a error value from response instance.//// response.Error().(*AuthError)func ( *Request) ( interface{}) *Request {.Error = getPointer()return}// SetFile method is to set single file field name and its path for multipart upload.//// client.R().// SetFile("my_file", "/Users/jeeva/Gas Bill - Sep.pdf")func ( *Request) (, string) *Request {.isMultiPart = true.FormData.Set("@"+, )return}// SetFiles method is to set multiple file field name and its path for multipart upload.//// client.R().// SetFiles(map[string]string{// "my_file1": "/Users/jeeva/Gas Bill - Sep.pdf",// "my_file2": "/Users/jeeva/Electricity Bill - Sep.pdf",// "my_file3": "/Users/jeeva/Water Bill - Sep.pdf",// })func ( *Request) ( map[string]string) *Request {.isMultiPart = truefor , := range {.FormData.Set("@"+, )}return}// SetFileReader method is to set single file using io.Reader for multipart upload.//// client.R().// SetFileReader("profile_img", "my-profile-img.png", bytes.NewReader(profileImgBytes)).// SetFileReader("notes", "user-notes.txt", bytes.NewReader(notesBytes))func ( *Request) (, string, io.Reader) *Request {.isMultiPart = true.multipartFiles = append(.multipartFiles, &File{Name: ,ParamName: ,Reader: ,})return}// SetMultipartFormData method allows simple form data to be attached to the request as `multipart:form-data`func ( *Request) ( map[string]string) *Request {for , := range {= .SetMultipartField(, "", "", strings.NewReader())}return}// SetMultipartField method is to set custom data using io.Reader for multipart upload.func ( *Request) (, , string, io.Reader) *Request {.isMultiPart = true.multipartFields = append(.multipartFields, &MultipartField{Param: ,FileName: ,ContentType: ,Reader: ,})return}// SetMultipartFields method is to set multiple data fields using io.Reader for multipart upload.//// For Example://// client.R().SetMultipartFields(// &resty.MultipartField{// Param: "uploadManifest1",// FileName: "upload-file-1.json",// ContentType: "application/json",// Reader: strings.NewReader(`{"input": {"name": "Uploaded document 1", "_filename" : ["file1.txt"]}}`),// },// &resty.MultipartField{// Param: "uploadManifest2",// FileName: "upload-file-2.json",// ContentType: "application/json",// Reader: strings.NewReader(`{"input": {"name": "Uploaded document 2", "_filename" : ["file2.txt"]}}`),// })//// If you have slice already, then simply call-//// client.R().SetMultipartFields(fields...)func ( *Request) ( ...*MultipartField) *Request {.isMultiPart = true.multipartFields = append(.multipartFields, ...)return}// SetContentLength method sets the HTTP header `Content-Length` value for current request.// By default Resty won't set `Content-Length`. Also you have an option to enable for every// request.//// See `Client.SetContentLength`//// client.R().SetContentLength(true)func ( *Request) ( bool) *Request {.setContentLength =return}// SetBasicAuth method sets the basic authentication header in the current HTTP request.//// For Example://// Authorization: Basic <base64-encoded-value>//// To set the header for username "go-resty" and password "welcome"//// client.R().SetBasicAuth("go-resty", "welcome")//// This method overrides the credentials set by method `Client.SetBasicAuth`.func ( *Request) (, string) *Request {.UserInfo = &User{Username: , Password: }return}// SetAuthToken method sets the auth token header(Default Scheme: Bearer) in the current HTTP request. Header example://// Authorization: Bearer <auth-token-value-comes-here>//// For Example: To set auth token BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F//// client.R().SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")//// This method overrides the Auth token set by method `Client.SetAuthToken`.func ( *Request) ( string) *Request {.Token =return}// SetAuthScheme method sets the auth token scheme type in the HTTP request. For Example://// Authorization: <auth-scheme-value-set-here> <auth-token-value>//// For Example: To set the scheme to use OAuth//// client.R().SetAuthScheme("OAuth")//// This auth header scheme 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.//// 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//// This method overrides the Authorization scheme set by method `Client.SetAuthScheme`.func ( *Request) ( string) *Request {.AuthScheme =return}// SetDigestAuth method sets the Digest Access auth scheme for the HTTP request. If a server responds with 401 and sends// a Digest challenge in the WWW-Authenticate Header, the request will be resent with the appropriate Authorization Header.//// For Example: To set the Digest scheme with username "Mufasa" and password "Circle Of Life"//// client.R().SetDigestAuth("Mufasa", "Circle Of Life")//// Information about Digest Access Authentication can be found in RFC7616://// https://datatracker.ietf.org/doc/html/rfc7616//// This method overrides the username and password set by method `Client.SetDigestAuth`.func ( *Request) (, string) *Request {:= .client.httpClient.Transport.client.OnBeforeRequest(func( *Client, *Request) error {.httpClient.Transport = &digestTransport{digestCredentials: digestCredentials{, },transport: ,}return nil}).client.OnAfterResponse(func( *Client, *Response) error {.httpClient.Transport =return nil})return}// SetOutput method sets the output file for current HTTP request. Current HTTP response will be// saved into given file. It is similar to `curl -o` flag. Absolute path or relative path can be used.// If is it relative path then output file goes under the output directory, as mentioned// in the `Client.SetOutputDirectory`.//// client.R().// SetOutput("/Users/jeeva/Downloads/ReplyWithHeader-v5.1-beta.zip").// Get("http://bit.ly/1LouEKr")//// Note: In this scenario `Response.Body` might be nil.func ( *Request) ( string) *Request {.outputFile =.isSaveResponse = truereturn}// SetSRV method sets the details to query the service SRV record and execute the// request.//// client.R().// SetSRV(SRVRecord{"web", "testservice.com"}).// Get("/get")func ( *Request) ( *SRVRecord) *Request {.SRV =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 ( *Request) ( bool) *Request {.notParseResponse =return}// SetPathParam method sets single URL path key-value pair in the// Resty current request instance.//// client.R().SetPathParam("userId", "sample@sample.com")//// Result:// URL - /v1/users/{userId}/details// Composed URL - /v1/users/sample@sample.com/details//// client.R().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 values will be escaped using `url.PathEscape` function.//// Also you can override Path Params value, which was set at client instance// level.func ( *Request) (, string) *Request {.PathParams[] =return}// SetPathParams method sets multiple URL path key-value pairs at one go in the// Resty current request instance.//// client.R().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 request URL.// The value will be used as it is and will not be escaped.//// Also you can override Path Params value, which was set at client instance// level.func ( *Request) ( map[string]string) *Request {for , := range {.SetPathParam(, )}return}// SetRawPathParam method sets single URL path key-value pair in the// Resty current request instance.//// client.R().SetPathParam("userId", "sample@sample.com")//// Result:// URL - /v1/users/{userId}/details// Composed URL - /v1/users/sample@sample.com/details//// client.R().SetPathParam("path", "groups/developers")//// Result:// URL - /v1/users/{userId}/details// Composed URL - /v1/users/groups/developers/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 you can override Path Params value, which was set at client instance// level.//// Since v2.8.0func ( *Request) (, string) *Request {.RawPathParams[] =return}// SetRawPathParams method sets multiple URL path key-value pairs at one go in the// Resty current request instance.//// client.R().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 request URL.// The values will be used as they are and will not be escaped.//// Also you can override Path Params value, which was set at client instance// level.//// Since v2.8.0func ( *Request) ( map[string]string) *Request {for , := range {.SetRawPathParam(, )}return}// ExpectContentType method allows to provide fallback `Content-Type` for automatic unmarshalling// when `Content-Type` response header is unavailable.func ( *Request) ( string) *Request {.fallbackContentType =return}// ForceContentType method provides a strong sense of response `Content-Type` for automatic unmarshalling.// Resty gives this a higher priority than the `Content-Type` response header. This means that if both// `Request.ForceContentType` is set and the response `Content-Type` is available, `ForceContentType` will win.func ( *Request) ( string) *Request {.forceContentType =return}// SetJSONEscapeHTML method is to enable/disable the HTML escape on JSON marshal.//// Note: This option only applicable to standard JSON Marshaller.func ( *Request) ( bool) *Request {.jsonEscapeHTML =return}// SetCookie method appends a single cookie in the current request instance.//// client.R().SetCookie(&http.Cookie{// Name:"go-resty",// Value:"This is cookie value",// })//// Note: Method appends the Cookie value into existing Cookie if already existing.//// Since v2.1.0func ( *Request) ( *http.Cookie) *Request {.Cookies = append(.Cookies, )return}// SetCookies method sets an array of cookies in the current request 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's current request// client.R().SetCookies(cookies)//// Note: Method appends the Cookie value into existing Cookie if already existing.//// Since v2.1.0func ( *Request) ( []*http.Cookie) *Request {.Cookies = append(.Cookies, ...)return}// SetLogger method sets given writer for logging Resty request and response details.// By default, requests and responses inherit their logger from the client.//// Compliant to interface `resty.Logger`.func ( *Request) ( Logger) *Request {.log =return}// SetDebug method enables the debug mode on current request Resty request, It logs// the details current 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.R().SetDebug(true)func ( *Request) ( bool) *Request {.Debug =return}// AddRetryCondition method adds a retry condition function to the request's// 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 checked before all retry conditions of the client.//// Since v2.7.0func ( *Request) ( RetryConditionFunc) *Request {.retryConditions = append(.retryConditions, )return}//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾// HTTP request tracing//_______________________________________________________________________// EnableTrace method enables trace for the current request// using `httptrace.ClientTrace` and provides insights.//// client := resty.New()//// resp, err := client.R().EnableTrace().Get("https://httpbin.org/get")// fmt.Println("Error:", err)// fmt.Println("Trace Info:", resp.Request.TraceInfo())//// See `Client.EnableTrace` available too to get trace info for all requests.//// Since v2.0.0func ( *Request) () *Request {.trace = truereturn}// TraceInfo method returns the trace info for the request.// If either the Client or Request EnableTrace function has not been called// prior to the request being made, an empty TraceInfo object will be returned.//// Since v2.0.0func ( *Request) () TraceInfo {:= .clientTraceif == nil {return TraceInfo{}}:= TraceInfo{DNSLookup: .dnsDone.Sub(.dnsStart),TLSHandshake: .tlsHandshakeDone.Sub(.tlsHandshakeStart),ServerTime: .gotFirstResponseByte.Sub(.gotConn),IsConnReused: .gotConnInfo.Reused,IsConnWasIdle: .gotConnInfo.WasIdle,ConnIdleTime: .gotConnInfo.IdleTime,RequestAttempt: .Attempt,}// Calculate the total time accordingly,// when connection is reusedif .gotConnInfo.Reused {.TotalTime = .endTime.Sub(.getConn)} else {.TotalTime = .endTime.Sub(.dnsStart)}// Only calculate on successful connectionsif !.connectDone.IsZero() {.TCPConnTime = .connectDone.Sub(.dnsDone)}// Only calculate on successful connectionsif !.gotConn.IsZero() {.ConnTime = .gotConn.Sub(.getConn)}// Only calculate on successful connectionsif !.gotFirstResponseByte.IsZero() {.ResponseTime = .endTime.Sub(.gotFirstResponseByte)}// Capture remote address info when connection is non-nilif .gotConnInfo.Conn != nil {.RemoteAddr = .gotConnInfo.Conn.RemoteAddr()}return}//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾// HTTP verb method starts here//_______________________________________________________________________// Get method does GET HTTP request. It's defined in section 4.3.1 of RFC7231.func ( *Request) ( string) (*Response, error) {return .Execute(MethodGet, )}// Head method does HEAD HTTP request. It's defined in section 4.3.2 of RFC7231.func ( *Request) ( string) (*Response, error) {return .Execute(MethodHead, )}// Post method does POST HTTP request. It's defined in section 4.3.3 of RFC7231.func ( *Request) ( string) (*Response, error) {return .Execute(MethodPost, )}// Put method does PUT HTTP request. It's defined in section 4.3.4 of RFC7231.func ( *Request) ( string) (*Response, error) {return .Execute(MethodPut, )}// Delete method does DELETE HTTP request. It's defined in section 4.3.5 of RFC7231.func ( *Request) ( string) (*Response, error) {return .Execute(MethodDelete, )}// Options method does OPTIONS HTTP request. It's defined in section 4.3.7 of RFC7231.func ( *Request) ( string) (*Response, error) {return .Execute(MethodOptions, )}// Patch method does PATCH HTTP request. It's defined in section 2 of RFC5789.func ( *Request) ( string) (*Response, error) {return .Execute(MethodPatch, )}// Send method performs the HTTP request using the method and URL already defined// for current `Request`.//// req := client.R()// req.Method = resty.GET// req.URL = "http://httpbin.org/get"// resp, err := req.Send()func ( *Request) () (*Response, error) {return .Execute(.Method, .URL)}// Execute method performs the HTTP request with given HTTP method and URL// for current `Request`.//// resp, err := client.R().Execute(resty.GET, "http://httpbin.org/get")func ( *Request) (, string) (*Response, error) {var []*net.SRVvar *Responsevar errordefer func() {if := recover(); != nil {if , := .(error); {.client.onPanicHooks(, )} else {.client.onPanicHooks(, fmt.Errorf("panic %v", ))}panic()}}()if .isMultiPart && !( == MethodPost || == MethodPut || == MethodPatch) {// No OnError hook here since this is a request validation error:= fmt.Errorf("multipart content is not allowed in HTTP verb [%v]", ).client.onInvalidHooks(, )return nil,}if .SRV != nil {_, , = net.LookupSRV(.SRV.Service, "tcp", .SRV.Domain)if != nil {.client.onErrorHooks(, nil, )return nil,}}.Method =.URL = .selectAddr(, , 0)if .client.RetryCount == 0 {.Attempt = 1, = .client.execute().client.onErrorHooks(, , unwrapNoRetryErr())return , unwrapNoRetryErr()}= Backoff(func() (*Response, error) {.Attempt++.URL = .selectAddr(, , .Attempt), = .client.execute()if != nil {.log.Warnf("%v, Attempt %v", , .Attempt)}return ,},Retries(.client.RetryCount),WaitTime(.client.RetryWaitTime),MaxWaitTime(.client.RetryMaxWaitTime),RetryConditions(append(.retryConditions, .client.RetryConditions...)),RetryHooks(.client.RetryHooks),ResetMultipartReaders(.client.RetryResetReaders),)if != nil {.log.Errorf("%v", )}.client.onErrorHooks(, , unwrapNoRetryErr())return , unwrapNoRetryErr()}//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾// SRVRecord struct//_______________________________________________________________________// SRVRecord struct holds the data to query the SRV record for the// following service.type SRVRecord struct {Service stringDomain string}//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾// Request Unexported methods//_______________________________________________________________________func ( *Request) ( int64) ( string) {= "***** NO CONTENT *****"if !isPayloadSupported(.Method, .client.AllowGetMethodPayload) {return}if , := .Body.(io.Reader); {= "***** BODY IS io.Reader *****"return}// multipart or form-dataif .isMultiPart || .isFormData {:= int64(.bodyBuf.Len())if > {= fmt.Sprintf("***** REQUEST TOO LARGE (size - %d) *****", )return}= .bodyBuf.String()return}// request body dataif .Body == nil {return}var []bytevar error:= .Header.Get(hdrContentTypeKey):= kindOf(.Body)if canJSONMarshal(, ) {, = noescapeJSONMarshalIndent(&.Body)} else if IsXMLType() && ( == reflect.Struct) {, = xml.MarshalIndent(&.Body, "", " ")} else if , := .Body.(string); {if IsJSONType() {:= []byte():= acquireBuffer()defer releaseBuffer()if = json.Indent(, , "", " "); == nil {= .Bytes()}} else {=}} else if , := .Body.([]byte); {= fmt.Sprintf("***** BODY IS byte(s) (size - %d) *****", len())return}if != nil && == nil {= string()}if len() > 0 {:= int64(len([]byte()))if > {= fmt.Sprintf("***** REQUEST TOO LARGE (size - %d) *****", )}}return}func ( *Request) ( []*net.SRV, string, int) string {if == nil {return}:= % len():= strings.TrimRight([].Target, ".")= strings.TrimLeft(, "/")return fmt.Sprintf("%s://%s:%d/%s", .client.scheme, , [].Port, )}func ( *Request) () {if .values == nil {.values = make(map[string]interface{})}}var noescapeJSONMarshal = func( interface{}) (*bytes.Buffer, error) {:= acquireBuffer():= json.NewEncoder().SetEscapeHTML(false)if := .Encode(); != nil {releaseBuffer()return nil,}return , nil}var noescapeJSONMarshalIndent = func( interface{}) ([]byte, error) {:= acquireBuffer()defer releaseBuffer():= json.NewEncoder().SetEscapeHTML(false).SetIndent("", " ")if := .Encode(); != nil {return nil,}return .Bytes(), nil}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |