github.com/aldelo/common@v1.5.1/wrapper/aws/awscustomhttp2.go (about)

     1  package aws
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  import (
    20  	helper "github.com/aldelo/common"
    21  	"golang.org/x/net/http2"
    22  	"net"
    23  	"net/http"
    24  	"time"
    25  )
    26  
    27  // HttpClientSettings based on aws documentation
    28  type HttpClientSettings struct {
    29  	// Dialer.KeepAlive: negative value disables keep-alive; 0 enables keep-alive
    30  	// default = keep-alive enabled
    31  	ConnKeepAlive *time.Duration
    32  
    33  	// Dialer.Timeout: maximum amount of time a dial will wait for a connection to be created
    34  	// default = 30 seconds
    35  	Connect *time.Duration
    36  
    37  	// Transport.ExpectContinueTimeout: maximum amount of time to wait for a server's first response headers after fully writing the request headers,
    38  	// 		if the response has an "Expect: 100-continue" header,
    39  	//		this time does not include the time to send the request header,
    40  	//		the http client sends its payload after this timeout is exhausted
    41  	// default = 1 second; set to 0 for no timeout and send request payload without waiting
    42  	ExpectContinue *time.Duration
    43  
    44  	// Transport.IdleConnTimeout: maximum amount of time to keep an idle network connection alive between http requests
    45  	// default = 0 for no limit
    46  	IdleConn *time.Duration
    47  
    48  	// Transport.MaxIdleConns: maximum number of idle (keep-alive) connections across all hosts,
    49  	// 		use case: increasing this value when many connections in a short period from same clients
    50  	// default = 0 means no limit
    51  	MaxAllIdleConns *int
    52  
    53  	// Transport.MaxIdleConnsPerHost: maximum number of idle (keep-alive) connections to keep per-host,
    54  	//		use case: increasing this value when many connections in a short period from same clients
    55  	// default = 0 means 2 idle connections per host
    56  	MaxHostIdleConns *int
    57  
    58  	// Transport.ResponseHeaderTimeout: maximum amount of time to wait for a client to read the response header,
    59  	//		if the client isn't able to read the response's header within this duration, the request fails with a timeout error,
    60  	//		warning: when using long-running lambda functions, as the operation does not return any response headers until the lambda has finished or timeout
    61  	// default = no timeout, waits forever
    62  	ResponseHeader *time.Duration
    63  
    64  	// Transport.TLSHandshakeTimeout: maximum amount of time waiting for a TLS handshake to be completed
    65  	// default = 10 seconds; 0 means no timeout
    66  	TlsHandshake *time.Duration
    67  }
    68  
    69  // AwsHttp2Client struct defines container for HttpClientSettings
    70  type AwsHttp2Client struct {
    71  	Options *HttpClientSettings
    72  }
    73  
    74  func (h2 *AwsHttp2Client) setDefaults() {
    75  	if h2.Options == nil {
    76  		h2.Options = new(HttpClientSettings)
    77  	}
    78  
    79  	if h2.Options.ConnKeepAlive == nil {
    80  		h2.Options.ConnKeepAlive = helper.DurationPtr(0)
    81  	}
    82  
    83  	if h2.Options.Connect == nil {
    84  		h2.Options.Connect = helper.DurationPtr(5 * time.Second)
    85  	}
    86  
    87  	if h2.Options.ExpectContinue == nil {
    88  		h2.Options.ExpectContinue = helper.DurationPtr(1 * time.Second)
    89  	}
    90  
    91  	if h2.Options.IdleConn == nil {
    92  		h2.Options.IdleConn = helper.DurationPtr(300 * time.Second)
    93  	}
    94  
    95  	if h2.Options.MaxAllIdleConns == nil {
    96  		h2.Options.MaxAllIdleConns = helper.IntPtr(0)
    97  	}
    98  
    99  	if h2.Options.MaxHostIdleConns == nil {
   100  		h2.Options.MaxHostIdleConns = helper.IntPtr(100)
   101  	}
   102  
   103  	if h2.Options.ResponseHeader == nil {
   104  		h2.Options.ResponseHeader = helper.DurationPtr(5 * time.Second)
   105  	}
   106  
   107  	if h2.Options.TlsHandshake == nil {
   108  		h2.Options.TlsHandshake = helper.DurationPtr(5 * time.Second)
   109  	}
   110  }
   111  
   112  // ConnKeepAlive sets Dialer.KeepAlive: negative value disables keep-alive; 0 enables keep-alive
   113  // default = keep-alive enabled
   114  func (h2 *AwsHttp2Client) ConnKeepAlive(v time.Duration) {
   115  	h2.Options.ConnKeepAlive = &v
   116  }
   117  
   118  // ConnectTimeout sets Dialer.Timeout: maximum amount of time a dial will wait for a connection to be created
   119  // default = 30 seconds
   120  func (h2 *AwsHttp2Client) ConnectTimeout(v time.Duration) {
   121  	h2.Options.Connect = &v
   122  }
   123  
   124  // ExpectContinueTimeout sets Transport.ExpectContinueTimeout: maximum amount of time to wait for a server's first response headers after fully writing the request headers,
   125  //
   126  //	if the response has an "Expect: 100-continue" header,
   127  //	this time does not include the time to send the request header,
   128  //	the http client sends its payload after this timeout is exhausted
   129  //
   130  // default = 1 second; set to 0 for no timeout and send request payload without waiting
   131  func (h2 *AwsHttp2Client) ExpectContinueTimeout(v time.Duration) {
   132  	h2.Options.ExpectContinue = &v
   133  }
   134  
   135  // IdleConnTimeout sets Transport.IdleConnTimeout: maximum amount of time to keep an idle network connection alive between http requests
   136  // default = 0 for no limit
   137  func (h2 *AwsHttp2Client) IdleConnTimeout(v time.Duration) {
   138  	h2.Options.IdleConn = &v
   139  }
   140  
   141  // MaxAllIdleConns sets Transport.MaxIdleConns: maximum number of idle (keep-alive) connections across all hosts,
   142  //
   143  //	use case: increasing this value when many connections in a short period from same clients
   144  //
   145  // default = 0 means no limit
   146  func (h2 *AwsHttp2Client) MaxAllIdleConns(v int) {
   147  	h2.Options.MaxAllIdleConns = &v
   148  }
   149  
   150  // MaxHostIdleConns sets Transport.MaxIdleConnsPerHost: maximum number of idle (keep-alive) connections to keep per-host,
   151  //
   152  //	use case: increasing this value when many connections in a short period from same clients
   153  //
   154  // default = 0 means 2 idle connections per host
   155  func (h2 *AwsHttp2Client) MaxHostIdleConns(v int) {
   156  	h2.Options.MaxHostIdleConns = &v
   157  }
   158  
   159  // ResponseHeaderTimeout sets Transport.ResponseHeaderTimeout: maximum amount of time to wait for a client to read the response header,
   160  //
   161  //	if the client isn't able to read the response's header within this duration, the request fails with a timeout error,
   162  //	warning: when using long-running lambda functions, as the operation does not return any response headers until the lambda has finished or timeout
   163  //
   164  // default = no timeout, waits forever
   165  func (h2 *AwsHttp2Client) ResponseHeaderTimeout(v time.Duration) {
   166  	h2.Options.ResponseHeader = &v
   167  }
   168  
   169  // TlsHandshakeTimeout sets Transport.TLSHandshakeTimeout: maximum amount of time waiting for a TLS handshake to be completed
   170  // default = 10 seconds; 0 means no timeout
   171  func (h2 *AwsHttp2Client) TlsHandshakeTimeout(v time.Duration) {
   172  	h2.Options.TlsHandshake = &v
   173  }
   174  
   175  // NewHttp2Client returns custom http2 client for aws connection
   176  func (h2 *AwsHttp2Client) NewHttp2Client() (*http.Client, error) {
   177  	h2.setDefaults()
   178  
   179  	var client http.Client
   180  
   181  	tr := &http.Transport{
   182  		ResponseHeaderTimeout: *h2.Options.ResponseHeader,
   183  		Proxy:                 http.ProxyFromEnvironment,
   184  		DialContext: (&net.Dialer{
   185  			KeepAlive: *h2.Options.ConnKeepAlive,
   186  			Timeout:   *h2.Options.Connect,
   187  		}).DialContext,
   188  		MaxIdleConns:          *h2.Options.MaxAllIdleConns,
   189  		IdleConnTimeout:       *h2.Options.IdleConn,
   190  		TLSHandshakeTimeout:   *h2.Options.TlsHandshake,
   191  		MaxIdleConnsPerHost:   *h2.Options.MaxHostIdleConns,
   192  		ExpectContinueTimeout: *h2.Options.ExpectContinue,
   193  	}
   194  
   195  	// client makes HTTP/2 requests
   196  	err := http2.ConfigureTransport(tr)
   197  
   198  	if err != nil {
   199  		return &client, err
   200  	}
   201  
   202  	return &http.Client{
   203  		Transport: tr,
   204  	}, nil
   205  }