feat: release v0.27 unified HTTP limits and safe request shutdown
This commit is contained in:
63
app/body.go
63
app/body.go
@@ -1,11 +1,68 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"git.yuntuo.hk/k2safe/go-omni/response"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.yuntuo.hk/k2safe/go-omni/config"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"git.yuntuo.hk/k2safe/go-omni/internal/httplimits"
|
||||
"git.yuntuo.hk/k2safe/go-omni/response"
|
||||
)
|
||||
|
||||
type routeBodyLimit struct {
|
||||
method, path string
|
||||
maxBytes int64
|
||||
}
|
||||
|
||||
func (a *App) hardBodyLimit() int64 {
|
||||
if a.config.HTTP.MaxBodyBytes > 0 {
|
||||
return a.config.HTTP.MaxBodyBytes
|
||||
}
|
||||
return httplimits.MaxBodyBytes
|
||||
}
|
||||
|
||||
func (a *App) defaultBodyLimit() int64 {
|
||||
limit := a.config.HTTP.DefaultMaxBodyBytes
|
||||
if limit <= 0 {
|
||||
limit = httplimits.DefaultBodyBytes
|
||||
}
|
||||
if limit > a.hardBodyLimit() {
|
||||
limit = a.hardBodyLimit()
|
||||
}
|
||||
// Invalid configuration is rejected at startup or the first external request.
|
||||
if limit > httplimits.MaxBodyBytes {
|
||||
limit = httplimits.MaxBodyBytes
|
||||
}
|
||||
return limit
|
||||
}
|
||||
|
||||
// ValidateHTTP checks HTTP settings and registered route body limits without
|
||||
// opening a listener. Call after registration when hosting App/Engine externally.
|
||||
// Built-in serving entry points and RunWith perform this check automatically.
|
||||
func (a *App) ValidateHTTP() error {
|
||||
if err := a.config.HTTP.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, route := range a.bodyLimits {
|
||||
if route.maxBytes > a.hardBodyLimit() {
|
||||
return &config.ConfigError{Field: "http.maxBodyBytes", Message: fmt.Sprintf("route %s %s maxBytes=%d exceeds service hard limit=%d; raise http.maxBodyBytes or lower the route limit", route.method, route.path, route.maxBytes, a.hardBodyLimit())}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func joinRoutePath(prefix, path string) string {
|
||||
if path == "" {
|
||||
if prefix == "" {
|
||||
return "/"
|
||||
}
|
||||
return prefix
|
||||
}
|
||||
return strings.TrimSuffix(prefix, "/") + "/" + strings.TrimPrefix(path, "/")
|
||||
}
|
||||
|
||||
func (a *App) bodyHandler(maxBytes int64, encoder response.Encoder, handler httpx.Handler, middleware ...httpx.Middleware) http.Handler {
|
||||
checked := httpx.LimitBody(maxBytes)(handler)
|
||||
if encoder == nil {
|
||||
@@ -25,8 +82,10 @@ func (a *App) bodyHandler(maxBytes int64, encoder response.Encoder, handler http
|
||||
// the response policy, including auth failures and parameter errors.
|
||||
func (a *App) HandleWithBodyLimit(method, path string, maxBytes int64, encoder response.Encoder, handler httpx.Handler, middleware ...httpx.Middleware) {
|
||||
a.router.Handle(method, path, a.bodyHandler(maxBytes, encoder, handler, middleware...))
|
||||
a.bodyLimits = append(a.bodyLimits, routeBodyLimit{method, path, maxBytes})
|
||||
}
|
||||
func (g *RouterGroup) HandleWithBodyLimit(method, path string, maxBytes int64, encoder response.Encoder, handler httpx.Handler, middleware ...httpx.Middleware) {
|
||||
combined := append(append([]httpx.Middleware{}, g.middlewares...), middleware...)
|
||||
g.group.Handle(method, path, g.app.bodyHandler(maxBytes, encoder, handler, combined...))
|
||||
g.app.bodyLimits = append(g.app.bodyLimits, routeBodyLimit{method, joinRoutePath(g.prefix, path), maxBytes})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user