github.com/emreu/go-swagger@v0.22.1/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/runtime/flagext"
    24  	"github.com/go-openapi/swag"
    25  	flag "github.com/spf13/pflag"
    26  	"golang.org/x/net/netutil"
    27  
    28  	"github.com/go-swagger/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  	wg.Add(1)
   283  	go s.handleShutdown(wg, &servers)
   284  
   285  	if s.hasScheme(schemeUnix) {
   286  		domainSocket := new(http.Server)
   287  		domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
   288  		domainSocket.Handler = s.handler
   289  		if int64(s.CleanupTimeout) > 0 {
   290  			domainSocket.IdleTimeout = s.CleanupTimeout
   291  		}
   292  
   293  		configureServer(domainSocket, "unix", string(s.SocketPath))
   294  
   295  		servers = append(servers, domainSocket)
   296  		wg.Add(1)
   297  		s.Logf("Serving todo list at unix://%s", s.SocketPath)
   298  		go func(l net.Listener) {
   299  			defer wg.Done()
   300  			if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
   301  				s.Fatalf("%v", err)
   302  			}
   303  			s.Logf("Stopped serving todo list at unix://%s", s.SocketPath)
   304  		}(s.domainSocketL)
   305  	}
   306  
   307  	if s.hasScheme(schemeHTTP) {
   308  		httpServer := new(http.Server)
   309  		httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
   310  		httpServer.ReadTimeout = s.ReadTimeout
   311  		httpServer.WriteTimeout = s.WriteTimeout
   312  		httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
   313  		if s.ListenLimit > 0 {
   314  			s.httpServerL = netutil.LimitListener(s.httpServerL, s.ListenLimit)
   315  		}
   316  
   317  		if int64(s.CleanupTimeout) > 0 {
   318  			httpServer.IdleTimeout = s.CleanupTimeout
   319  		}
   320  
   321  		httpServer.Handler = s.handler
   322  
   323  		configureServer(httpServer, "http", s.httpServerL.Addr().String())
   324  
   325  		servers = append(servers, httpServer)
   326  		wg.Add(1)
   327  		s.Logf("Serving todo list at http://%s", s.httpServerL.Addr())
   328  		go func(l net.Listener) {
   329  			defer wg.Done()
   330  			if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
   331  				s.Fatalf("%v", err)
   332  			}
   333  			s.Logf("Stopped serving todo list at http://%s", l.Addr())
   334  		}(s.httpServerL)
   335  	}
   336  
   337  	if s.hasScheme(schemeHTTPS) {
   338  		httpsServer := new(http.Server)
   339  		httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
   340  		httpsServer.ReadTimeout = s.TLSReadTimeout
   341  		httpsServer.WriteTimeout = s.TLSWriteTimeout
   342  		httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
   343  		if s.TLSListenLimit > 0 {
   344  			s.httpsServerL = netutil.LimitListener(s.httpsServerL, s.TLSListenLimit)
   345  		}
   346  		if int64(s.CleanupTimeout) > 0 {
   347  			httpsServer.IdleTimeout = s.CleanupTimeout
   348  		}
   349  		httpsServer.Handler = s.handler
   350  
   351  		// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
   352  		httpsServer.TLSConfig = &tls.Config{
   353  			// Causes servers to use Go's default ciphersuite preferences,
   354  			// which are tuned to avoid attacks. Does nothing on clients.
   355  			PreferServerCipherSuites: true,
   356  			// Only use curves which have assembly implementations
   357  			// https://github.com/golang/go/tree/master/src/crypto/elliptic
   358  			CurvePreferences: []tls.CurveID{tls.CurveP256},
   359  			// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
   360  			NextProtos: []string{"h2", "http/1.1"},
   361  			// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
   362  			MinVersion: tls.VersionTLS12,
   363  			// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
   364  			CipherSuites: []uint16{
   365  				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   366  				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   367  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   368  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   369  				tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   370  				tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   371  			},
   372  		}
   373  
   374  		// build standard config from server options
   375  		if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
   376  			httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
   377  			httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(s.TLSCertificate, s.TLSCertificateKey)
   378  			if err != nil {
   379  				return err
   380  			}
   381  		}
   382  
   383  		if s.TLSCACertificate != "" {
   384  			// include specified CA certificate
   385  			caCert, caCertErr := ioutil.ReadFile(s.TLSCACertificate)
   386  			if caCertErr != nil {
   387  				return caCertErr
   388  			}
   389  			caCertPool := x509.NewCertPool()
   390  			ok := caCertPool.AppendCertsFromPEM(caCert)
   391  			if !ok {
   392  				return fmt.Errorf("cannot parse CA certificate")
   393  			}
   394  			httpsServer.TLSConfig.ClientCAs = caCertPool
   395  			httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
   396  		}
   397  
   398  		// call custom TLS configurator
   399  		configureTLS(httpsServer.TLSConfig)
   400  
   401  		if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
   402  			// after standard and custom config are passed, this ends up with no certificate
   403  			if s.TLSCertificate == "" {
   404  				if s.TLSCertificateKey == "" {
   405  					s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
   406  				}
   407  				s.Fatalf("the required flag `--tls-certificate` was not specified")
   408  			}
   409  			if s.TLSCertificateKey == "" {
   410  				s.Fatalf("the required flag `--tls-key` was not specified")
   411  			}
   412  			// this happens with a wrong custom TLS configurator
   413  			s.Fatalf("no certificate was configured for TLS")
   414  		}
   415  
   416  		// must have at least one certificate or panics
   417  		httpsServer.TLSConfig.BuildNameToCertificate()
   418  
   419  		configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
   420  
   421  		servers = append(servers, httpsServer)
   422  		wg.Add(1)
   423  		s.Logf("Serving todo list at https://%s", s.httpsServerL.Addr())
   424  		go func(l net.Listener) {
   425  			defer wg.Done()
   426  			if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
   427  				s.Fatalf("%v", err)
   428  			}
   429  			s.Logf("Stopped serving todo list at https://%s", l.Addr())
   430  		}(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
   431  	}
   432  
   433  	wg.Wait()
   434  	return nil
   435  }
   436  
   437  // Listen creates the listeners for the server
   438  func (s *Server) Listen() error {
   439  	if s.hasListeners { // already done this
   440  		return nil
   441  	}
   442  
   443  	if s.hasScheme(schemeHTTPS) {
   444  		// Use http host if https host wasn't defined
   445  		if s.TLSHost == "" {
   446  			s.TLSHost = s.Host
   447  		}
   448  		// Use http listen limit if https listen limit wasn't defined
   449  		if s.TLSListenLimit == 0 {
   450  			s.TLSListenLimit = s.ListenLimit
   451  		}
   452  		// Use http tcp keep alive if https tcp keep alive wasn't defined
   453  		if int64(s.TLSKeepAlive) == 0 {
   454  			s.TLSKeepAlive = s.KeepAlive
   455  		}
   456  		// Use http read timeout if https read timeout wasn't defined
   457  		if int64(s.TLSReadTimeout) == 0 {
   458  			s.TLSReadTimeout = s.ReadTimeout
   459  		}
   460  		// Use http write timeout if https write timeout wasn't defined
   461  		if int64(s.TLSWriteTimeout) == 0 {
   462  			s.TLSWriteTimeout = s.WriteTimeout
   463  		}
   464  	}
   465  
   466  	if s.hasScheme(schemeUnix) {
   467  		domSockListener, err := net.Listen("unix", string(s.SocketPath))
   468  		if err != nil {
   469  			return err
   470  		}
   471  		s.domainSocketL = domSockListener
   472  	}
   473  
   474  	if s.hasScheme(schemeHTTP) {
   475  		listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
   476  		if err != nil {
   477  			return err
   478  		}
   479  
   480  		h, p, err := swag.SplitHostPort(listener.Addr().String())
   481  		if err != nil {
   482  			return err
   483  		}
   484  		s.Host = h
   485  		s.Port = p
   486  		s.httpServerL = listener
   487  	}
   488  
   489  	if s.hasScheme(schemeHTTPS) {
   490  		tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
   491  		if err != nil {
   492  			return err
   493  		}
   494  
   495  		sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
   496  		if err != nil {
   497  			return err
   498  		}
   499  		s.TLSHost = sh
   500  		s.TLSPort = sp
   501  		s.httpsServerL = tlsListener
   502  	}
   503  
   504  	s.hasListeners = true
   505  	return nil
   506  }
   507  
   508  // Shutdown server and clean up resources
   509  func (s *Server) Shutdown() error {
   510  	if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
   511  		close(s.shutdown)
   512  	}
   513  	return nil
   514  }
   515  
   516  func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
   517  	// wg.Done must occur last, after s.api.ServerShutdown()
   518  	// (to preserve old behaviour)
   519  	defer wg.Done()
   520  
   521  	<-s.shutdown
   522  
   523  	servers := *serversPtr
   524  
   525  	ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
   526  	defer cancel()
   527  
   528  	shutdownChan := make(chan bool)
   529  	for i := range servers {
   530  		server := servers[i]
   531  		go func() {
   532  			var success bool
   533  			defer func() {
   534  				shutdownChan <- success
   535  			}()
   536  			if err := server.Shutdown(ctx); err != nil {
   537  				// Error from closing listeners, or context timeout:
   538  				s.Logf("HTTP server Shutdown: %v", err)
   539  			} else {
   540  				success = true
   541  			}
   542  		}()
   543  	}
   544  
   545  	// Wait until all listeners have successfully shut down before calling ServerShutdown
   546  	success := true
   547  	for range servers {
   548  		success = success && <-shutdownChan
   549  	}
   550  	if success {
   551  		s.api.ServerShutdown()
   552  	}
   553  }
   554  
   555  // GetHandler returns a handler useful for testing
   556  func (s *Server) GetHandler() http.Handler {
   557  	return s.handler
   558  }
   559  
   560  // SetHandler allows for setting a http handler on this server
   561  func (s *Server) SetHandler(handler http.Handler) {
   562  	s.handler = handler
   563  }
   564  
   565  // UnixListener returns the domain socket listener
   566  func (s *Server) UnixListener() (net.Listener, error) {
   567  	if !s.hasListeners {
   568  		if err := s.Listen(); err != nil {
   569  			return nil, err
   570  		}
   571  	}
   572  	return s.domainSocketL, nil
   573  }
   574  
   575  // HTTPListener returns the http listener
   576  func (s *Server) HTTPListener() (net.Listener, error) {
   577  	if !s.hasListeners {
   578  		if err := s.Listen(); err != nil {
   579  			return nil, err
   580  		}
   581  	}
   582  	return s.httpServerL, nil
   583  }
   584  
   585  // TLSListener returns the https listener
   586  func (s *Server) TLSListener() (net.Listener, error) {
   587  	if !s.hasListeners {
   588  		if err := s.Listen(); err != nil {
   589  			return nil, err
   590  		}
   591  	}
   592  	return s.httpsServerL, nil
   593  }
   594  
   595  func handleInterrupt(once *sync.Once, s *Server) {
   596  	once.Do(func() {
   597  		for _ = range s.interrupt {
   598  			if s.interrupted {
   599  				s.Logf("Server already shutting down")
   600  				continue
   601  			}
   602  			s.interrupted = true
   603  			s.Logf("Shutting down... ")
   604  			if err := s.Shutdown(); err != nil {
   605  				s.Logf("HTTP server Shutdown: %v", err)
   606  			}
   607  		}
   608  	})
   609  }
   610  
   611  func signalNotify(interrupt chan<- os.Signal) {
   612  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
   613  }