diff --git a/ca/ca.go b/ca/ca.go index 7baf2419..ca6b7153 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -41,6 +41,7 @@ type options struct { configFile string linkedCAToken string quiet bool + httpTimeout time.Duration password []byte issuerPassword []byte sshHostPassword []byte @@ -118,6 +119,13 @@ func WithQuiet(quiet bool) Option { } } +// WithHTTPTimeout sets the http timeout flag. +func WithHTTPTimeout(httpTimeout time.Duration) Option { + return func(o *options) { + o.httpTimeout = httpTimeout + } +} + // CA is the type used to build the complete certificate authority. It builds // the HTTP server, set ups the middlewares and the HTTP handlers. type CA struct { @@ -300,7 +308,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { // Create context with all the necessary values. baseContext := buildContext(auth, scepAuthority, acmeDB, acmeLinker) - ca.srv = server.New(cfg.Address, handler, tlsConfig) + ca.srv = server.New(cfg.Address, handler, tlsConfig, ca.opts.httpTimeout) ca.srv.BaseContext = func(net.Listener) context.Context { return baseContext } @@ -312,7 +320,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { // http.Servers handling the HTTP and HTTPS handler? The latter // will probably introduce more complexity in terms of graceful // reload. - ca.insecureSrv = server.New(cfg.InsecureAddress, insecureHandler, nil) + ca.insecureSrv = server.New(cfg.InsecureAddress, insecureHandler, nil, ca.opts.httpTimeout) ca.insecureSrv.BaseContext = func(net.Listener) context.Context { return baseContext } diff --git a/commands/app.go b/commands/app.go index e5c6ea1e..14c2e03d 100644 --- a/commands/app.go +++ b/commands/app.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strconv" "strings" + "time" "unicode" "github.com/pkg/errors" @@ -73,6 +74,13 @@ certificate issuer private key used in the RA mode.`, Usage: "the of the authority's context.", EnvVar: "STEP_CA_CONTEXT", }, + cli.DurationFlag{ + Name: "http-timeout", + Usage: "the (shared) duration for HTTP timeouts (experimental).", + EnvVar: "STEP_CA_HTTP_TIMEOUT", + Value: 15 * time.Second, + Hidden: true, + }, cli.IntFlag{ Name: "acme-http-port", Usage: `the used on http-01 challenges. It can be changed for testing purposes. @@ -105,6 +113,7 @@ func appAction(ctx *cli.Context) error { resolver := ctx.String("resolver") token := ctx.String("token") quiet := ctx.Bool("quiet") + httpTimeout := ctx.Duration("http-timeout") if ctx.NArg() > 1 { return errs.TooManyArguments(ctx) @@ -251,7 +260,8 @@ To get a linked authority token: ca.WithSSHUserPassword(sshUserPassword), ca.WithIssuerPassword(issuerPassword), ca.WithLinkedCAToken(token), - ca.WithQuiet(quiet)) + ca.WithQuiet(quiet), + ca.WithHTTPTimeout(httpTimeout)) if err != nil { fatal(err) } diff --git a/server/server.go b/server/server.go index e12c792c..7e1b87b9 100644 --- a/server/server.go +++ b/server/server.go @@ -27,25 +27,25 @@ type Server struct { // New creates a new HTTP/HTTPS server configured with the passed // address, http.Handler and tls.Config. -func New(addr string, handler http.Handler, tlsConfig *tls.Config) *Server { +func New(addr string, handler http.Handler, tlsConfig *tls.Config, httpTimeout time.Duration) *Server { return &Server{ reloadCh: make(chan net.Listener), shutdownCh: make(chan struct{}), - Server: newHTTPServer(addr, handler, tlsConfig), + Server: newHTTPServer(addr, handler, tlsConfig, httpTimeout), } } // newHTTPServer creates a new http.Server with the TCP address, handler and // tls.Config. -func newHTTPServer(addr string, handler http.Handler, tlsConfig *tls.Config) *http.Server { +func newHTTPServer(addr string, handler http.Handler, tlsConfig *tls.Config, httpTimeout time.Duration) *http.Server { return &http.Server{ Addr: addr, Handler: handler, TLSConfig: tlsConfig, - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, - ReadHeaderTimeout: 15 * time.Second, - IdleTimeout: 15 * time.Second, + WriteTimeout: httpTimeout, + ReadTimeout: httpTimeout, + ReadHeaderTimeout: httpTimeout, + IdleTimeout: httpTimeout, ErrorLog: log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Llongfile), } }