dynamicproxy.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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) AddVirtualDirectoryProxyService(rootname string, domain string, requireTLS bool) error {
  98. if domain[len(domain)-1:] == "/" {
  99. domain = domain[:len(domain)-1]
  100. }
  101. if rootname[len(rootname)-1:] == "/" {
  102. rootname = rootname[:len(rootname)-1]
  103. }
  104. webProxyEndpoint := domain
  105. if requireTLS {
  106. webProxyEndpoint = "https://" + webProxyEndpoint
  107. } else {
  108. webProxyEndpoint = "http://" + webProxyEndpoint
  109. }
  110. //Create a new proxy agent for this root
  111. path, err := url.Parse(webProxyEndpoint)
  112. if err != nil {
  113. return err
  114. }
  115. proxy := dpcore.NewDynamicProxyCore(path, rootname)
  116. router.ProxyEndpoints.Store(rootname, &ProxyEndpoint{
  117. Root: rootname,
  118. Domain: domain,
  119. RequireTLS: requireTLS,
  120. Proxy: proxy,
  121. })
  122. log.Println("Adding Proxy Rule: ", rootname+" to "+domain)
  123. return nil
  124. }
  125. /*
  126. Add an default router for the proxy server
  127. */
  128. func (router *Router) SetRootProxy(proxyLocation string, requireTLS bool) error {
  129. if proxyLocation[len(proxyLocation)-1:] == "/" {
  130. proxyLocation = proxyLocation[:len(proxyLocation)-1]
  131. }
  132. webProxyEndpoint := proxyLocation
  133. if requireTLS {
  134. webProxyEndpoint = "https://" + webProxyEndpoint
  135. } else {
  136. webProxyEndpoint = "http://" + webProxyEndpoint
  137. }
  138. //Create a new proxy agent for this root
  139. path, err := url.Parse(webProxyEndpoint)
  140. if err != nil {
  141. return err
  142. }
  143. proxy := dpcore.NewDynamicProxyCore(path, "")
  144. rootEndpoint := ProxyEndpoint{
  145. Root: "/",
  146. Domain: proxyLocation,
  147. RequireTLS: requireTLS,
  148. Proxy: proxy,
  149. }
  150. router.Root = &rootEndpoint
  151. return nil
  152. }
  153. //Do all the main routing in here
  154. func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  155. if strings.Contains(r.Host, ".") {
  156. //This might be a subdomain. See if there are any subdomain proxy router for this
  157. sep := h.Parent.getSubdomainProxyEndpointFromHostname(r.Host)
  158. if sep != nil {
  159. h.subdomainRequest(w, r, sep)
  160. return
  161. }
  162. }
  163. targetProxyEndpoint := h.Parent.getTargetProxyEndpointFromRequestURI(r.RequestURI)
  164. if targetProxyEndpoint != nil {
  165. h.proxyRequest(w, r, targetProxyEndpoint)
  166. } else {
  167. h.proxyRequest(w, r, h.Parent.Root)
  168. }
  169. }