package http
import (
)
var (
DefaultHTTPTransportMaxIdleConns = 100
DefaultHTTPTransportMaxIdleConnsPerHost = 10
DefaultHTTPTransportIdleConnTimeout = 90 * time.Second
DefaultHTTPTransportTLSHandleshakeTimeout = 10 * time.Second
DefaultHTTPTransportExpectContinueTimeout = 1 * time.Second
DefaultHTTPTransportTLSMinVersion uint16 = tls.VersionTLS12
)
var (
DefaultDialConnectTimeout = 30 * time.Second
DefaultDialKeepAliveTimeout = 30 * time.Second
)
type BuildableClient struct {
transport *http.Transport
dialer *net.Dialer
initOnce sync.Once
clientTimeout time.Duration
client *http.Client
}
func () *BuildableClient {
return &BuildableClient{}
}
func ( *BuildableClient) ( *http.Request) (*http.Response, error) {
.initOnce.Do(.build)
return .client.Do()
}
func ( *BuildableClient) () aws.HTTPClient {
:= .clone()
.build()
return .client
}
func ( *BuildableClient) () {
.client = wrapWithLimitedRedirect(&http.Client{
Timeout: .clientTimeout,
Transport: .GetTransport(),
})
}
func ( *BuildableClient) () *BuildableClient {
:= NewBuildableClient()
.transport = .GetTransport()
.dialer = .GetDialer()
.clientTimeout = .clientTimeout
return
}
func ( *BuildableClient) ( ...func(*http.Transport)) *BuildableClient {
:= .clone()
:= .GetTransport()
for , := range {
()
}
.transport =
return
}
func ( *BuildableClient) ( ...func(*net.Dialer)) *BuildableClient {
:= .clone()
:= .GetDialer()
for , := range {
()
}
.dialer =
:= .GetTransport()
.DialContext = .dialer.DialContext
.transport =
return
}
func ( *BuildableClient) ( time.Duration) *BuildableClient {
:= .clone()
.clientTimeout =
return
}
func ( *BuildableClient) () *http.Transport {
var *http.Transport
if .transport != nil {
= .transport.Clone()
} else {
= defaultHTTPTransport()
}
return
}
func ( *BuildableClient) () *net.Dialer {
var *net.Dialer
if .dialer != nil {
= shallowCopyStruct(.dialer).(*net.Dialer)
} else {
= defaultDialer()
}
return
}
func ( *BuildableClient) () time.Duration {
return .clientTimeout
}
func () *net.Dialer {
return &net.Dialer{
Timeout: DefaultDialConnectTimeout,
KeepAlive: DefaultDialKeepAliveTimeout,
DualStack: true,
}
}
func () *http.Transport {
:= defaultDialer()
:= &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: .DialContext,
TLSHandshakeTimeout: DefaultHTTPTransportTLSHandleshakeTimeout,
MaxIdleConns: DefaultHTTPTransportMaxIdleConns,
MaxIdleConnsPerHost: DefaultHTTPTransportMaxIdleConnsPerHost,
IdleConnTimeout: DefaultHTTPTransportIdleConnTimeout,
ExpectContinueTimeout: DefaultHTTPTransportExpectContinueTimeout,
ForceAttemptHTTP2: true,
TLSClientConfig: &tls.Config{
MinVersion: DefaultHTTPTransportTLSMinVersion,
},
}
return
}
func ( interface{}) interface{} {
:= reflect.ValueOf()
:= .Type()
var bool
if .Kind() == reflect.Ptr {
= .Elem()
= .Elem()
= true
}
:= reflect.New().Elem()
for := 0; < .NumField(); ++ {
:= .Field()
if len(.PkgPath) != 0 {
continue
}
.Field().Set(.Field())
}
if {
= .Addr()
}
return .Interface()
}
func ( *http.Client) *http.Client {
:= .Transport
if == nil {
= defaultHTTPTransport()
}
:= *
.CheckRedirect = limitedRedirect
.Transport = suppressBadHTTPRedirectTransport{
tr: ,
}
return &
}
func ( *http.Request, []*http.Request) error {
:= .Response
if .URL.String() == badHTTPRedirectLocation {
.Header.Del(badHTTPRedirectLocation)
return http.ErrUseLastResponse
}
switch .StatusCode {
case 307, 308:
return nil
}
return http.ErrUseLastResponse
}
type suppressBadHTTPRedirectTransport struct {
tr http.RoundTripper
}
const badHTTPRedirectLocation = `https://amazonaws.com/badhttpredirectlocation`
func ( suppressBadHTTPRedirectTransport) ( *http.Request) (*http.Response, error) {
, := .tr.RoundTrip()
if != nil {
return ,
}
switch .StatusCode {
case 301, 302:
if := .Header.Get("Location"); len() == 0 {
.Header.Set("Location", badHTTPRedirectLocation)
}
}
return ,
}