github.com/xmidt-org/webpa-common@v1.11.9/xhttp/server.go (about)

     1  package xhttp
     2  
     3  import (
     4  	stdlog "log"
     5  	"net"
     6  	"net/http"
     7  	"time"
     8  
     9  	"github.com/go-kit/kit/log"
    10  	"github.com/go-kit/kit/log/level"
    11  	"github.com/xmidt-org/webpa-common/logging"
    12  )
    13  
    14  var (
    15  	serverKey interface{} = "server"
    16  )
    17  
    18  // ServerKey returns the contextual logging key for the server name
    19  func ServerKey() interface{} {
    20  	return serverKey
    21  }
    22  
    23  // NewServerLogger adapts a go-kit Logger onto a golang Logger in a way that is appropriate
    24  // for http.Server.ErrorLog.
    25  func NewServerLogger(logger log.Logger) *stdlog.Logger {
    26  	if logger == nil {
    27  		logger = logging.DefaultLogger()
    28  	}
    29  
    30  	return stdlog.New(
    31  		log.NewStdlibAdapter(logger),
    32  		"", // having a prefix gives the adapter trouble
    33  		stdlog.LstdFlags|stdlog.LUTC,
    34  	)
    35  }
    36  
    37  // NewServerConnStateLogger adapts a go-kit Logger onto a connection state handler appropriate
    38  // for http.Server.ConnState.
    39  func NewServerConnStateLogger(logger log.Logger) func(net.Conn, http.ConnState) {
    40  	if logger == nil {
    41  		logger = logging.DefaultLogger()
    42  	}
    43  
    44  	return func(c net.Conn, cs http.ConnState) {
    45  		logger.Log(
    46  			"remoteAddress", c.RemoteAddr(),
    47  			"state", cs,
    48  		)
    49  	}
    50  }
    51  
    52  // StartOptions represents the subset of server options that have to do with how
    53  // an HTTP server is started.
    54  type StartOptions struct {
    55  	// Logger is the go-kit Logger to use for server startup and error logging.  If not
    56  	// supplied, logging.DefaultLogger() is used instead.
    57  	Logger log.Logger `json:"-"`
    58  
    59  	// Listener is the optional net.Listener to use.  If not supplied, the http.Server default
    60  	// listener is used.
    61  	Listener net.Listener `json:"-"`
    62  
    63  	// DisableKeepAlives indicates whether the server should honor keep alives
    64  	DisableKeepAlives bool `json:"disableKeepAlives,omitempty"`
    65  
    66  	// CertificateFile is the HTTPS certificate file(s).  If both this field and KeyFile are set,
    67  	// an HTTPS starter function is created.
    68  	CertificateFile []string `json:"certificateFile,omitempty"`
    69  
    70  	// KeyFile is the HTTPS key file(s).  If both this field and CertificateFile are set,
    71  	// an HTTPS starter function is created.
    72  	KeyFile []string `json:"keyFile,omitempty"`
    73  }
    74  
    75  // NewStarter returns a starter closure for the given HTTP server.  The start options are first
    76  // applied to the server instance, and the server instance must not have already been started prior
    77  // to invoking this method.
    78  //
    79  // The returned closure will invoke the correct method on the server to start it, e.g. Serve, ServeTLS, etc.
    80  // The selection of which server method is based on the options.  For example, if CertificateFile and KeyFile
    81  // are set, either of the xxxTLS methods will be invoked based on whether there is a Listener configured.
    82  //
    83  // Note: tlsConfig is expected to already be set
    84  func NewStarter(o StartOptions, s httpServer) func() error {
    85  	if o.Logger == nil {
    86  		o.Logger = logging.DefaultLogger()
    87  	}
    88  
    89  	s.SetKeepAlivesEnabled(!o.DisableKeepAlives)
    90  
    91  	var starter func() error
    92  
    93  	if o.Listener != nil {
    94  		starter = func() error {
    95  			return s.Serve(o.Listener)
    96  		}
    97  	} else {
    98  		starter = func() error {
    99  			return s.ListenAndServe()
   100  		}
   101  	}
   102  
   103  	return func() error {
   104  		o.Logger.Log(level.Key(), level.InfoValue(), logging.MessageKey(), "starting server")
   105  		err := starter()
   106  		if err == http.ErrServerClosed {
   107  			o.Logger.Log(level.Key(), level.InfoValue(), logging.MessageKey(), "server closed")
   108  		} else {
   109  			o.Logger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "server exited", logging.ErrorKey(), err)
   110  		}
   111  
   112  		return err
   113  	}
   114  }
   115  
   116  // httpServer exposes the set of methods expected of an http.Server by this package.
   117  type httpServer interface {
   118  	ListenAndServe() error
   119  	ListenAndServeTLS(string, string) error
   120  
   121  	Serve(net.Listener) error
   122  	ServeTLS(net.Listener, string, string) error
   123  
   124  	SetKeepAlivesEnabled(bool)
   125  }
   126  
   127  // ServerOptions describes the superset of options for both construction an http.Server and
   128  // starting it.
   129  type ServerOptions struct {
   130  	// Logger is the go-kit Logger to use for server startup and error logging.  If not
   131  	// supplied, logging.DefaultLogger() is used instead.
   132  	Logger log.Logger `json:"-"`
   133  
   134  	// Address is the bind address of the server.  If not supplied, defaults to the internal net/http default.
   135  	Address string `json:"address,omitempty"`
   136  
   137  	// ReadTimeout is the maximum duration for reading the entire request.  If not supplied, defaults to the
   138  	// internal net/http default.
   139  	ReadTimeout time.Duration `json:"readTimeout,omitempty"`
   140  
   141  	// ReadHeaderTimeout is the amount of time allowed to read request headers.  If not supplied, defaults to
   142  	// the internal net/http default.
   143  	ReadHeaderTimeout time.Duration `json:"readHeaderTimeout,omitempty"`
   144  
   145  	// WriteTimeout is the maximum duration before timing out writes of the response.  If not supplied, defaults
   146  	// to the internal net/http default.
   147  	WriteTimeout time.Duration `json:"writeTimeout,omitempty"`
   148  
   149  	// IdleTimeout is the maximum amount of time to wait for the next request when keep-alives are enabled.
   150  	// If not supplied, defaults to the internal net/http default.
   151  	IdleTimeout time.Duration `json:"idleTimeout,omitempty"`
   152  
   153  	// MaxHeaderBytes controls the maximum number of bytes the server will read parsing the request header's
   154  	// keys and values.  If not supplied, defaults to the internal net/http default.
   155  	MaxHeaderBytes int `json:"maxHeaderBytes,omitempty"`
   156  
   157  	// Listener is the optional net.Listener to use.  If not supplied, the http.Server default
   158  	// listener is used.
   159  	Listener net.Listener `json:"-"`
   160  
   161  	// DisableKeepAlives indicates whether the server should honor keep alives
   162  	DisableKeepAlives bool `json:"disableKeepAlives,omitempty"`
   163  
   164  	// CertificateFile is the HTTPS certificate file.  If both this field and KeyFile are set,
   165  	// an HTTPS starter function is created.
   166  	CertificateFile []string `json:"certificateFile,omitempty"`
   167  
   168  	// KeyFile is the HTTPS key file.  If both this field and CertificateFile are set,
   169  	// an HTTPS starter function is created.
   170  	KeyFile []string `json:"keyFile,omitempty"`
   171  }
   172  
   173  // StartOptions produces a StartOptions with the corresponding values from this ServerOptions
   174  func (so *ServerOptions) StartOptions() StartOptions {
   175  	logger := so.Logger
   176  	if logger == nil {
   177  		logger = logging.DefaultLogger()
   178  	}
   179  
   180  	return StartOptions{
   181  		Logger: log.With(logger,
   182  			"address", so.Address,
   183  		),
   184  		Listener:          so.Listener,
   185  		DisableKeepAlives: so.DisableKeepAlives,
   186  		CertificateFile:   so.CertificateFile,
   187  		KeyFile:           so.KeyFile,
   188  	}
   189  }
   190  
   191  // NewServer creates a Server from a supplied set of options.
   192  func NewServer(o ServerOptions) *http.Server {
   193  	return &http.Server{
   194  		Addr:              o.Address,
   195  		ReadTimeout:       o.ReadTimeout,
   196  		ReadHeaderTimeout: o.ReadHeaderTimeout,
   197  		WriteTimeout:      o.WriteTimeout,
   198  		IdleTimeout:       o.IdleTimeout,
   199  		MaxHeaderBytes:    o.MaxHeaderBytes,
   200  		ErrorLog:          NewServerLogger(o.Logger),
   201  		ConnState:         NewServerConnStateLogger(o.Logger),
   202  	}
   203  }