server.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. // Code generated by go-swagger; DO NOT EDIT.
  2. package restapi
  3. import (
  4. "context"
  5. "crypto/tls"
  6. "crypto/x509"
  7. "errors"
  8. "fmt"
  9. "io/ioutil"
  10. "log"
  11. "net"
  12. "net/http"
  13. "os"
  14. "os/signal"
  15. "strconv"
  16. "sync"
  17. "sync/atomic"
  18. "syscall"
  19. "time"
  20. "github.com/go-openapi/runtime/flagext"
  21. "github.com/go-openapi/swag"
  22. flags "github.com/jessevdk/go-flags"
  23. "golang.org/x/net/netutil"
  24. "gem-spaas-coding-challenge/restapi/operations"
  25. )
  26. const (
  27. schemeHTTP = "http"
  28. schemeHTTPS = "https"
  29. schemeUnix = "unix"
  30. )
  31. var defaultSchemes []string
  32. func init() {
  33. defaultSchemes = []string{
  34. schemeHTTP,
  35. }
  36. }
  37. // NewServer creates a new api spaas server but does not configure it
  38. func NewServer(api *operations.SpaasAPI) *Server {
  39. s := new(Server)
  40. s.shutdown = make(chan struct{})
  41. s.api = api
  42. s.interrupt = make(chan os.Signal, 1)
  43. return s
  44. }
  45. // ConfigureAPI configures the API and handlers.
  46. func (s *Server) ConfigureAPI() {
  47. if s.api != nil {
  48. s.handler = configureAPI(s.api)
  49. }
  50. }
  51. // ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
  52. func (s *Server) ConfigureFlags() {
  53. if s.api != nil {
  54. configureFlags(s.api)
  55. }
  56. }
  57. // Server for the spaas API
  58. type Server struct {
  59. EnabledListeners []string `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`
  60. CleanupTimeout time.Duration `long:"cleanup-timeout" description:"grace period for which to wait before killing idle connections" default:"10s"`
  61. GracefulTimeout time.Duration `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`
  62. MaxHeaderSize flagext.ByteSize `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"`
  63. SocketPath flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/spaas.sock"`
  64. domainSocketL net.Listener
  65. Host string `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`
  66. Port int `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`
  67. ListenLimit int `long:"listen-limit" description:"limit the number of outstanding requests"`
  68. KeepAlive time.Duration `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"`
  69. ReadTimeout time.Duration `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`
  70. WriteTimeout time.Duration `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`
  71. httpServerL net.Listener
  72. TLSHost string `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`
  73. TLSPort int `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`
  74. TLSCertificate flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`
  75. TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`
  76. TLSCACertificate flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`
  77. TLSListenLimit int `long:"tls-listen-limit" description:"limit the number of outstanding requests"`
  78. TLSKeepAlive time.Duration `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)"`
  79. TLSReadTimeout time.Duration `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`
  80. TLSWriteTimeout time.Duration `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`
  81. httpsServerL net.Listener
  82. api *operations.SpaasAPI
  83. handler http.Handler
  84. hasListeners bool
  85. shutdown chan struct{}
  86. shuttingDown int32
  87. interrupted bool
  88. interrupt chan os.Signal
  89. }
  90. // Logf logs message either via defined user logger or via system one if no user logger is defined.
  91. func (s *Server) Logf(f string, args ...interface{}) {
  92. if s.api != nil && s.api.Logger != nil {
  93. s.api.Logger(f, args...)
  94. } else {
  95. log.Printf(f, args...)
  96. }
  97. }
  98. // Fatalf logs message either via defined user logger or via system one if no user logger is defined.
  99. // Exits with non-zero status after printing
  100. func (s *Server) Fatalf(f string, args ...interface{}) {
  101. if s.api != nil && s.api.Logger != nil {
  102. s.api.Logger(f, args...)
  103. os.Exit(1)
  104. } else {
  105. log.Fatalf(f, args...)
  106. }
  107. }
  108. // SetAPI configures the server with the specified API. Needs to be called before Serve
  109. func (s *Server) SetAPI(api *operations.SpaasAPI) {
  110. if api == nil {
  111. s.api = nil
  112. s.handler = nil
  113. return
  114. }
  115. s.api = api
  116. s.handler = configureAPI(api)
  117. }
  118. func (s *Server) hasScheme(scheme string) bool {
  119. schemes := s.EnabledListeners
  120. if len(schemes) == 0 {
  121. schemes = defaultSchemes
  122. }
  123. for _, v := range schemes {
  124. if v == scheme {
  125. return true
  126. }
  127. }
  128. return false
  129. }
  130. // Serve the api
  131. func (s *Server) Serve() (err error) {
  132. if !s.hasListeners {
  133. if err = s.Listen(); err != nil {
  134. return err
  135. }
  136. }
  137. // set default handler, if none is set
  138. if s.handler == nil {
  139. if s.api == nil {
  140. return errors.New("can't create the default handler, as no api is set")
  141. }
  142. s.SetHandler(s.api.Serve(nil))
  143. }
  144. wg := new(sync.WaitGroup)
  145. once := new(sync.Once)
  146. signalNotify(s.interrupt)
  147. go handleInterrupt(once, s)
  148. servers := []*http.Server{}
  149. if s.hasScheme(schemeUnix) {
  150. domainSocket := new(http.Server)
  151. domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
  152. domainSocket.Handler = s.handler
  153. if int64(s.CleanupTimeout) > 0 {
  154. domainSocket.IdleTimeout = s.CleanupTimeout
  155. }
  156. configureServer(domainSocket, "unix", string(s.SocketPath))
  157. servers = append(servers, domainSocket)
  158. wg.Add(1)
  159. s.Logf("Serving spaas at unix://%s", s.SocketPath)
  160. go func(l net.Listener) {
  161. defer wg.Done()
  162. if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
  163. s.Fatalf("%v", err)
  164. }
  165. s.Logf("Stopped serving spaas at unix://%s", s.SocketPath)
  166. }(s.domainSocketL)
  167. }
  168. if s.hasScheme(schemeHTTP) {
  169. httpServer := new(http.Server)
  170. httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
  171. httpServer.ReadTimeout = s.ReadTimeout
  172. httpServer.WriteTimeout = s.WriteTimeout
  173. httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
  174. if s.ListenLimit > 0 {
  175. s.httpServerL = netutil.LimitListener(s.httpServerL, s.ListenLimit)
  176. }
  177. if int64(s.CleanupTimeout) > 0 {
  178. httpServer.IdleTimeout = s.CleanupTimeout
  179. }
  180. httpServer.Handler = s.handler
  181. configureServer(httpServer, "http", s.httpServerL.Addr().String())
  182. servers = append(servers, httpServer)
  183. wg.Add(1)
  184. s.Logf("Serving spaas at http://%s", s.httpServerL.Addr())
  185. go func(l net.Listener) {
  186. defer wg.Done()
  187. if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
  188. s.Fatalf("%v", err)
  189. }
  190. s.Logf("Stopped serving spaas at http://%s", l.Addr())
  191. }(s.httpServerL)
  192. }
  193. if s.hasScheme(schemeHTTPS) {
  194. httpsServer := new(http.Server)
  195. httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
  196. httpsServer.ReadTimeout = s.TLSReadTimeout
  197. httpsServer.WriteTimeout = s.TLSWriteTimeout
  198. httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
  199. if s.TLSListenLimit > 0 {
  200. s.httpsServerL = netutil.LimitListener(s.httpsServerL, s.TLSListenLimit)
  201. }
  202. if int64(s.CleanupTimeout) > 0 {
  203. httpsServer.IdleTimeout = s.CleanupTimeout
  204. }
  205. httpsServer.Handler = s.handler
  206. // Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
  207. httpsServer.TLSConfig = &tls.Config{
  208. // Causes servers to use Go's default ciphersuite preferences,
  209. // which are tuned to avoid attacks. Does nothing on clients.
  210. PreferServerCipherSuites: true,
  211. // Only use curves which have assembly implementations
  212. // https://github.com/golang/go/tree/master/src/crypto/elliptic
  213. CurvePreferences: []tls.CurveID{tls.CurveP256},
  214. // Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
  215. NextProtos: []string{"h2", "http/1.1"},
  216. // https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
  217. MinVersion: tls.VersionTLS12,
  218. // These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
  219. CipherSuites: []uint16{
  220. tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
  221. tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  222. tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  223. tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  224. tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
  225. tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
  226. },
  227. }
  228. // build standard config from server options
  229. if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
  230. httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
  231. httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(string(s.TLSCertificate), string(s.TLSCertificateKey))
  232. if err != nil {
  233. return err
  234. }
  235. }
  236. if s.TLSCACertificate != "" {
  237. // include specified CA certificate
  238. caCert, caCertErr := ioutil.ReadFile(string(s.TLSCACertificate))
  239. if caCertErr != nil {
  240. return caCertErr
  241. }
  242. caCertPool := x509.NewCertPool()
  243. ok := caCertPool.AppendCertsFromPEM(caCert)
  244. if !ok {
  245. return fmt.Errorf("cannot parse CA certificate")
  246. }
  247. httpsServer.TLSConfig.ClientCAs = caCertPool
  248. httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
  249. }
  250. // call custom TLS configurator
  251. configureTLS(httpsServer.TLSConfig)
  252. if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
  253. // after standard and custom config are passed, this ends up with no certificate
  254. if s.TLSCertificate == "" {
  255. if s.TLSCertificateKey == "" {
  256. s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
  257. }
  258. s.Fatalf("the required flag `--tls-certificate` was not specified")
  259. }
  260. if s.TLSCertificateKey == "" {
  261. s.Fatalf("the required flag `--tls-key` was not specified")
  262. }
  263. // this happens with a wrong custom TLS configurator
  264. s.Fatalf("no certificate was configured for TLS")
  265. }
  266. // must have at least one certificate or panics
  267. httpsServer.TLSConfig.BuildNameToCertificate()
  268. configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
  269. servers = append(servers, httpsServer)
  270. wg.Add(1)
  271. s.Logf("Serving spaas at https://%s", s.httpsServerL.Addr())
  272. go func(l net.Listener) {
  273. defer wg.Done()
  274. if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
  275. s.Fatalf("%v", err)
  276. }
  277. s.Logf("Stopped serving spaas at https://%s", l.Addr())
  278. }(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
  279. }
  280. wg.Add(1)
  281. go s.handleShutdown(wg, &servers)
  282. wg.Wait()
  283. return nil
  284. }
  285. // Listen creates the listeners for the server
  286. func (s *Server) Listen() error {
  287. if s.hasListeners { // already done this
  288. return nil
  289. }
  290. if s.hasScheme(schemeHTTPS) {
  291. // Use http host if https host wasn't defined
  292. if s.TLSHost == "" {
  293. s.TLSHost = s.Host
  294. }
  295. // Use http listen limit if https listen limit wasn't defined
  296. if s.TLSListenLimit == 0 {
  297. s.TLSListenLimit = s.ListenLimit
  298. }
  299. // Use http tcp keep alive if https tcp keep alive wasn't defined
  300. if int64(s.TLSKeepAlive) == 0 {
  301. s.TLSKeepAlive = s.KeepAlive
  302. }
  303. // Use http read timeout if https read timeout wasn't defined
  304. if int64(s.TLSReadTimeout) == 0 {
  305. s.TLSReadTimeout = s.ReadTimeout
  306. }
  307. // Use http write timeout if https write timeout wasn't defined
  308. if int64(s.TLSWriteTimeout) == 0 {
  309. s.TLSWriteTimeout = s.WriteTimeout
  310. }
  311. }
  312. if s.hasScheme(schemeUnix) {
  313. domSockListener, err := net.Listen("unix", string(s.SocketPath))
  314. if err != nil {
  315. return err
  316. }
  317. s.domainSocketL = domSockListener
  318. }
  319. if s.hasScheme(schemeHTTP) {
  320. listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
  321. if err != nil {
  322. return err
  323. }
  324. h, p, err := swag.SplitHostPort(listener.Addr().String())
  325. if err != nil {
  326. return err
  327. }
  328. s.Host = h
  329. s.Port = p
  330. s.httpServerL = listener
  331. }
  332. if s.hasScheme(schemeHTTPS) {
  333. tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
  334. if err != nil {
  335. return err
  336. }
  337. sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
  338. if err != nil {
  339. return err
  340. }
  341. s.TLSHost = sh
  342. s.TLSPort = sp
  343. s.httpsServerL = tlsListener
  344. }
  345. s.hasListeners = true
  346. return nil
  347. }
  348. // Shutdown server and clean up resources
  349. func (s *Server) Shutdown() error {
  350. if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
  351. close(s.shutdown)
  352. }
  353. return nil
  354. }
  355. func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
  356. // wg.Done must occur last, after s.api.ServerShutdown()
  357. // (to preserve old behaviour)
  358. defer wg.Done()
  359. <-s.shutdown
  360. servers := *serversPtr
  361. ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
  362. defer cancel()
  363. // first execute the pre-shutdown hook
  364. s.api.PreServerShutdown()
  365. shutdownChan := make(chan bool)
  366. for i := range servers {
  367. server := servers[i]
  368. go func() {
  369. var success bool
  370. defer func() {
  371. shutdownChan <- success
  372. }()
  373. if err := server.Shutdown(ctx); err != nil {
  374. // Error from closing listeners, or context timeout:
  375. s.Logf("HTTP server Shutdown: %v", err)
  376. } else {
  377. success = true
  378. }
  379. }()
  380. }
  381. // Wait until all listeners have successfully shut down before calling ServerShutdown
  382. success := true
  383. for range servers {
  384. success = success && <-shutdownChan
  385. }
  386. if success {
  387. s.api.ServerShutdown()
  388. }
  389. }
  390. // GetHandler returns a handler useful for testing
  391. func (s *Server) GetHandler() http.Handler {
  392. return s.handler
  393. }
  394. // SetHandler allows for setting a http handler on this server
  395. func (s *Server) SetHandler(handler http.Handler) {
  396. s.handler = handler
  397. }
  398. // UnixListener returns the domain socket listener
  399. func (s *Server) UnixListener() (net.Listener, error) {
  400. if !s.hasListeners {
  401. if err := s.Listen(); err != nil {
  402. return nil, err
  403. }
  404. }
  405. return s.domainSocketL, nil
  406. }
  407. // HTTPListener returns the http listener
  408. func (s *Server) HTTPListener() (net.Listener, error) {
  409. if !s.hasListeners {
  410. if err := s.Listen(); err != nil {
  411. return nil, err
  412. }
  413. }
  414. return s.httpServerL, nil
  415. }
  416. // TLSListener returns the https listener
  417. func (s *Server) TLSListener() (net.Listener, error) {
  418. if !s.hasListeners {
  419. if err := s.Listen(); err != nil {
  420. return nil, err
  421. }
  422. }
  423. return s.httpsServerL, nil
  424. }
  425. func handleInterrupt(once *sync.Once, s *Server) {
  426. once.Do(func() {
  427. for range s.interrupt {
  428. if s.interrupted {
  429. s.Logf("Server already shutting down")
  430. continue
  431. }
  432. s.interrupted = true
  433. s.Logf("Shutting down... ")
  434. if err := s.Shutdown(); err != nil {
  435. s.Logf("HTTP server Shutdown: %v", err)
  436. }
  437. }
  438. })
  439. }
  440. func signalNotify(interrupt chan<- os.Signal) {
  441. signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
  442. }