diff --git a/cli/ocspserve/ocspserve.go b/cli/ocspserve/ocspserve.go index 3d984ea05..cf4d8e718 100644 --- a/cli/ocspserve/ocspserve.go +++ b/cli/ocspserve/ocspserve.go @@ -2,10 +2,14 @@ package ocspserve import ( + "context" "errors" "net" "net/http" + "os" + "os/signal" "strconv" + "time" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/log" @@ -56,7 +60,42 @@ func ocspServerMain(args []string, c cli.Config) error { addr := net.JoinHostPort(c.Address, strconv.Itoa(c.Port)) log.Info("Now listening on ", addr) - return http.ListenAndServe(addr, nil) + + server := &http.Server{Addr: addr, Handler: nil} + + //gracefull shutdown on SIGTERM or SIGINT + //see issue https://github.com/golang/go/issues/19541 + //see https://play.golang.org/p/LdXUYyzDxY + exit := make(chan struct{}) + quit := make(chan os.Signal, 1) //use buffered version due to vet false positive . Could be unbuffered in go@1.20 + signal.Notify(quit, os.Interrupt) + + go func() { + defer func() { + if err := recover(); err != nil { + log.Infof("recovered: %+v\n", err) + } + }() + <-quit + d := time.Now().Add(60 * time.Second) // deadline 5s max + ctx, cancel := context.WithDeadline(context.Background(), d) + + defer cancel() + + log.Info("Shutting down server...") + if err := server.Shutdown(ctx); err != nil { + log.Fatalf("could not shutdown: %v", err) + } + close(exit) + }() + err := server.ListenAndServe() + <-exit + + if err != http.ErrServerClosed { + log.Fatalf("listen: %s\n", err) + } + + return err } // Command assembles the definition of Command 'ocspserve'