|
@@ -13,6 +13,7 @@ import (
|
|
"strings"
|
|
"strings"
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
|
"github.com/gorilla/websocket"
|
|
|
|
+ "imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
|
|
"imuslab.com/zoraxy/mod/info/logger"
|
|
"imuslab.com/zoraxy/mod/info/logger"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -56,9 +57,11 @@ type WebsocketProxy struct {
|
|
|
|
|
|
// Additional options for websocket proxy runtime
|
|
// Additional options for websocket proxy runtime
|
|
type Options struct {
|
|
type Options struct {
|
|
- SkipTLSValidation bool //Skip backend TLS validation
|
|
|
|
- SkipOriginCheck bool //Skip origin check
|
|
|
|
- Logger *logger.Logger //Logger, can be nil
|
|
|
|
|
|
+ SkipTLSValidation bool //Skip backend TLS validation
|
|
|
|
+ SkipOriginCheck bool //Skip origin check
|
|
|
|
+ CopyAllHeaders bool //Copy all headers from incoming request to backend request
|
|
|
|
+ UserDefinedHeaders []*rewrite.UserDefinedHeader //User defined headers
|
|
|
|
+ Logger *logger.Logger //Logger, can be nil
|
|
}
|
|
}
|
|
|
|
|
|
// ProxyHandler returns a new http.Handler interface that reverse proxies the
|
|
// ProxyHandler returns a new http.Handler interface that reverse proxies the
|
|
@@ -78,7 +81,14 @@ func NewProxy(target *url.URL, options Options) *WebsocketProxy {
|
|
u.RawQuery = r.URL.RawQuery
|
|
u.RawQuery = r.URL.RawQuery
|
|
return &u
|
|
return &u
|
|
}
|
|
}
|
|
- return &WebsocketProxy{Backend: backend, Verbal: false, Options: options}
|
|
|
|
|
|
+
|
|
|
|
+ // Create a new websocket proxy
|
|
|
|
+ wsprox := &WebsocketProxy{Backend: backend, Verbal: false, Options: options}
|
|
|
|
+ if options.CopyAllHeaders {
|
|
|
|
+ wsprox.Director = DefaultDirector
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return wsprox
|
|
}
|
|
}
|
|
|
|
|
|
// Utilities function for log printing
|
|
// Utilities function for log printing
|
|
@@ -90,6 +100,35 @@ func (w *WebsocketProxy) Println(messsage string, err error) {
|
|
log.Println("[websocketproxy] [system:info]"+messsage, err)
|
|
log.Println("[websocketproxy] [system:info]"+messsage, err)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// DefaultDirector is the default implementation of Director, which copies
|
|
|
|
+// all headers from the incoming request to the outgoing request.
|
|
|
|
+func DefaultDirector(r *http.Request, h http.Header) {
|
|
|
|
+ //Copy all header values from request to target header
|
|
|
|
+ for k, vv := range r.Header {
|
|
|
|
+ for _, v := range vv {
|
|
|
|
+ h.Set(k, v)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Remove hop-by-hop headers
|
|
|
|
+ for _, removePendingHeader := range []string{
|
|
|
|
+ "Connection",
|
|
|
|
+ "Keep-Alive",
|
|
|
|
+ "Proxy-Authenticate",
|
|
|
|
+ "Proxy-Authorization",
|
|
|
|
+ "Te",
|
|
|
|
+ "Trailers",
|
|
|
|
+ "Transfer-Encoding",
|
|
|
|
+ "Sec-WebSocket-Extensions",
|
|
|
|
+ "Sec-WebSocket-Key",
|
|
|
|
+ "Sec-WebSocket-Protocol",
|
|
|
|
+ "Sec-WebSocket-Version",
|
|
|
|
+ "Upgrade",
|
|
|
|
+ } {
|
|
|
|
+ h.Del(removePendingHeader)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
|
|
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
|
|
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
if w.Backend == nil {
|
|
if w.Backend == nil {
|
|
@@ -162,6 +201,15 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
w.Director(req, requestHeader)
|
|
w.Director(req, requestHeader)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Replace header variables and copy user-defined headers
|
|
|
|
+ rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(req, w.Options.UserDefinedHeaders)
|
|
|
|
+ upstreamHeaders, _ := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
|
|
|
|
+ UserDefinedHeaders: rewrittenUserDefinedHeaders,
|
|
|
|
+ })
|
|
|
|
+ for _, headerValuePair := range upstreamHeaders {
|
|
|
|
+ requestHeader.Set(headerValuePair[0], headerValuePair[1])
|
|
|
|
+ }
|
|
|
|
+
|
|
// Connect to the backend URL, also pass the headers we get from the requst
|
|
// Connect to the backend URL, also pass the headers we get from the requst
|
|
// together with the Forwarded headers we prepared above.
|
|
// together with the Forwarded headers we prepared above.
|
|
// TODO: support multiplexing on the same backend connection instead of
|
|
// TODO: support multiplexing on the same backend connection instead of
|