mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-17 23:03:49 +01:00
feat(agentproxy): simplify configuration handling and related header management
This commit is contained in:
76
agent/pkg/agentproxy/config.go
Normal file
76
agent/pkg/agentproxy/config.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package agentproxy
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
route "github.com/yusing/go-proxy/internal/route/types"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
Host string `json:"host,omitempty"` // host or host:port
|
||||
|
||||
route.HTTPConfig
|
||||
}
|
||||
|
||||
func ConfigFromHeaders(h http.Header) (Config, error) {
|
||||
cfg, err := proxyConfigFromHeaders(h)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if cfg.Host == "" {
|
||||
cfg = proxyConfigFromHeadersLegacy(h)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func proxyConfigFromHeadersLegacy(h http.Header) (cfg Config) {
|
||||
cfg.Host = h.Get(HeaderXProxyHost)
|
||||
isHTTPS, _ := strconv.ParseBool(h.Get(HeaderXProxyHTTPS))
|
||||
cfg.NoTLSVerify, _ = strconv.ParseBool(h.Get(HeaderXProxySkipTLSVerify))
|
||||
responseHeaderTimeout, err := strconv.Atoi(h.Get(HeaderXProxyResponseHeaderTimeout))
|
||||
if err != nil {
|
||||
responseHeaderTimeout = 0
|
||||
}
|
||||
cfg.ResponseHeaderTimeout = time.Duration(responseHeaderTimeout) * time.Second
|
||||
|
||||
cfg.Scheme = "http"
|
||||
if isHTTPS {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func proxyConfigFromHeaders(h http.Header) (cfg Config, err error) {
|
||||
cfg.Scheme = h.Get(HeaderXProxyScheme)
|
||||
cfg.Host = h.Get(HeaderXProxyHost)
|
||||
|
||||
cfgBase64 := h.Get(HeaderXProxyConfig)
|
||||
cfgJSON, err := base64.StdEncoding.DecodeString(cfgBase64)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(cfgJSON, &cfg)
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (cfg *Config) SetAgentProxyConfigHeadersLegacy(h http.Header) {
|
||||
h.Set(HeaderXProxyHost, cfg.Host)
|
||||
h.Set(HeaderXProxyHTTPS, strconv.FormatBool(cfg.Scheme == "https"))
|
||||
h.Set(HeaderXProxySkipTLSVerify, strconv.FormatBool(cfg.NoTLSVerify))
|
||||
h.Set(HeaderXProxyResponseHeaderTimeout, strconv.Itoa(int(cfg.ResponseHeaderTimeout.Round(time.Second).Seconds())))
|
||||
}
|
||||
|
||||
func (cfg *Config) SetAgentProxyConfigHeaders(h http.Header) {
|
||||
h.Set(HeaderXProxyHost, cfg.Host)
|
||||
h.Set(HeaderXProxyScheme, string(cfg.Scheme))
|
||||
cfgJSON, _ := json.Marshal(cfg.HTTPConfig)
|
||||
cfgBase64 := base64.StdEncoding.EncodeToString(cfgJSON)
|
||||
h.Set(HeaderXProxyConfig, cfgBase64)
|
||||
}
|
||||
@@ -1,27 +1,14 @@
|
||||
package agentproxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
const (
|
||||
HeaderXProxyScheme = "X-Proxy-Scheme"
|
||||
HeaderXProxyHost = "X-Proxy-Host"
|
||||
HeaderXProxyConfig = "X-Proxy-Config"
|
||||
)
|
||||
|
||||
// deprecated
|
||||
const (
|
||||
HeaderXProxyHost = "X-Proxy-Host"
|
||||
HeaderXProxyHTTPS = "X-Proxy-Https"
|
||||
HeaderXProxySkipTLSVerify = "X-Proxy-Skip-Tls-Verify"
|
||||
HeaderXProxyResponseHeaderTimeout = "X-Proxy-Response-Header-Timeout"
|
||||
)
|
||||
|
||||
type AgentProxyHeaders struct {
|
||||
Host string
|
||||
IsHTTPS bool
|
||||
SkipTLSVerify bool
|
||||
ResponseHeaderTimeout int
|
||||
}
|
||||
|
||||
func SetAgentProxyHeaders(r *http.Request, headers *AgentProxyHeaders) {
|
||||
r.Header.Set(HeaderXProxyHost, headers.Host)
|
||||
r.Header.Set(HeaderXProxyHTTPS, strconv.FormatBool(headers.IsHTTPS))
|
||||
r.Header.Set(HeaderXProxySkipTLSVerify, strconv.FormatBool(headers.SkipTLSVerify))
|
||||
r.Header.Set(HeaderXProxyResponseHeaderTimeout, strconv.Itoa(headers.ResponseHeaderTimeout))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
||||
@@ -24,31 +23,17 @@ func NewTransport() *http.Transport {
|
||||
}
|
||||
|
||||
func ProxyHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
host := r.Header.Get(agentproxy.HeaderXProxyHost)
|
||||
isHTTPS, _ := strconv.ParseBool(r.Header.Get(agentproxy.HeaderXProxyHTTPS))
|
||||
skipTLSVerify, _ := strconv.ParseBool(r.Header.Get(agentproxy.HeaderXProxySkipTLSVerify))
|
||||
responseHeaderTimeout, err := strconv.Atoi(r.Header.Get(agentproxy.HeaderXProxyResponseHeaderTimeout))
|
||||
cfg, err := agentproxy.ConfigFromHeaders(r.Header)
|
||||
if err != nil {
|
||||
responseHeaderTimeout = 0
|
||||
}
|
||||
|
||||
if host == "" {
|
||||
http.Error(w, "missing required headers", http.StatusBadRequest)
|
||||
http.Error(w, fmt.Sprintf("failed to parse agent proxy config: %s", err.Error()), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
scheme := "http"
|
||||
if isHTTPS {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
transport := NewTransport()
|
||||
if skipTLSVerify {
|
||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
if responseHeaderTimeout > 0 {
|
||||
transport.ResponseHeaderTimeout = time.Duration(responseHeaderTimeout) * time.Second
|
||||
transport.TLSClientConfig, err = cfg.BuildTLSConfig(r.URL)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to build TLS client config: %s", err.Error()), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
r.URL.Scheme = ""
|
||||
@@ -58,8 +43,8 @@ func ProxyHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rp := &httputil.ReverseProxy{
|
||||
Director: func(r *http.Request) {
|
||||
r.URL.Scheme = scheme
|
||||
r.URL.Host = host
|
||||
r.URL.Scheme = cfg.Scheme
|
||||
r.URL.Host = cfg.Host
|
||||
},
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/types"
|
||||
"github.com/yusing/go-proxy/internal/watcher/health/monitor"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
)
|
||||
|
||||
type ReveseProxyRoute struct {
|
||||
@@ -43,7 +44,7 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
||||
trans = a.Transport()
|
||||
proxyURL = nettypes.NewURL(agent.HTTPProxyURL)
|
||||
} else {
|
||||
tlsConfig, err := httpConfig.BuildTLSConfig(base.ProxyURL)
|
||||
tlsConfig, err := httpConfig.BuildTLSConfig(&base.ProxyURL.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -68,15 +69,19 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
||||
}
|
||||
|
||||
if a != nil {
|
||||
headers := &agentproxy.AgentProxyHeaders{
|
||||
Host: base.ProxyURL.Host,
|
||||
IsHTTPS: base.ProxyURL.Scheme == "https",
|
||||
SkipTLSVerify: httpConfig.NoTLSVerify,
|
||||
ResponseHeaderTimeout: int(httpConfig.ResponseHeaderTimeout.Seconds()),
|
||||
cfg := agentproxy.Config{
|
||||
Scheme: base.ProxyURL.Scheme,
|
||||
Host: base.ProxyURL.Host,
|
||||
HTTPConfig: httpConfig,
|
||||
}
|
||||
setHeaderFunc := cfg.SetAgentProxyConfigHeaders
|
||||
if !a.Version.IsOlderThan(pkg.Ver(0, 18, 6)) {
|
||||
setHeaderFunc = cfg.SetAgentProxyConfigHeadersLegacy
|
||||
}
|
||||
|
||||
ori := rp.HandlerFunc
|
||||
rp.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
||||
agentproxy.SetAgentProxyHeaders(r, headers)
|
||||
setHeaderFunc(r.Header)
|
||||
ori(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ package route
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
nettypes "github.com/yusing/go-proxy/internal/net/types"
|
||||
)
|
||||
|
||||
type HTTPConfig struct {
|
||||
@@ -25,7 +25,7 @@ type HTTPConfig struct {
|
||||
}
|
||||
|
||||
// BuildTLSConfig creates a TLS configuration based on the HTTP config options.
|
||||
func (cfg *HTTPConfig) BuildTLSConfig(targetURL *nettypes.URL) (*tls.Config, gperr.Error) {
|
||||
func (cfg *HTTPConfig) BuildTLSConfig(targetURL *url.URL) (*tls.Config, gperr.Error) {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
// Handle InsecureSkipVerify (legacy NoTLSVerify option)
|
||||
|
||||
Reference in New Issue
Block a user