feat: release v0.27 unified HTTP limits and safe request shutdown

This commit is contained in:
2026-09-29 23:24:19 +08:00
parent 859f1851b1
commit 3b00bb55d1
42 changed files with 1191 additions and 70 deletions

View File

@@ -3,17 +3,28 @@ package config
import (
"log"
"time"
"git.yuntuo.hk/k2safe/go-omni/internal/httplimits"
)
// HTTPConfig controls built-in HTTP servers. Positive values override the
// selected transport's defaults; zero keeps its existing behavior. Timeouts
// follow that transport's semantics, not a handler execution deadline.
// 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:"-"`
}
@@ -27,6 +38,7 @@ func (c HTTPConfig) Validate() error {
{"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"}
@@ -35,11 +47,22 @@ func (c HTTPConfig) Validate() error {
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 the built-in server's HTTP options. RunWith uses a
// caller-owned Runner and does not apply these options to that runner.
// 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 }
}