package config import ( "log" "time" "git.yuntuo.hk/k2safe/go-omni/internal/httplimits" ) // HTTPConfig controls HTTP serving. Network timeouts follow the selected // transport's semantics, not a handler execution deadline. Body limits and // shutdown cancellation grace also apply to App used with an external server. type HTTPConfig struct { ReadHeaderTimeout time.Duration `json:"readHeaderTimeout"` ReadTimeout time.Duration `json:"readTimeout"` WriteTimeout time.Duration `json:"writeTimeout"` IdleTimeout time.Duration `json:"idleTimeout"` MaxHeaderBytes int `json:"maxHeaderBytes"` // DefaultMaxBodyBytes applies to App routes without an explicit limit. // Zero uses 8 MiB, or the hard limit if smaller. Route limits may override it. DefaultMaxBodyBytes int64 `json:"defaultMaxBodyBytes"` // MaxBodyBytes is an optional service hard limit. Zero adds no hard limit // below the framework's supported maximum of 1 TiB. MaxBodyBytes int64 `json:"maxBodyBytes"` // ShutdownCancelTimeout bounds the wait for handlers after cancellation. // Zero uses 5s. Resources are retained if handlers have not returned. ShutdownCancelTimeout time.Duration `json:"shutdownCancelTimeout"` // ErrorLog is a Go-only hook for the nethttp server's internal diagnostics. ErrorLog *log.Logger `json:"-"` } func (c HTTPConfig) Validate() error { for _, field := range []struct { name string value time.Duration }{ {"readHeaderTimeout", c.ReadHeaderTimeout}, {"readTimeout", c.ReadTimeout}, {"writeTimeout", c.WriteTimeout}, {"idleTimeout", c.IdleTimeout}, {"shutdownCancelTimeout", c.ShutdownCancelTimeout}, } { if field.value < 0 { return &ConfigError{Field: "http." + field.name, Message: "must be nonnegative"} } } if c.MaxHeaderBytes < 0 { return &ConfigError{Field: "http.maxHeaderBytes", Message: "must be nonnegative"} } for _, field := range []struct { name string value int64 }{{"defaultMaxBodyBytes", c.DefaultMaxBodyBytes}, {"maxBodyBytes", c.MaxBodyBytes}} { if field.value < 0 || field.value > httplimits.MaxBodyBytes { return &ConfigError{Field: "http." + field.name, Message: "must be 0..1 TiB (bytes)"} } } if c.MaxBodyBytes > 0 && c.DefaultMaxBodyBytes > c.MaxBodyBytes { return &ConfigError{Field: "http.defaultMaxBodyBytes", Message: "must not exceed http.maxBodyBytes"} } return nil } // WithHTTPConfig sets HTTP options. RunWith leaves network configuration to the // caller-owned Runner, but App body limits and cancellation grace still apply. func WithHTTPConfig(settings HTTPConfig) Option { return func(cfg *Config) { cfg.HTTP = settings } }