github.com/iotexproject/iotex-core@v1.14.1-rc1/pkg/util/httputil/httputil.go (about)

     1  package httputil
     2  
     3  import (
     4  	"net"
     5  	"net/http"
     6  	"time"
     7  
     8  	"golang.org/x/net/netutil"
     9  )
    10  
    11  const (
    12  	_connectionCount = 400
    13  )
    14  
    15  type (
    16  	// ServerOption is a server option
    17  	ServerOption func(*serverConfig)
    18  
    19  	serverConfig struct {
    20  		ReadHeaderTimeout time.Duration
    21  		ReadTimeout       time.Duration
    22  		WriteTimeout      time.Duration
    23  		IdleTimeout       time.Duration
    24  	}
    25  )
    26  
    27  // DefaultServerConfig is the default server config
    28  var DefaultServerConfig = serverConfig{
    29  	ReadHeaderTimeout: 5 * time.Second,
    30  	ReadTimeout:       30 * time.Second,
    31  	WriteTimeout:      30 * time.Second,
    32  	IdleTimeout:       120 * time.Second,
    33  }
    34  
    35  // ReadHeaderTimeout sets header timeout
    36  func ReadHeaderTimeout(h time.Duration) ServerOption {
    37  	return func(cfg *serverConfig) {
    38  		cfg.ReadHeaderTimeout = h
    39  	}
    40  }
    41  
    42  // NewServer creates a HTTP server with time out settings.
    43  func NewServer(addr string, handler http.Handler, opts ...ServerOption) http.Server {
    44  	cfg := DefaultServerConfig
    45  	for _, opt := range opts {
    46  		opt(&cfg)
    47  	}
    48  
    49  	return http.Server{
    50  		ReadHeaderTimeout: cfg.ReadHeaderTimeout,
    51  		ReadTimeout:       cfg.ReadTimeout,
    52  		WriteTimeout:      cfg.WriteTimeout,
    53  		IdleTimeout:       cfg.IdleTimeout,
    54  		Addr:              addr,
    55  		Handler:           handler,
    56  	}
    57  }
    58  
    59  // LimitListener creates a tcp keep-alive listener with 400 maximum connections.
    60  func LimitListener(addr string) (net.Listener, error) {
    61  	if addr == "" {
    62  		addr = ":http"
    63  	}
    64  	ln, err := net.Listen("tcp", addr)
    65  	if err != nil {
    66  		return ln, err
    67  	}
    68  	return netutil.LimitListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, _connectionCount), nil
    69  }
    70  
    71  // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
    72  // connections. It's used by ListenAndServe and ListenAndServeTLS so
    73  // dead TCP connections (e.g. closing laptop mid-download) eventually
    74  // go away.
    75  // refer: https://golang.org/src/net/http/server.go
    76  type tcpKeepAliveListener struct {
    77  	*net.TCPListener
    78  }
    79  
    80  func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
    81  	tc, err := ln.AcceptTCP()
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	if err = tc.SetKeepAlive(true); err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	if err = tc.SetKeepAlivePeriod(3 * time.Minute); err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	return tc, nil
    95  }