Repository: labstack/echo
File: middleware/proxy.go (Go)

Code before:

	commonBalancer struct {
		targets []*ProxyTarget
		mutex   sync.Mutex
	}

	// RandomBalancer implements a random load balancing technique.
	randomBalancer struct {
		commonBalancer
		random *rand.Rand
	}

	// RoundRobinBalancer implements a round-robin load balancing technique.
	roundRobinBalancer struct {
		commonBalancer
		// tracking the index on `targets` slice for the next `*ProxyTarget` to be used
		i int
	}
)

var (
	// DefaultProxyConfig is the default Proxy middleware config.
	DefaultProxyConfig = ProxyConfig{
		Skipper:     DefaultSkipper,
		ContextKey:  "target",
		RetryFilter: DefaultProxyRetryFilter,
	}
)

func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		in, _, err := c.Response().Hijack()
		if err != nil {
			c.Set("_error", fmt.Sprintf("proxy raw, hijack error=%v, url=%s", t.URL, err))
			return
		}
		defer in.Close()

		out, err := net.Dial("tcp", t.URL.Host)
		if err != nil {
			c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err)))
			return
		}
		defer out.Close()

		// Write header
		err = r.Write(out)
		if err != nil {
			c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err)))
			return
		}

Review comment (bug):
these `Default*Config` public global structs are not very good things as you can mutate them anywhere, therefore causing hard to find bugs.

going with in middleware func is more bullet-proof
```go
	if config.ErrorHandler == nil {
		config.ErrorHandler = func(err error, c echo.Context) error {
			var httpErr *echo.HTTPError
			if errors.As(err, &httpErr) && httpErr.Code == http.StatusBadGateway {
				return nil
			}
			return err
		}
	}
```

Code after:
		RemoveTarget(string) bool
		Next(echo.Context) *ProxyTarget
	}

	// TargetProvider defines an interface that gives the opportunity for balancer
	// to return custom errors when selecting target.
	TargetProvider interface {
		NextTarget(echo.Context) (*ProxyTarget, error)
	}

	commonBalancer struct {
		targets []*ProxyTarget
		mutex   sync.Mutex
	}

	// RandomBalancer implements a random load balancing technique.
	randomBalancer struct {
		commonBalancer
		random *rand.Rand
	}

	// RoundRobinBalancer implements a round-robin load balancing technique.
	roundRobinBalancer struct {
		commonBalancer
		// tracking the index on `targets` slice for the next `*ProxyTarget` to be used
		i int
	}
)

var (
	// DefaultProxyConfig is the default Proxy middleware config.
	DefaultProxyConfig = ProxyConfig{
		Skipper:    DefaultSkipper,
		ContextKey: "target",
	}
)

func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		in, _, err := c.Response().Hijack()
		if err != nil {
			c.Set("_error", fmt.Errorf("proxy raw, hijack error=%w, url=%s", err, t.URL))
			return
		}
		defer in.Close()

		out, err := net.Dial("tcp", t.URL.Host)
		if err != nil {
			c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", err, t.URL)))
			return
		}