|
@@ -0,0 +1,136 @@
|
|
|
+package dynamicproxy
|
|
|
+
|
|
|
+import (
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "strconv"
|
|
|
+ "sync"
|
|
|
+
|
|
|
+ "imuslab.com/arozos/mod/network/reverseproxy"
|
|
|
+)
|
|
|
+
|
|
|
+/*
|
|
|
+ Allow users to setup manual proxying for specific path
|
|
|
+
|
|
|
+*/
|
|
|
+type Router struct {
|
|
|
+ ListenPort int
|
|
|
+ ProxyEndpoints *sync.Map
|
|
|
+ root *ProxyEndpoint
|
|
|
+ mux http.Handler
|
|
|
+ useTLS bool
|
|
|
+}
|
|
|
+
|
|
|
+type RouterOption struct {
|
|
|
+ Port int
|
|
|
+}
|
|
|
+
|
|
|
+type ProxyEndpoint struct {
|
|
|
+ Root string
|
|
|
+ Domain string
|
|
|
+ RequireTLS bool
|
|
|
+ Proxy *reverseproxy.ReverseProxy
|
|
|
+}
|
|
|
+
|
|
|
+type ProxyHandler struct {
|
|
|
+ Parent *Router
|
|
|
+}
|
|
|
+
|
|
|
+func NewDynamicProxy(port int) (*Router, error) {
|
|
|
+ newSyncMap := sync.Map{}
|
|
|
+ thisRouter := Router{
|
|
|
+ ListenPort: port,
|
|
|
+ ProxyEndpoints: &newSyncMap,
|
|
|
+ useTLS: false,
|
|
|
+ }
|
|
|
+
|
|
|
+ thisRouter.mux = &ProxyHandler{
|
|
|
+ Parent: &thisRouter,
|
|
|
+ }
|
|
|
+
|
|
|
+ return &thisRouter, nil
|
|
|
+}
|
|
|
+
|
|
|
+//Start the dynamic routing
|
|
|
+func (router *Router) StartProxyService() {
|
|
|
+ go func() {
|
|
|
+ err := http.ListenAndServe(":"+strconv.Itoa(router.ListenPort), router.mux)
|
|
|
+ log.Println("[DynamicProxy] " + err.Error())
|
|
|
+ }()
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ Add an URL into a custom proxy services
|
|
|
+*/
|
|
|
+func (router *Router) AddProxyService(rootname string, domain string, requireTLS bool) error {
|
|
|
+ if domain[len(domain)-1:] == "/" {
|
|
|
+ domain = domain[:len(domain)-1]
|
|
|
+ }
|
|
|
+
|
|
|
+ webProxyEndpoint := domain
|
|
|
+ if requireTLS {
|
|
|
+ webProxyEndpoint = "https://" + webProxyEndpoint
|
|
|
+ } else {
|
|
|
+ webProxyEndpoint = "http://" + webProxyEndpoint
|
|
|
+ }
|
|
|
+ //Create a new proxy agent for this root
|
|
|
+ path, err := url.Parse(webProxyEndpoint)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ proxy := reverseproxy.NewReverseProxy(path)
|
|
|
+
|
|
|
+ router.ProxyEndpoints.Store(rootname, &ProxyEndpoint{
|
|
|
+ Root: rootname,
|
|
|
+ Domain: domain,
|
|
|
+ RequireTLS: requireTLS,
|
|
|
+ Proxy: proxy,
|
|
|
+ })
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ Add an default router for the proxy server
|
|
|
+*/
|
|
|
+func (router *Router) SetRootProxy(proxyLocation string, requireTLS bool) error {
|
|
|
+ if proxyLocation[len(proxyLocation)-1:] == "/" {
|
|
|
+ proxyLocation = proxyLocation[:len(proxyLocation)-1]
|
|
|
+ }
|
|
|
+
|
|
|
+ webProxyEndpoint := proxyLocation
|
|
|
+ if requireTLS {
|
|
|
+ webProxyEndpoint = "https://" + webProxyEndpoint
|
|
|
+ } else {
|
|
|
+ webProxyEndpoint = "http://" + webProxyEndpoint
|
|
|
+ }
|
|
|
+ //Create a new proxy agent for this root
|
|
|
+ path, err := url.Parse(webProxyEndpoint)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ proxy := reverseproxy.NewReverseProxy(path)
|
|
|
+
|
|
|
+ rootEndpoint := ProxyEndpoint{
|
|
|
+ Root: "/",
|
|
|
+ Domain: proxyLocation,
|
|
|
+ RequireTLS: requireTLS,
|
|
|
+ Proxy: proxy,
|
|
|
+ }
|
|
|
+
|
|
|
+ router.root = &rootEndpoint
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+//Do all the main routing in here
|
|
|
+func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
+ targetProxyEndpoint := h.Parent.getTargetProxyEndpointFromRequestURI(r.RequestURI)
|
|
|
+ log.Println(targetProxyEndpoint)
|
|
|
+ if targetProxyEndpoint != nil {
|
|
|
+ h.proxyRequest(w, r, targetProxyEndpoint)
|
|
|
+ } else {
|
|
|
+ h.proxyRequest(w, r, h.Parent.root)
|
|
|
+ }
|
|
|
+}
|