Skip to content

Commit

Permalink
Proxy: Better errors + remote custom TLS (labstack#1197)
Browse files Browse the repository at this point in the history
Proxy will be more verbose on errors + possibility to configure custom transport (example: for custom TLS certificates)
  • Loading branch information
blaubaer authored and vishr committed Oct 13, 2018
1 parent fcdf096 commit bc37a3a
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 7 deletions.
1 change: 1 addition & 0 deletions echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ var (
ErrBadGateway = NewHTTPError(http.StatusBadGateway)
ErrInternalServerError = NewHTTPError(http.StatusInternalServerError)
ErrRequestTimeout = NewHTTPError(http.StatusRequestTimeout)
ErrServiceUnavailable = NewHTTPError(http.StatusServiceUnavailable)
ErrValidatorNotRegistered = errors.New("validator not registered")
ErrRendererNotRegistered = errors.New("renderer not registered")
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
Expand Down
13 changes: 6 additions & 7 deletions middleware/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"math/rand"
"net"
"net/http"
"net/http/httputil"
"net/url"
"regexp"
"strings"
Expand Down Expand Up @@ -38,10 +37,14 @@ type (
// "/users/*/orders/*": "/user/$1/order/$2",
Rewrite map[string]string

// Context key to store selected ProxyTarget into context.
// Context key to store selected ProxyTarget into context.
// Optional. Default value "target".
ContextKey string

// To customize the transport to remote.
// Examples: If custom TLS certificates are required.
Transport http.RoundTripper

rewriteRegex map[*regexp.Regexp]string
}

Expand Down Expand Up @@ -85,10 +88,6 @@ var (
}
)

func proxyHTTP(t *ProxyTarget) http.Handler {
return httputil.NewSingleHostReverseProxy(t.URL)
}

func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
in, _, err := c.Response().Hijack()
Expand Down Expand Up @@ -250,7 +249,7 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
proxyRaw(tgt, c).ServeHTTP(res, req)
case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
default:
proxyHTTP(tgt).ServeHTTP(res, req)
proxyHTTP(tgt, c, config).ServeHTTP(res, req)
}

return
Expand Down
24 changes: 24 additions & 0 deletions middleware/proxy_1_11.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// +build go1.11

package middleware

import (
"fmt"
"github.com/labstack/echo"
"net/http"
"net/http/httputil"
)

func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
proxy := httputil.NewSingleHostReverseProxy(tgt.URL)
proxy.ErrorHandler = func(resp http.ResponseWriter, req *http.Request, err error) {
descr := tgt.URL.String()
if tgt.Name != "" {
descr = fmt.Sprintf("%s(%s)", tgt.Name, tgt.URL.String())
}
c.Logger().Errorf("remote %s unreachable, could not forward: %v", descr, err)
c.Error(echo.ErrServiceUnavailable)
}
proxy.Transport = config.Transport
return proxy
}
13 changes: 13 additions & 0 deletions middleware/proxy_1_11_n.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// +build !go1.11

package middleware

import (
"github.com/labstack/echo"
"net/http"
"net/http/httputil"
)

func proxyHTTP(t *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
return httputil.NewSingleHostReverseProxy(t.URL)
}
52 changes: 52 additions & 0 deletions middleware/proxy_1_11_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// +build go1.11

package middleware

import (
"github.com/labstack/echo"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"net/url"
"testing"
)

func TestProxy_1_11(t *testing.T) {
// Setup
url1, _ := url.Parse("http://127.0.0.1:27121")
url2, _ := url.Parse("http://127.0.0.1:27122")

targets := []*ProxyTarget{
{
Name: "target 1",
URL: url1,
},
{
Name: "target 2",
URL: url2,
},
}
rb := NewRandomBalancer(nil)
// must add targets:
for _, target := range targets {
assert.True(t, rb.AddTarget(target))
}

// must ignore duplicates:
for _, target := range targets {
assert.False(t, rb.AddTarget(target))
}

// Random
e := echo.New()
e.Use(Proxy(rb))
req := httptest.NewRequest(echo.GET, "/", nil)
rec := newCloseNotifyRecorder()

// Remote unreachable
rec = newCloseNotifyRecorder()
req.URL.Path = "/api/users"
e.ServeHTTP(rec, req)
assert.Equal(t, "/api/users", req.URL.Path)
assert.Equal(t, http.StatusServiceUnavailable, rec.Code)
}
1 change: 1 addition & 0 deletions middleware/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ func TestProxy(t *testing.T) {
req.URL.Path = "/users/jack/orders/1"
e.ServeHTTP(rec, req)
assert.Equal(t, "/user/jack/order/1", req.URL.Path)
assert.Equal(t, http.StatusOK, rec.Code)

// ProxyTarget is set in context
contextObserver := func(next echo.HandlerFunc) echo.HandlerFunc {
Expand Down

0 comments on commit bc37a3a

Please sign in to comment.