@@ -113,6 +113,22 @@ func (s *Server) UnmarshalYAML(unmarshal func(interface{}) error) error {
113113 return checkOverflow (s .XXX , "server" )
114114}
115115
116+ // TimeoutCfg contains configurable http.Server timeouts
117+ type TimeoutCfg struct {
118+ // ReadTimeout is the maximum duration for reading the entire
119+ // request, including the body.
120+ // Default value is 1m
121+ ReadTimeout Duration `yaml:"read_timeout,omitempty"`
122+
123+ // WriteTimeout is the maximum duration before timing out writes of the response.
124+ // Default is largest MaxExecutionTime + MaxQueueTime value from Users or Clusters
125+ WriteTimeout Duration `yaml:"write_timeout,omitempty"`
126+
127+ // IdleTimeout is the maximum amount of time to wait for the next request.
128+ // Default is 10m
129+ IdleTimeout Duration `yaml:"idle_timeout,omitempty"`
130+ }
131+
116132// HTTP describes configuration for server to listen HTTP connections
117133type HTTP struct {
118134 // TCP address to listen to for http
@@ -128,6 +144,8 @@ type HTTP struct {
128144 // Whether to support Autocert handler for http-01 challenge
129145 ForceAutocertHandler bool
130146
147+ TimeoutCfg `yaml:",inline"`
148+
131149 // Catches all undefined fields and must be empty after parsing.
132150 XXX map [string ]interface {} `yaml:",inline"`
133151}
@@ -138,6 +156,12 @@ func (c *HTTP) UnmarshalYAML(unmarshal func(interface{}) error) error {
138156 if err := unmarshal ((* plain )(c )); err != nil {
139157 return err
140158 }
159+ if c .ReadTimeout == 0 {
160+ c .ReadTimeout = Duration (time .Minute )
161+ }
162+ if c .IdleTimeout == 0 {
163+ c .IdleTimeout = Duration (time .Minute * 10 )
164+ }
141165 return checkOverflow (c .XXX , "http" )
142166}
143167
@@ -162,6 +186,8 @@ type HTTPS struct {
162186 // if omitted or zero - no limits would be applied
163187 AllowedNetworks Networks `yaml:"-"`
164188
189+ TimeoutCfg `yaml:",inline"`
190+
165191 // Catches all undefined fields and must be empty after parsing.
166192 XXX map [string ]interface {} `yaml:",inline"`
167193}
@@ -172,6 +198,12 @@ func (c *HTTPS) UnmarshalYAML(unmarshal func(interface{}) error) error {
172198 if err := unmarshal ((* plain )(c )); err != nil {
173199 return err
174200 }
201+ if c .ReadTimeout == 0 {
202+ c .ReadTimeout = Duration (time .Minute )
203+ }
204+ if c .IdleTimeout == 0 {
205+ c .IdleTimeout = Duration (time .Minute * 10 )
206+ }
175207 if len (c .ListenAddr ) == 0 {
176208 c .ListenAddr = ":443"
177209 }
@@ -646,21 +678,45 @@ func LoadFile(filename string) (*Config, error) {
646678 if cfg .Server .Metrics .AllowedNetworks , err = cfg .groupToNetwork (cfg .Server .Metrics .NetworksOrGroups ); err != nil {
647679 return nil , err
648680 }
681+ var maxResponseTime time.Duration
649682 for i := range cfg .Clusters {
650683 c := & cfg .Clusters [i ]
651684 for j := range c .ClusterUsers {
652685 u := & c .ClusterUsers [j ]
686+ cud := time .Duration (u .MaxExecutionTime + u .MaxQueueTime )
687+ if cud > maxResponseTime {
688+ maxResponseTime = cud
689+ }
653690 if u .AllowedNetworks , err = cfg .groupToNetwork (u .NetworksOrGroups ); err != nil {
654691 return nil , err
655692 }
656693 }
657694 }
658695 for i := range cfg .Users {
659696 u := & cfg .Users [i ]
697+ ud := time .Duration (u .MaxExecutionTime + u .MaxQueueTime )
698+ if ud > maxResponseTime {
699+ maxResponseTime = ud
700+ }
660701 if u .AllowedNetworks , err = cfg .groupToNetwork (u .NetworksOrGroups ); err != nil {
661702 return nil , err
662703 }
663704 }
705+
706+ if maxResponseTime < 0 {
707+ maxResponseTime = 0
708+ }
709+ // Give an additional minute for the maximum response time,
710+ // so the response body may be sent to the requester.
711+ maxResponseTime += time .Minute
712+ if len (cfg .Server .HTTP .ListenAddr ) > 0 && cfg .Server .HTTP .WriteTimeout == 0 {
713+ cfg .Server .HTTP .WriteTimeout = Duration (maxResponseTime )
714+ }
715+
716+ if len (cfg .Server .HTTPS .ListenAddr ) > 0 && cfg .Server .HTTPS .WriteTimeout == 0 {
717+ cfg .Server .HTTPS .WriteTimeout = Duration (maxResponseTime )
718+ }
719+
664720 if err := cfg .checkVulnerabilities (); err != nil {
665721 return nil , fmt .Errorf ("security breach: %s\n Set option `hack_me_please=true` to disable security errors" , err )
666722 }
0 commit comments