github.com/percona-lab/go-swagger@v0.19.0/generator/templates/server/server.gotmpl (about)

     1  // Code generated by go-swagger; DO NOT EDIT.
     2  
     3  
     4  {{ if .Copyright -}}// {{ comment .Copyright -}}{{ end }}
     5  
     6  
     7  package {{ .APIPackage }}
     8  
     9  import (
    10  	"context"
    11  	"crypto/tls"
    12  	"errors"
    13  	"log"
    14  	"net"
    15  	"net/http"
    16  	"os"
    17  	"os/signal"
    18  	"strconv"
    19  	"sync"
    20  	"sync/atomic"
    21  	"syscall"
    22  	"time"
    23  
    24  
    25    "github.com/go-openapi/swag"
    26    {{ if .UseGoStructFlags }}flags "github.com/jessevdk/go-flags"
    27    {{ end -}}
    28    "github.com/go-openapi/runtime/flagext"
    29    {{ if .UsePFlags }}flag "github.com/spf13/pflag"
    30    {{ end -}}
    31    "golang.org/x/net/netutil"
    32  
    33    {{ range .DefaultImports }}{{ printf "%q" . }}
    34    {{ end }}
    35    {{ range $key, $value := .Imports }}{{ $key }} {{ printf "%q" $value }}
    36    {{ end }}
    37  )
    38  
    39  const (
    40  	schemeHTTP  = "http"
    41  	schemeHTTPS = "https"
    42  	schemeUnix  = "unix"
    43  )
    44  
    45  var defaultSchemes []string
    46  
    47  func init() {
    48  	defaultSchemes = []string{ {{ if (hasInsecure .Schemes) }}
    49  		schemeHTTP,{{ end}}{{ if (hasSecure .Schemes) }}
    50  		schemeHTTPS,{{ end }}{{ if (contains .ExtraSchemes "unix") }}
    51  		schemeUnix,{{ end }}
    52  	}
    53  }
    54  
    55  {{ if .UsePFlags }}
    56  var ({{ if .ExcludeSpec }}
    57    specFile         string
    58    {{ end }}enabledListeners []string
    59    cleanupTimeout   time.Duration
    60    gracefulTimeout  time.Duration
    61    maxHeaderSize    flagext.ByteSize
    62  
    63    socketPath string
    64  
    65    host         string
    66    port         int
    67    listenLimit  int
    68    keepAlive    time.Duration
    69    readTimeout  time.Duration
    70    writeTimeout time.Duration
    71  
    72    tlsHost           string
    73    tlsPort           int
    74    tlsListenLimit    int
    75    tlsKeepAlive      time.Duration
    76    tlsReadTimeout    time.Duration
    77    tlsWriteTimeout   time.Duration
    78    tlsCertificate    string
    79    tlsCertificateKey string
    80    tlsCACertificate  string
    81  )
    82  
    83  func init() {
    84    maxHeaderSize = flagext.ByteSize(1000000){{ if .ExcludeSpec }}
    85    flag.StringVarP(&specFile, "spec", "", "", "the swagger specification to serve")
    86    {{ end }}
    87  
    88  	flag.StringSliceVar(&enabledListeners, "scheme", defaultSchemes, "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec")
    89  	flag.DurationVar(&cleanupTimeout, "cleanup-timeout", 10*time.Second, "grace period for which to wait before killing idle connections")
    90  	flag.DurationVar(&gracefulTimeout, "graceful-timeout", 15*time.Second, "grace period for which to wait before shutting down the server")
    91  	flag.Var(&maxHeaderSize, "max-header-size", "controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body")
    92  
    93  	flag.StringVar(&socketPath, "socket-path", "/var/run/todo-list.sock", "the unix socket to listen on")
    94  
    95  	flag.StringVar(&host, "host", "localhost", "the IP to listen on")
    96  	flag.IntVar(&port, "port", 0, "the port to listen on for insecure connections, defaults to a random value")
    97  	flag.IntVar(&listenLimit, "listen-limit", 0, "limit the number of outstanding requests")
    98  	flag.DurationVar(&keepAlive, "keep-alive", 3*time.Minute, "sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)")
    99  	flag.DurationVar(&readTimeout, "read-timeout", 30*time.Second, "maximum duration before timing out read of the request")
   100  	flag.DurationVar(&writeTimeout, "write-timeout", 30*time.Second, "maximum duration before timing out write of the response")
   101  
   102  	flag.StringVar(&tlsHost, "tls-host", "localhost", "the IP to listen on")
   103  	flag.IntVar(&tlsPort, "tls-port", 0, "the port to listen on for secure connections, defaults to a random value")
   104  	flag.StringVar(&tlsCertificate, "tls-certificate", "", "the certificate file to use for secure connections")
   105  	flag.StringVar(&tlsCertificateKey, "tls-key", "", "the private key file to use for secure connections (without passphrase)")
   106  	flag.StringVar(&tlsCACertificate, "tls-ca", "", "the certificate authority certificate file to be used with mutual tls auth")
   107  	flag.IntVar(&tlsListenLimit, "tls-listen-limit", 0, "limit the number of outstanding requests")
   108  	flag.DurationVar(&tlsKeepAlive, "tls-keep-alive", 3*time.Minute, "sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)")
   109  	flag.DurationVar(&tlsReadTimeout, "tls-read-timeout", 30*time.Second, "maximum duration before timing out read of the request")
   110  	flag.DurationVar(&tlsWriteTimeout, "tls-write-timeout", 30*time.Second, "maximum duration before timing out write of the response")
   111  }
   112  
   113  func stringEnvOverride(orig string, def string, keys ...string) string {
   114  	for _, k := range keys {
   115  		if os.Getenv(k) != "" {
   116  			return os.Getenv(k)
   117  		}
   118  	}
   119  	if def != "" && orig == "" {
   120  		return def
   121  	}
   122  	return orig
   123  }
   124  
   125  func intEnvOverride(orig int, def int, keys ...string) int {
   126  	for _, k := range keys {
   127  		if os.Getenv(k) != "" {
   128  			v, err := strconv.Atoi(os.Getenv(k))
   129  			if err != nil {
   130  				fmt.Fprintln(os.Stderr, k, "is not a valid number")
   131  				os.Exit(1)
   132  			}
   133  			return v
   134  		}
   135  	}
   136  	if def != 0 && orig == 0 {
   137  		return def
   138  	}
   139  	return orig
   140  }
   141  {{ end }}
   142  
   143  // NewServer creates a new api {{ humanize .Name }} server but does not configure it
   144  func NewServer(api *{{ .Package }}.{{ pascalize .Name }}API) *Server {
   145  	s := new(Server)
   146    {{ if .UsePFlags }}
   147  	s.EnabledListeners = enabledListeners
   148  	s.CleanupTimeout = cleanupTimeout
   149  	s.GracefulTimeout = gracefulTimeout
   150  	s.MaxHeaderSize = maxHeaderSize
   151  	s.SocketPath = socketPath
   152  	s.Host = stringEnvOverride(host, "", "HOST")
   153  	s.Port = intEnvOverride(port, 0, "PORT")
   154  	s.ListenLimit = listenLimit
   155  	s.KeepAlive = keepAlive
   156  	s.ReadTimeout = readTimeout
   157  	s.WriteTimeout = writeTimeout
   158  	s.TLSHost = stringEnvOverride(tlsHost, s.Host, "TLS_HOST", "HOST")
   159  	s.TLSPort = intEnvOverride(tlsPort, 0, "TLS_PORT")
   160  	s.TLSCertificate = stringEnvOverride(tlsCertificate, "", "TLS_CERTIFICATE")
   161  	s.TLSCertificateKey = stringEnvOverride(tlsCertificateKey, "", "TLS_PRIVATE_KEY")
   162  	s.TLSCACertificate = stringEnvOverride(tlsCACertificate, "", "TLS_CA_CERTIFICATE")
   163  	s.TLSListenLimit = tlsListenLimit
   164  	s.TLSKeepAlive = tlsKeepAlive
   165  	s.TLSReadTimeout = tlsReadTimeout
   166  	s.TLSWriteTimeout = tlsWriteTimeout
   167      {{- if .ExcludeSpec }}
   168      s.Spec = specFile
   169      {{- end }}
   170    {{- end }}
   171  	s.shutdown = make(chan struct{})
   172  	s.api = api
   173  	s.interrupt = make(chan os.Signal, 1)
   174  	return s
   175  }
   176  
   177  // ConfigureAPI configures the API and handlers.
   178  func (s *Server) ConfigureAPI() {
   179      if s.api != nil {
   180          s.handler = configureAPI(s.api)
   181      }
   182  }
   183  
   184  // ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
   185  func (s *Server) ConfigureFlags() {
   186      if s.api != nil {
   187         configureFlags(s.api)
   188      }
   189  }
   190  
   191  // Server for the {{ humanize .Name }} API
   192  type Server struct {
   193  	EnabledListeners []string{{ if .UseGoStructFlags }} `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`{{ end }}
   194  	CleanupTimeout   time.Duration{{ if .UseGoStructFlags }}    `long:"cleanup-timeout" description:"grace period for which to wait before killing idle connections" default:"10s"`{{ end }}
   195  	GracefulTimeout  time.Duration{{ if .UseGoStructFlags }}    `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`{{ end }}
   196  	MaxHeaderSize    flagext.ByteSize{{ if .UseGoStructFlags }} `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`{{ end }}
   197  
   198  	SocketPath {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/{{ dasherize .Name }}.sock"`{{ end }}
   199  	domainSocketL net.Listener
   200  
   201  	Host string{{ if .UseGoStructFlags }} `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`{{ end }}
   202  	Port int{{ if .UseGoStructFlags }}    `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`{{ end }}
   203  	ListenLimit  int{{ if .UseGoStructFlags }}           `long:"listen-limit" description:"limit the number of outstanding requests"`{{ end }}
   204  	KeepAlive    time.Duration{{ if .UseGoStructFlags }} `long:"keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)" default:"3m"`{{ end }}
   205  	ReadTimeout  time.Duration{{ if .UseGoStructFlags }} `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`{{ end }}
   206  	WriteTimeout time.Duration{{ if .UseGoStructFlags }} `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`{{ end }}
   207  	httpServerL   net.Listener
   208  
   209  	TLSHost           string{{ if .UseGoStructFlags }}         `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`{{ end }}
   210  	TLSPort           int{{ if .UseGoStructFlags }}            `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`{{ end }}
   211  	TLSCertificate    {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`{{ end }}
   212  	TLSCertificateKey {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`{{ end }}
   213  	TLSCACertificate  {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`{{ end }}
   214  	TLSListenLimit    int{{ if .UseGoStructFlags }}            `long:"tls-listen-limit" description:"limit the number of outstanding requests"`{{ end }}
   215  	TLSKeepAlive      time.Duration{{ if .UseGoStructFlags }}  `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`{{ end }}
   216  	TLSReadTimeout    time.Duration{{ if .UseGoStructFlags }}  `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`{{ end }}
   217  	TLSWriteTimeout   time.Duration{{ if .UseGoStructFlags }}  `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`{{ end }}
   218  	httpsServerL  net.Listener
   219  
   220  	{{ if .ExcludeSpec }}Spec {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"spec" description:"the swagger specification to serve"`{{ end }}{{ end }}
   221  	api               *{{ .Package }}.{{ pascalize .Name }}API
   222  	handler           http.Handler
   223  	hasListeners      bool
   224  	shutdown          chan struct{}
   225  	shuttingDown      int32
   226  	interrupted       bool
   227  	interrupt         chan os.Signal
   228  }
   229  
   230  // Logf logs message either via defined user logger or via system one if no user logger is defined.
   231  func (s *Server) Logf(f string, args ...interface{}) {
   232  	if s.api != nil && s.api.Logger != nil {
   233  		s.api.Logger(f, args...)
   234  	} else {
   235  		log.Printf(f, args...)
   236  	}
   237  }
   238  
   239  // Fatalf logs message either via defined user logger or via system one if no user logger is defined.
   240  // Exits with non-zero status after printing
   241  func (s *Server) Fatalf(f string, args ...interface{}) {
   242  	if s.api != nil && s.api.Logger != nil {
   243  		s.api.Logger(f, args...)
   244  		os.Exit(1)
   245  	} else {
   246  		log.Fatalf(f, args...)
   247  	}
   248  }
   249  
   250  // SetAPI configures the server with the specified API. Needs to be called before Serve
   251  func (s *Server) SetAPI(api *{{ .Package }}.{{ pascalize .Name }}API) {
   252  	if api == nil {
   253  		s.api = nil
   254  		s.handler = nil
   255  		return
   256  	}
   257  
   258  	s.api = api
   259  	s.api.Logger = log.Printf
   260  	s.handler = configureAPI(api)
   261  }
   262  
   263  func (s *Server) hasScheme(scheme string) bool {
   264  	schemes := s.EnabledListeners
   265  	if len(schemes) == 0 {
   266  		schemes = defaultSchemes
   267  	}
   268  
   269  	for _, v := range schemes {
   270  		if v == scheme {
   271  			return true
   272  		}
   273  	}
   274  	return false
   275  }
   276  
   277  // Serve the api
   278  func (s *Server) Serve() (err error) {
   279  	if !s.hasListeners {
   280  		if err = s.Listen(); err != nil {
   281  		  return err
   282  		}
   283  	}
   284  
   285  	// set default handler, if none is set
   286  	if s.handler == nil {
   287  		if s.api == nil {
   288  			return errors.New("can't create the default handler, as no api is set")
   289  		}
   290  
   291  		s.SetHandler(s.api.Serve(nil))
   292  	}
   293  
   294  	wg := new(sync.WaitGroup)
   295  	once := new(sync.Once)
   296  	signalNotify(s.interrupt)
   297  	go handleInterrupt(once, s)
   298  
   299  	servers := []*http.Server{}
   300  	wg.Add(1)
   301  	go s.handleShutdown(wg, &servers)
   302  
   303  	if s.hasScheme(schemeUnix) {
   304  		domainSocket := new(http.Server)
   305  		domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
   306  		domainSocket.Handler = s.handler
   307  		if int64(s.CleanupTimeout) > 0 {
   308  			domainSocket.IdleTimeout = s.CleanupTimeout
   309  		}
   310  
   311  		configureServer(domainSocket, "unix", string(s.SocketPath))
   312  
   313  		servers = append(servers, domainSocket)
   314  		wg.Add(1)
   315  		s.Logf("Serving {{ humanize .Name }} at unix://%s", s.SocketPath)
   316  		go func(l net.Listener){
   317  		  defer wg.Done()
   318  		  if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
   319  			s.Fatalf("%v", err)
   320  		  }
   321  		  s.Logf("Stopped serving {{ humanize .Name }} at unix://%s", s.SocketPath)
   322  		}(s.domainSocketL)
   323  	}
   324  
   325  	if s.hasScheme(schemeHTTP) {
   326  		httpServer := new(http.Server)
   327  		httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
   328  		httpServer.ReadTimeout = s.ReadTimeout
   329  		httpServer.WriteTimeout = s.WriteTimeout
   330  		httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
   331  		if s.ListenLimit > 0 {
   332  			s.httpServerL = netutil.LimitListener(s.httpServerL, s.ListenLimit)
   333  		}
   334  
   335  		if int64(s.CleanupTimeout) > 0 {
   336  			httpServer.IdleTimeout = s.CleanupTimeout
   337  		}
   338  
   339  		httpServer.Handler = s.handler
   340  
   341  		configureServer(httpServer, "http", s.httpServerL.Addr().String())
   342  
   343  		servers = append(servers, httpServer)
   344  		wg.Add(1)
   345  		s.Logf("Serving {{ humanize .Name }} at http://%s", s.httpServerL.Addr())
   346  		go func(l net.Listener) {
   347  			defer wg.Done()
   348  			if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
   349  				s.Fatalf("%v", err)
   350  			}
   351  			s.Logf("Stopped serving {{ humanize .Name }} at http://%s", l.Addr())
   352  		}(s.httpServerL)
   353  	}
   354  
   355  	if s.hasScheme(schemeHTTPS) {
   356  		httpsServer := new(http.Server)
   357  		httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
   358  		httpsServer.ReadTimeout = s.TLSReadTimeout
   359  		httpsServer.WriteTimeout = s.TLSWriteTimeout
   360  		httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
   361  		if s.TLSListenLimit > 0 {
   362  			s.httpsServerL = netutil.LimitListener(s.httpsServerL, s.TLSListenLimit)
   363  		}
   364  		if int64(s.CleanupTimeout) > 0 {
   365  			httpsServer.IdleTimeout = s.CleanupTimeout
   366  		}
   367  		httpsServer.Handler = s.handler
   368  
   369  		// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
   370  		httpsServer.TLSConfig = &tls.Config{
   371  			// Causes servers to use Go's default ciphersuite preferences,
   372  			// which are tuned to avoid attacks. Does nothing on clients.
   373  			PreferServerCipherSuites: true,
   374  			// Only use curves which have assembly implementations
   375  			// https://github.com/golang/go/tree/master/src/crypto/elliptic
   376  			CurvePreferences: []tls.CurveID{tls.CurveP256},
   377  		{{- if .UseModernMode }}
   378  			// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
   379  			NextProtos: []string{"http/1.1", "h2"},
   380  			// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
   381  			MinVersion: tls.VersionTLS12,
   382  			// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
   383  			CipherSuites: []uint16{
   384  				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   385  				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   386  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   387  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   388  				tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   389  				tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   390  			},
   391  		{{- end }}
   392  		}
   393  
   394  		// build standard config from server options
   395  		if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
   396  			httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
   397  			httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair({{ if .UseGoStructFlags }}string({{ end }}s.TLSCertificate{{ if .UseGoStructFlags }}){{ end }}, {{ if .UseGoStructFlags }}string({{ end }}s.TLSCertificateKey{{ if .UseGoStructFlags }}){{ end }})
   398  			if err != nil {
   399  				return err
   400  			}
   401  		}
   402  
   403  		if s.TLSCACertificate != "" {
   404  			// include specified CA certificate
   405  			caCert, caCertErr := ioutil.ReadFile({{ if .UseGoStructFlags }}string({{ end }}s.TLSCACertificate{{ if .UseGoStructFlags }}){{ end }})
   406  			if caCertErr != nil {
   407  				return caCertErr
   408  			}
   409  			caCertPool := x509.NewCertPool()
   410  			ok := caCertPool.AppendCertsFromPEM(caCert)
   411  			if !ok {
   412  				return fmt.Errorf("cannot parse CA certificate")
   413  			}
   414  			httpsServer.TLSConfig.ClientCAs = caCertPool
   415  			httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
   416  		}
   417  
   418  		// call custom TLS configurator
   419  		configureTLS(httpsServer.TLSConfig)
   420  
   421  		if len(httpsServer.TLSConfig.Certificates) == 0 {
   422  			// after standard and custom config are passed, this ends up with no certificate
   423  			if s.TLSCertificate == "" {
   424  				if s.TLSCertificateKey == "" {
   425  					s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
   426  				}
   427  				s.Fatalf("the required flag `--tls-certificate` was not specified")
   428  			}
   429  			if s.TLSCertificateKey == "" {
   430  				s.Fatalf("the required flag `--tls-key` was not specified")
   431  			}
   432  			// this happens with a wrong custom TLS configurator
   433  			s.Fatalf("no certificate was configured for TLS")
   434  		}
   435  
   436  		// must have at least one certificate or panics
   437  		httpsServer.TLSConfig.BuildNameToCertificate()
   438  
   439  		configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
   440  
   441  		servers = append(servers, httpsServer)
   442  		wg.Add(1)
   443  		s.Logf("Serving {{ humanize .Name }} at https://%s", s.httpsServerL.Addr())
   444  		go func(l net.Listener) {
   445  			defer wg.Done()
   446  			if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
   447  				s.Fatalf("%v", err)
   448  			}
   449  			s.Logf("Stopped serving {{ humanize .Name }} at https://%s", l.Addr())
   450  		}(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
   451  	}
   452  
   453  	wg.Wait()
   454  	return nil
   455  }
   456  
   457  // Listen creates the listeners for the server
   458  func (s *Server) Listen() error {
   459    if s.hasListeners { // already done this
   460      return nil
   461    }
   462  
   463    if s.hasScheme(schemeHTTPS) {
   464      // Use http host if https host wasn't defined
   465      if s.TLSHost == "" {
   466        s.TLSHost = s.Host
   467      }
   468  		// Use http listen limit if https listen limit wasn't defined
   469  		if s.TLSListenLimit == 0 {
   470  			s.TLSListenLimit = s.ListenLimit
   471  		}
   472  		// Use http tcp keep alive if https tcp keep alive wasn't defined
   473  		if int64(s.TLSKeepAlive) == 0 {
   474  			s.TLSKeepAlive = s.KeepAlive
   475  		}
   476  		// Use http read timeout if https read timeout wasn't defined
   477  		if int64(s.TLSReadTimeout) == 0 {
   478  			s.TLSReadTimeout = s.ReadTimeout
   479  		}
   480  		// Use http write timeout if https write timeout wasn't defined
   481  		if int64(s.TLSWriteTimeout) == 0 {
   482  			s.TLSWriteTimeout = s.WriteTimeout
   483  		}
   484    }
   485  
   486    if s.hasScheme(schemeUnix) {
   487      domSockListener, err := net.Listen("unix", string(s.SocketPath))
   488      if err != nil {
   489        return err
   490      }
   491      s.domainSocketL = domSockListener
   492    }
   493  
   494    if s.hasScheme(schemeHTTP) {
   495      listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
   496      if err != nil {
   497        return err
   498      }
   499  
   500      h, p, err := swag.SplitHostPort(listener.Addr().String())
   501      if err != nil {
   502        return err
   503      }
   504      s.Host = h
   505      s.Port = p
   506      s.httpServerL = listener
   507    }
   508  
   509    if s.hasScheme(schemeHTTPS) {
   510      tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
   511      if err != nil {
   512        return err
   513      }
   514  
   515      sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
   516      if err != nil {
   517        return err
   518      }
   519      s.TLSHost = sh
   520      s.TLSPort = sp
   521      s.httpsServerL = tlsListener
   522    }
   523  
   524    s.hasListeners = true
   525  	return nil
   526  }
   527  
   528  // Shutdown server and clean up resources
   529  func (s *Server) Shutdown() error {
   530  	if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
   531  		close(s.shutdown)
   532  	}
   533  	return nil
   534  }
   535  
   536  func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
   537  	// wg.Done must occur last, after s.api.ServerShutdown()
   538  	// (to preserve old behaviour)
   539  	defer wg.Done()
   540  
   541  	<-s.shutdown
   542  
   543  	servers := *serversPtr
   544  
   545  	ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
   546  	defer cancel()
   547  
   548  	shutdownChan := make(chan bool)
   549  	for i := range servers {
   550  		server := servers[i]
   551  		go func() {
   552  			var success bool
   553  			defer func() {
   554  				shutdownChan <- success
   555  			}()
   556  			if err := server.Shutdown(ctx); err != nil {
   557  				// Error from closing listeners, or context timeout:
   558  				s.Logf("HTTP server Shutdown: %v", err)
   559  			} else {
   560  				success = true
   561  			}
   562  		}()
   563  	}
   564  
   565  	// Wait until all listeners have successfully shut down before calling ServerShutdown
   566  	success := true
   567  	for range servers {
   568  		success = success && <-shutdownChan
   569  	}
   570  	if success {
   571  		s.api.ServerShutdown()
   572  	}
   573  }
   574  
   575  // GetHandler returns a handler useful for testing
   576  func (s *Server) GetHandler() http.Handler {
   577  	return s.handler
   578  }
   579  
   580  // SetHandler allows for setting a http handler on this server
   581  func (s *Server) SetHandler(handler http.Handler) {
   582  	s.handler = handler
   583  }
   584  
   585  // UnixListener returns the domain socket listener
   586  func (s *Server) UnixListener() (net.Listener, error) {
   587  	if !s.hasListeners {
   588  		if err := s.Listen(); err != nil {
   589  			return nil, err
   590  		}
   591  	}
   592  	return s.domainSocketL, nil
   593  }
   594  
   595  // HTTPListener returns the http listener
   596  func (s *Server) HTTPListener() (net.Listener, error) {
   597  	if !s.hasListeners {
   598  		if err := s.Listen(); err != nil {
   599  			return nil, err
   600  		}
   601  	}
   602  	return s.httpServerL, nil
   603  }
   604  
   605  // TLSListener returns the https listener
   606  func (s *Server) TLSListener() (net.Listener, error) {
   607  	if !s.hasListeners {
   608  		if err := s.Listen(); err != nil {
   609  			return nil, err
   610  		}
   611  	}
   612  	return s.httpsServerL, nil
   613  }
   614  
   615  func handleInterrupt(once *sync.Once, s *Server) {
   616  	once.Do(func(){
   617  	for _ = range s.interrupt {
   618  		if s.interrupted {
   619  			s.Logf("Server already shutting down")
   620  			continue
   621  		}
   622  		s.interrupted = true
   623  		s.Logf("Shutting down... ")
   624  		if err := s.Shutdown(); err != nil {
   625  			s.Logf("HTTP server Shutdown: %v", err)
   626  		}
   627  	}
   628  	})
   629  }
   630  
   631  func signalNotify(interrupt chan<- os.Signal) {
   632  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
   633  }