From 373f521de800af3dfbeb054fdfff5b47df74c2df Mon Sep 17 00:00:00 2001 From: SirStendec Date: Thu, 28 Sep 2017 23:03:41 -0400 Subject: [PATCH] Allow the socket server to act as a proxy to other services. --- socketserver/server/handlecore.go | 46 +++++++++++++++++++++++++++++++ socketserver/server/types.go | 10 +++++++ 2 files changed, 56 insertions(+) diff --git a/socketserver/server/handlecore.go b/socketserver/server/handlecore.go index 6b1db227..525101aa 100644 --- a/socketserver/server/handlecore.go +++ b/socketserver/server/handlecore.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "log" "net/http" + "net/http/httputil" "net/url" "os" "os/signal" @@ -105,6 +106,10 @@ func SetupServerAndHandle(config *ConfigFile, serveMux *http.ServeMux) { serveMux.HandleFunc("/get_sub_count", HTTPGetSubscriberCount) serveMux.HandleFunc("/all_topics", HTTPListAllTopics) + for _, route := range config.ProxyRoutes { + serveMux.Handle(route.Route, ProxyHandler(route)) + } + announceForm, err := Backend.secureForm.Seal(url.Values{ "startup": []string{"1"}, }) @@ -169,6 +174,47 @@ func dumpStackOnCtrlZ() { } } +// Join two URL segments +func singleJoiningSlash(a, b string) string { + aslash := strings.HasSuffix(a, "/") + bslash := strings.HasPrefix(b, "/") + switch { + case aslash && bslash: + return a + b[1:] + case !aslash && !bslash: + return a + "/" + b + } + return a + b +} + +// ProxyHandler sets up a ReverseProxy for serving content on a route. +func ProxyHandler(route ProxyRoute) *httputil.ReverseProxy { + target, err := url.Parse(route.Server) + if err != nil { + log.Fatalln("Unable to parse proxy URL:", err) + } + + offset := len(route.Route) + targetQuery := target.RawQuery + + director := func(req *http.Request) { + req.URL.Scheme = target.Scheme + req.URL.Host = target.Host + req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path[offset:len(req.URL.Path)]) + if targetQuery == "" || req.URL.RawQuery == "" { + req.URL.RawQuery = targetQuery + req.URL.RawQuery + } else { + req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery + } + if _, ok := req.Header["User-Agent"]; !ok { + // Disable User-Agent + req.Header.Set("User-Agent", "") + } + } + + return &httputil.ReverseProxy{Director: director} +} + // HTTPSayOK replies with 200 and a body of "ok\n". func HTTPSayOK(w http.ResponseWriter, _ *http.Request) { w.(interface { diff --git a/socketserver/server/types.go b/socketserver/server/types.go index b6a39d4e..3face4c4 100644 --- a/socketserver/server/types.go +++ b/socketserver/server/types.go @@ -42,8 +42,18 @@ type ConfigFile struct { // Request username validation from all new clients. SendAuthToNewClients bool + + // Proxy Routes + ProxyRoutes []ProxyRoute } + +type ProxyRoute struct { + Route string + Server string +} + + type ClientMessage struct { // Message ID. Increments by 1 for each message sent from the client. // When replying to a command, the message ID must be echoed.