dynamicproxy.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package dynamicproxy
  2. import (
  3. "context"
  4. "errors"
  5. "log"
  6. "net/http"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "time"
  12. "imuslab.com/arozos/ReverseProxy/mod/dynamicproxy/dpcore"
  13. "imuslab.com/arozos/ReverseProxy/mod/reverseproxy"
  14. )
  15. /*
  16. Allow users to setup manual proxying for specific path
  17. */
  18. type Router struct {
  19. ListenPort int
  20. ProxyEndpoints *sync.Map
  21. SubdomainEndpoint *sync.Map
  22. Running bool
  23. Root *ProxyEndpoint
  24. mux http.Handler
  25. useTLS bool
  26. server *http.Server
  27. }
  28. type RouterOption struct {
  29. Port int
  30. }
  31. type ProxyEndpoint struct {
  32. Root string
  33. Domain string
  34. RequireTLS bool
  35. Proxy *dpcore.ReverseProxy `json:"-"`
  36. }
  37. type SubdomainEndpoint struct {
  38. MatchingDomain string
  39. Domain string
  40. RequireTLS bool
  41. Proxy *reverseproxy.ReverseProxy `json:"-"`
  42. }
  43. type ProxyHandler struct {
  44. Parent *Router
  45. }
  46. func NewDynamicProxy(port int) (*Router, error) {
  47. proxyMap := sync.Map{}
  48. domainMap := sync.Map{}
  49. thisRouter := Router{
  50. ListenPort: port,
  51. ProxyEndpoints: &proxyMap,
  52. SubdomainEndpoint: &domainMap,
  53. Running: false,
  54. useTLS: false,
  55. server: nil,
  56. }
  57. thisRouter.mux = &ProxyHandler{
  58. Parent: &thisRouter,
  59. }
  60. return &thisRouter, nil
  61. }
  62. //Start the dynamic routing
  63. func (router *Router) StartProxyService() error {
  64. //Create a new server object
  65. if router.server != nil {
  66. return errors.New("Reverse proxy server already running")
  67. }
  68. if router.Root == nil {
  69. return errors.New("Reverse proxy router root not set")
  70. }
  71. router.server = &http.Server{Addr: ":" + strconv.Itoa(router.ListenPort), Handler: router.mux}
  72. router.Running = true
  73. go func() {
  74. err := router.server.ListenAndServe()
  75. log.Println("[DynamicProxy] " + err.Error())
  76. }()
  77. return nil
  78. }
  79. func (router *Router) StopProxyService() error {
  80. if router.server == nil {
  81. return errors.New("Reverse proxy server already stopped")
  82. }
  83. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  84. defer cancel()
  85. err := router.server.Shutdown(ctx)
  86. if err != nil {
  87. return err
  88. }
  89. //Discard the server object
  90. router.server = nil
  91. router.Running = false
  92. return nil
  93. }
  94. /*
  95. Add an URL into a custom proxy services
  96. */
  97. func (router *Router) AddProxyService(rootname string, domain string, requireTLS bool) error {
  98. if domain[len(domain)-1:] == "/" {
  99. domain = domain[:len(domain)-1]
  100. }
  101. webProxyEndpoint := domain
  102. if requireTLS {
  103. webProxyEndpoint = "https://" + webProxyEndpoint
  104. } else {
  105. webProxyEndpoint = "http://" + webProxyEndpoint
  106. }
  107. //Create a new proxy agent for this root
  108. path, err := url.Parse(webProxyEndpoint)
  109. if err != nil {
  110. return err
  111. }
  112. proxy := dpcore.NewDynamicProxyCore(path, rootname)
  113. router.ProxyEndpoints.Store(rootname, &ProxyEndpoint{
  114. Root: rootname,
  115. Domain: domain,
  116. RequireTLS: requireTLS,
  117. Proxy: proxy,
  118. })
  119. log.Println("Adding Proxy Rule: ", rootname+" to "+domain)
  120. return nil
  121. }
  122. /*
  123. Add an default router for the proxy server
  124. */
  125. func (router *Router) SetRootProxy(proxyLocation string, requireTLS bool) error {
  126. if proxyLocation[len(proxyLocation)-1:] == "/" {
  127. proxyLocation = proxyLocation[:len(proxyLocation)-1]
  128. }
  129. webProxyEndpoint := proxyLocation
  130. if requireTLS {
  131. webProxyEndpoint = "https://" + webProxyEndpoint
  132. } else {
  133. webProxyEndpoint = "http://" + webProxyEndpoint
  134. }
  135. //Create a new proxy agent for this root
  136. path, err := url.Parse(webProxyEndpoint)
  137. if err != nil {
  138. return err
  139. }
  140. proxy := dpcore.NewDynamicProxyCore(path, "")
  141. rootEndpoint := ProxyEndpoint{
  142. Root: "/",
  143. Domain: proxyLocation,
  144. RequireTLS: requireTLS,
  145. Proxy: proxy,
  146. }
  147. router.Root = &rootEndpoint
  148. return nil
  149. }
  150. //Do all the main routing in here
  151. func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  152. if strings.Contains(r.Host, ".") {
  153. //This might be a subdomain. See if there are any subdomain proxy router for this
  154. sep := h.Parent.getSubdomainProxyEndpointFromHostname(r.Host)
  155. if sep != nil {
  156. h.subdomainRequest(w, r, sep)
  157. return
  158. }
  159. }
  160. targetProxyEndpoint := h.Parent.getTargetProxyEndpointFromRequestURI(r.RequestURI)
  161. if targetProxyEndpoint != nil {
  162. h.proxyRequest(w, r, targetProxyEndpoint)
  163. } else {
  164. h.proxyRequest(w, r, h.Parent.Root)
  165. }
  166. }