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 }