Skip to content

Instantly share code, notes, and snippets.

@bradfitz
Created November 5, 2018 17:06
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bradfitz/1d7bdf12278d4d713212ce6c74875dab to your computer and use it in GitHub Desktop.
Save bradfitz/1d7bdf12278d4d713212ce6c74875dab to your computer and use it in GitHub Desktop.
pre-Go1.12 websocket hijack+proxy
httpsServer := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
hj, isHJ := w.(http.Hijacker)
if r.Header.Get("Upgrade") == "websocket" && isHJ {
c, br, err := hj.Hijack()
if err != nil {
log.Printf("websocket websocket hijack: %v", err)
http.Error(w, err.Error(), 500)
return
}
defer c.Close()
var be net.Conn
if len(hostPorts) == 0 {
backendHostPort := base.Host
if !strings.Contains(backendHostPort, ":") {
backendHostPort = net.JoinHostPort(backendHostPort, "443")
}
be, err = tls.DialWithDialer(dialer, "tcp", backendHostPort, tlsConfig)
} else {
for _, hostPort := range hostPorts {
be, err = tls.DialWithDialer(dialer, "tcp", hostPort, tlsConfig)
if err == nil {
break
}
}
}
if err != nil {
log.Printf("websocket Dial: %v", err)
http.Error(w, err.Error(), 500)
return
}
defer be.Close()
if err := r.Write(be); err != nil {
log.Printf("websocket backend write request: %v", err)
http.Error(w, err.Error(), 500)
return
}
errc := make(chan error, 1)
go func() {
n, err := io.Copy(be, br) // backend <- buffered reader
if err != nil {
err = fmt.Errorf("websocket: to copy backend from buffered reader: %v, %v", n, err)
}
errc <- err
}()
go func() {
n, err := io.Copy(c, be) // raw conn <- backend
if err != nil {
err = fmt.Errorf("websocket: to raw conn from backend: %v, %v", n, err)
}
errc <- err
}()
if err := <-errc; err != nil {
log.Print(err)
}
return
}
rp.ServeHTTP(w, r)
}),
TLSConfig: &tls.Config{
NextProtos: []string{"h2", "http/1.1"},
GetCertificate: autoCertMan.GetCertificate,
},
}
@just1689
Copy link

just1689 commented Jan 23, 2019

Sorry for the noob question. May I ask what rp on line 59 is?

EDIT:
Well I feel a bit silly. This seems to work:

u, err := url.Parse(target)
...
rp := httputil.NewSingleHostReverseProxy(u)

@bubbajoe
Copy link

bubbajoe commented Apr 26, 2019

@just1689
Most likely proxy *httputil.ReverseProxy
or the struct made from it

@just1689
Copy link

just1689 commented Apr 26, 2019

@bubbajoe this may or may not be relevant - I believe this functionality is now in Go 1.12

https://golang.org/doc/go1.12#net/http/httputil

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment