Skip to content

Commit

Permalink
Issue #9: Use raw http proxy as websocket handler
Browse files Browse the repository at this point in the history
  • Loading branch information
magiconair committed Nov 28, 2015
1 parent 63ef0d1 commit fc4706c
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
5 changes: 4 additions & 1 deletion proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
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 fc4706c

Please sign in to comment.