100 lines of code implements a lightweight websocket proxy library, does not depend on other third-party libraries, and supports ws and wss proxies; if you only need a simple websocket traffic proxy function without any modification to the forwarded content, using this library will be very useful.
- Extreme performance, almost no performance loss, very low consumption of cpu and memory
- Support websocket handshake phase for management and control
- Supports setting header headers (cookie, origin, etc.) in the handshake phase
- Support ws, wss proxy
go get github.com/pretty66/websocketproxy
import (
"github.com/pretty66/websocketproxy""net/http"
)
wp, err:=websocketproxy.NewProxy("ws://82.157.123.54:9010/ajaxchattest", func(r*http.Request) error {
// Permission to verifyr.Header.Set("Cookie", "----")
// Source of disguiser.Header.Set("Origin", "http://82.157.123.54:9010")
returnnil
})
iferr!=nil {
t.Fatal()
}
// proxy pathhttp.HandleFunc("/wsproxy", wp.Proxy)
http.ListenAndServe(":9696", nil)Run the test file and start listening on the 127.0.0.1:9696 port, and use the online testing tool http://coolaf.com/tool/chattest to connect to the proxy to test the request response
func (wp*WebsocketProxy) Proxy(writer http.ResponseWriter, request*http.Request) {
// Check whether it is a Websocket requestifstrings.ToLower(request.Header.Get("Connection")) !="upgrade"||strings.ToLower(request.Header.Get("Upgrade")) !="websocket" {
_, _=writer.Write([]byte(`Must be a websocket request`))
return
}
// Hijack connectionshijacker, ok:=writer.(http.Hijacker)
if!ok {
return
}
conn, _, err:=hijacker.Hijack()
iferr!=nil {
return
}
deferconn.Close()
// Clone request, set destination address pathreq:=request.Clone(context.TODO())
req.URL.Path, req.URL.RawPath, req.RequestURI=wp.defaultPath, wp.defaultPath, wp.defaultPathreq.Host=wp.remoteAddr// Handshake before callbackifwp.beforeHandshake!=nil {
// Add headers, permission authentication + masquerade sourceserr=wp.beforeHandshake(req)
iferr!=nil {
_, _=writer.Write([]byte(err.Error()))
return
}
}
// Determine the protocol and select the dialing processvarremoteConn net.Connswitchwp.scheme {
caseWsScheme:
remoteConn, err=net.Dial("tcp", wp.remoteAddr)
caseWssScheme:
remoteConn, err=tls.Dial("tcp", wp.remoteAddr, wp.tlsc)
}
iferr!=nil {
_, _=writer.Write([]byte(err.Error()))
return
}
deferremoteConn.Close()
// Sends a handshake packet to the target WebSocket serviceerr=req.Write(remoteConn)
iferr!=nil {
wp.logger.Println("remote write err:", err)
return
}
// Traffic transparent transmissionerrChan:=make(chanerror, 2)
copyConn:=func(a, b net.Conn) {
_, err:=io.Copy(a, b)
errChan<-err
}
gocopyConn(conn, remoteConn) // responsegocopyConn(remoteConn, conn) // requestselect {
caseerr=<-errChan:
iferr!=nil {
log.Println(err)
}
}
}
websocketproxy is under the Apache 2.0 license. See the LICENSE directory for details.
