diff --git a/proxy/proxy.go b/proxy/proxy.go index bd6e4cb15..0efd29c12 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -44,7 +44,10 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { var h http.Handler switch { case r.Header.Get("Upgrade") == "websocket": - h = newWSProxy(t.URL) + h = newRawProxy(t.URL) + + // To use the filtered proxy use + // h = newWSProxy(t.URL) default: h = newHTTPProxy(t.URL, p.tr) } diff --git a/proxy/raw.go b/proxy/raw.go new file mode 100644 index 000000000..904b21990 --- /dev/null +++ b/proxy/raw.go @@ -0,0 +1,58 @@ +package proxy + +import ( + "io" + "log" + "net" + "net/http" + "net/url" +) + +// newRawProxy returns an HTTP handler which forwards data between +// an incoming and outgoing TCP connection including the original request. +// This handler establishes a new outgoing connection per request. +func newRawProxy(t *url.URL) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hj, ok := w.(http.Hijacker) + if !ok { + http.Error(w, "not a hijacker", http.StatusInternalServerError) + return + } + + in, _, err := hj.Hijack() + if err != nil { + log.Printf("[ERROR] Hijack error for %s. %s", r.URL, err) + http.Error(w, "hijack error", http.StatusInternalServerError) + return + } + defer in.Close() + + out, err := net.Dial("tcp", t.Host) + if err != nil { + log.Printf("[ERROR] WS error for %s. %s", r.URL, err) + http.Error(w, "error contacting backend server", http.StatusInternalServerError) + return + } + defer out.Close() + + err = r.Write(out) + if err != nil { + log.Printf("[ERROR] Error copying request for %s. %s", r.URL, err) + http.Error(w, "error copying request", http.StatusInternalServerError) + return + } + + errc := make(chan error, 2) + cp := func(dst io.Writer, src io.Reader) { + _, err := io.Copy(dst, src) + errc <- err + } + + go cp(out, in) + go cp(in, out) + err = <-errc + if err != nil && err != io.EOF { + log.Printf("[INFO] WS error for %s. %s", r.URL, err) + } + }) +}