feat: add precise diagnostics and optional client copy logging controls
This commit is contained in:
@@ -2,7 +2,6 @@ package httpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -10,6 +9,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/go-omni/internal/configdiag"
|
||||
)
|
||||
|
||||
// ProxyMode controls the owned transport's proxy selection. Empty preserves
|
||||
@@ -66,17 +67,23 @@ func normalizeConfig(cfg Config) (Config, error) {
|
||||
{"responseHeaderTimeout", cfg.ResponseHeaderTimeout}, {"expectContinueTimeout", cfg.ExpectContinueTimeout}, {"idleConnTimeout", cfg.IdleConnTimeout},
|
||||
} {
|
||||
if field.value < 0 {
|
||||
return Config{}, fmt.Errorf("httpc: %s must not be negative", field.name)
|
||||
return Config{}, configdiag.New(field.name, "must be nonnegative")
|
||||
}
|
||||
}
|
||||
if cfg.MaxRetries < 0 || cfg.MaxRetries > 5 {
|
||||
return Config{}, errors.New("httpc: maxRetries must be 0..5")
|
||||
return Config{}, configdiag.New("maxRetries", "must be between 0 and 5")
|
||||
}
|
||||
if cfg.MaxConnsPerHost < 0 || cfg.MaxConnsPerHost > 65536 || cfg.MaxIdleConnsPerHost < 0 || cfg.MaxIdleConnsPerHost > 65536 || cfg.MaxIdleConns < 0 || cfg.MaxIdleConns > 131072 {
|
||||
return Config{}, errors.New("httpc: invalid connection pool limits")
|
||||
for _, f := range []struct {
|
||||
name string
|
||||
value, max int
|
||||
}{{"maxConnsPerHost", cfg.MaxConnsPerHost, 65536}, {"maxIdleConnsPerHost", cfg.MaxIdleConnsPerHost, 65536}, {"maxIdleConns", cfg.MaxIdleConns, 131072}} {
|
||||
if f.value < 0 || f.value > f.max {
|
||||
return Config{}, configdiag.New(f.name, "must be between 0 and "+strconv.Itoa(f.max))
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.MaxResponseBytes < 0 || cfg.MaxResponseBytes > maxResponseBytes {
|
||||
return Config{}, errors.New("httpc: maxResponseBytes must be 0..1 GiB")
|
||||
return Config{}, configdiag.New("maxResponseBytes", "must be between 0 and 1 GiB")
|
||||
}
|
||||
if _, err := proxyFunction(cfg.Proxy); err != nil {
|
||||
return Config{}, err
|
||||
@@ -86,11 +93,11 @@ func normalizeConfig(cfg Config) (Config, error) {
|
||||
switch value.Kind() {
|
||||
case reflect.Pointer, reflect.Map, reflect.Func, reflect.Slice, reflect.Interface, reflect.Chan:
|
||||
if value.IsNil() {
|
||||
return Config{}, errors.New("httpc: nil Transport")
|
||||
return Config{}, configdiag.New("transport", "must not be a typed nil")
|
||||
}
|
||||
}
|
||||
if cfg.hasTransportOptions() {
|
||||
return Config{}, errors.New("httpc: Transport cannot be combined with proxy, dial, TLS or connection pool options; configure the borrowed transport directly")
|
||||
return Config{}, configdiag.New("transport", "cannot be combined with proxy, dial, TLS or connection pool options; configure the borrowed transport directly")
|
||||
}
|
||||
}
|
||||
if cfg.Timeout == 0 {
|
||||
@@ -103,7 +110,7 @@ func normalizeConfig(cfg Config) (Config, error) {
|
||||
cfg.MaxBackoff = 2 * time.Second
|
||||
}
|
||||
if cfg.Backoff > cfg.MaxBackoff {
|
||||
return Config{}, errors.New("httpc: backoff exceeds maxBackoff")
|
||||
return Config{}, configdiag.New("backoff", "must not exceed maxBackoff")
|
||||
}
|
||||
if cfg.MaxConnsPerHost == 0 {
|
||||
cfg.MaxConnsPerHost = 64
|
||||
@@ -124,7 +131,7 @@ func (c Config) hasTransportOptions() bool {
|
||||
}
|
||||
func proxyFunction(c ProxyConfig) (func(*http.Request) (*url.URL, error), error) {
|
||||
if c.Mode != ProxyURL && c.URL != "" {
|
||||
return nil, errors.New("httpc: proxy URL requires mode url")
|
||||
return nil, configdiag.New("proxy.mode", "must be url when a URL is configured")
|
||||
}
|
||||
switch c.Mode {
|
||||
case "":
|
||||
@@ -136,27 +143,27 @@ func proxyFunction(c ProxyConfig) (func(*http.Request) (*url.URL, error), error)
|
||||
case ProxyURL:
|
||||
u, err := url.Parse(c.URL)
|
||||
if err != nil || u == nil || u.Hostname() == "" || u.Opaque != "" || u.RawQuery != "" || u.ForceQuery || u.Fragment != "" || (u.Path != "" && u.Path != "/") {
|
||||
return nil, errors.New("httpc: proxy URL must be an absolute proxy origin without path, query or fragment")
|
||||
return nil, configdiag.New("proxy.url", "must be an absolute proxy origin without path, query or fragment")
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "http", "https", "socks5", "socks5h":
|
||||
default:
|
||||
return nil, errors.New("httpc: proxy scheme must be http, https, socks5 or socks5h")
|
||||
return nil, configdiag.New("proxy.url", "scheme must be http, https, socks5 or socks5h")
|
||||
}
|
||||
if strings.HasSuffix(u.Host, ":") {
|
||||
return nil, errors.New("httpc: proxy port must be 1..65535")
|
||||
return nil, configdiag.New("proxy.url", "port must be between 1 and 65535")
|
||||
}
|
||||
if port := u.Port(); port != "" {
|
||||
n, e := strconv.Atoi(port)
|
||||
if e != nil || n < 1 || n > 65535 {
|
||||
return nil, errors.New("httpc: proxy port must be 1..65535")
|
||||
return nil, configdiag.New("proxy.url", "port must be between 1 and 65535")
|
||||
}
|
||||
}
|
||||
u.Path = ""
|
||||
u.RawPath = ""
|
||||
return http.ProxyURL(u), nil
|
||||
default:
|
||||
return nil, errors.New("httpc: proxy mode must be environment, direct or url")
|
||||
return nil, configdiag.New("proxy.mode", "must be environment, direct or url")
|
||||
}
|
||||
}
|
||||
func ownedTransport(cfg Config) (*http.Transport, error) {
|
||||
|
||||
Reference in New Issue
Block a user