Commit 82b04922 authored by Matthew Holt's avatar Matthew Holt

proxy: Add basic proxying test and InsecureSkipVerify transport test

parent fae612d5
...@@ -57,6 +57,10 @@ func (uh *UpstreamHost) Down() bool { ...@@ -57,6 +57,10 @@ func (uh *UpstreamHost) Down() bool {
return uh.CheckDown(uh) return uh.CheckDown(uh)
} }
// tryDuration is how long to try upstream hosts; failures result in
// immediate retries until this duration ends or we get a nil host.
var tryDuration = 60 * time.Second
// ServeHTTP satisfies the middleware.Handler interface. // ServeHTTP satisfies the middleware.Handler interface.
func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
...@@ -68,7 +72,7 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { ...@@ -68,7 +72,7 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Since Select() should give us "up" hosts, keep retrying // Since Select() should give us "up" hosts, keep retrying
// hosts until timeout (or until we get a nil host). // hosts until timeout (or until we get a nil host).
for time.Now().Sub(start) < (60 * time.Second) { for time.Now().Sub(start) < tryDuration {
host := upstream.Select() host := upstream.Select()
if host == nil { if host == nil {
return http.StatusBadGateway, errUnreachable return http.StatusBadGateway, errUnreachable
......
...@@ -4,10 +4,13 @@ import ( ...@@ -4,10 +4,13 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"io" "io"
"io/ioutil"
"log"
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"os"
"strings" "strings"
"testing" "testing"
"time" "time"
...@@ -15,6 +18,70 @@ import ( ...@@ -15,6 +18,70 @@ import (
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
func init() {
tryDuration = 50 * time.Millisecond // prevent tests from hanging
}
func TestReverseProxy(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
var requestReceived bool
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestReceived = true
w.Write([]byte("Hello, client"))
}))
defer backend.Close()
// set up proxy
p := &Proxy{
Upstreams: []Upstream{newFakeUpstream(backend.URL, false)},
}
// create request and response recorder
r, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
w := httptest.NewRecorder()
p.ServeHTTP(w, r)
if !requestReceived {
t.Error("Expected backend to receive request, but it didn't")
}
}
func TestReverseProxyInsecureSkipVerify(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
var requestReceived bool
backend := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestReceived = true
w.Write([]byte("Hello, client"))
}))
defer backend.Close()
// set up proxy
p := &Proxy{
Upstreams: []Upstream{newFakeUpstream(backend.URL, true)},
}
// create request and response recorder
r, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
w := httptest.NewRecorder()
p.ServeHTTP(w, r)
if !requestReceived {
t.Error("Even with insecure HTTPS, expected backend to receive request, but it didn't")
}
}
func TestWebSocketReverseProxyServeHTTPHandler(t *testing.T) { func TestWebSocketReverseProxyServeHTTPHandler(t *testing.T) {
// No-op websocket backend simply allows the WS connection to be // No-op websocket backend simply allows the WS connection to be
// accepted then it will be immediately closed. Perfect for testing. // accepted then it will be immediately closed. Perfect for testing.
...@@ -93,25 +160,57 @@ func TestWebSocketReverseProxyFromWSClient(t *testing.T) { ...@@ -93,25 +160,57 @@ func TestWebSocketReverseProxyFromWSClient(t *testing.T) {
} }
} }
func newFakeUpstream(name string, insecure bool) *fakeUpstream {
uri, _ := url.Parse(name)
u := &fakeUpstream{
name: name,
host: &UpstreamHost{
Name: name,
ReverseProxy: NewSingleHostReverseProxy(uri, ""),
},
}
if insecure {
u.host.ReverseProxy.Transport = InsecureTransport
}
return u
}
type fakeUpstream struct {
name string
host *UpstreamHost
}
func (u *fakeUpstream) From() string {
return "/"
}
func (u *fakeUpstream) Select() *UpstreamHost {
return u.host
}
func (u *fakeUpstream) IsAllowedPath(requestPath string) bool {
return true
}
// newWebSocketTestProxy returns a test proxy that will // newWebSocketTestProxy returns a test proxy that will
// redirect to the specified backendAddr. The function // redirect to the specified backendAddr. The function
// also sets up the rules/environment for testing WebSocket // also sets up the rules/environment for testing WebSocket
// proxy. // proxy.
func newWebSocketTestProxy(backendAddr string) *Proxy { func newWebSocketTestProxy(backendAddr string) *Proxy {
return &Proxy{ return &Proxy{
Upstreams: []Upstream{&fakeUpstream{name: backendAddr}}, Upstreams: []Upstream{&fakeWsUpstream{name: backendAddr}},
} }
} }
type fakeUpstream struct { type fakeWsUpstream struct {
name string name string
} }
func (u *fakeUpstream) From() string { func (u *fakeWsUpstream) From() string {
return "/" return "/"
} }
func (u *fakeUpstream) Select() *UpstreamHost { func (u *fakeWsUpstream) Select() *UpstreamHost {
uri, _ := url.Parse(u.name) uri, _ := url.Parse(u.name)
return &UpstreamHost{ return &UpstreamHost{
Name: u.name, Name: u.name,
...@@ -122,7 +221,7 @@ func (u *fakeUpstream) Select() *UpstreamHost { ...@@ -122,7 +221,7 @@ func (u *fakeUpstream) Select() *UpstreamHost {
} }
} }
func (u *fakeUpstream) IsAllowedPath(requestPath string) bool { func (u *fakeWsUpstream) IsAllowedPath(requestPath string) bool {
return true return true
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment