github.com/circl-dev/go-swagger@v0.31.0/examples/todo-list/restapi/server.go (about)

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