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