Skip to content

Commit

Permalink
Issue #9: Add raw http proxy as an alternative websocket handler
Browse files Browse the repository at this point in the history
  • Loading branch information
magiconair committed Nov 16, 2015
1 parent def5c6c commit fe10842
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
8 changes: 8 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var h http.Handler
switch {
case r.Header.Get("Upgrade") == "websocket":
// to establish WS connections as an unfiltered TCP stream
// between the client and the server use
//
// h = newRawProxy(t.URL)
//
// This may resolve compatilbility issues between the client
// and the server but it also increases the chance for malicious
// attacks since fabio no longer acts as a middleman.
h = newWSProxy(t.URL)
default:
h = newHTTPProxy(t.URL, p.tr)
Expand Down
58 changes: 58 additions & 0 deletions proxy/raw.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}

0 comments on commit fe10842

Please sign in to comment.