123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- package dynamicproxy
- import (
- "context"
- "errors"
- "log"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "sync"
- "time"
- "imuslab.com/arozos/ReverseProxy/mod/dynamicproxy/dpcore"
- "imuslab.com/arozos/ReverseProxy/mod/reverseproxy"
- )
- /*
- Allow users to setup manual proxying for specific path
- */
- type Router struct {
- ListenPort int
- ProxyEndpoints *sync.Map
- SubdomainEndpoint *sync.Map
- Running bool
- Root *ProxyEndpoint
- mux http.Handler
- useTLS bool
- server *http.Server
- }
- type RouterOption struct {
- Port int
- }
- type ProxyEndpoint struct {
- Root string
- Domain string
- RequireTLS bool
- Proxy *dpcore.ReverseProxy `json:"-"`
- }
- type SubdomainEndpoint struct {
- MatchingDomain string
- Domain string
- RequireTLS bool
- Proxy *reverseproxy.ReverseProxy `json:"-"`
- }
- type ProxyHandler struct {
- Parent *Router
- }
- func NewDynamicProxy(port int) (*Router, error) {
- proxyMap := sync.Map{}
- domainMap := sync.Map{}
- thisRouter := Router{
- ListenPort: port,
- ProxyEndpoints: &proxyMap,
- SubdomainEndpoint: &domainMap,
- Running: false,
- useTLS: false,
- server: nil,
- }
- thisRouter.mux = &ProxyHandler{
- Parent: &thisRouter,
- }
- return &thisRouter, nil
- }
- //Start the dynamic routing
- func (router *Router) StartProxyService() error {
- //Create a new server object
- if router.server != nil {
- return errors.New("Reverse proxy server already running")
- }
- if router.Root == nil {
- return errors.New("Reverse proxy router root not set")
- }
- router.server = &http.Server{Addr: ":" + strconv.Itoa(router.ListenPort), Handler: router.mux}
- router.Running = true
- go func() {
- err := router.server.ListenAndServe()
- log.Println("[DynamicProxy] " + err.Error())
- }()
- return nil
- }
- func (router *Router) StopProxyService() error {
- if router.server == nil {
- return errors.New("Reverse proxy server already stopped")
- }
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- err := router.server.Shutdown(ctx)
- if err != nil {
- return err
- }
- //Discard the server object
- router.server = nil
- router.Running = false
- return nil
- }
- /*
- 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 := dpcore.NewDynamicProxyCore(path, rootname)
- router.ProxyEndpoints.Store(rootname, &ProxyEndpoint{
- Root: rootname,
- Domain: domain,
- RequireTLS: requireTLS,
- Proxy: proxy,
- })
- log.Println("Adding Proxy Rule: ", rootname+" to "+domain)
- 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 := dpcore.NewDynamicProxyCore(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) {
- if strings.Contains(r.Host, ".") {
- //This might be a subdomain. See if there are any subdomain proxy router for this
- sep := h.Parent.getSubdomainProxyEndpointFromHostname(r.Host)
- if sep != nil {
- h.subdomainRequest(w, r, sep)
- return
- }
- }
- targetProxyEndpoint := h.Parent.getTargetProxyEndpointFromRequestURI(r.RequestURI)
- if targetProxyEndpoint != nil {
- h.proxyRequest(w, r, targetProxyEndpoint)
- } else {
- h.proxyRequest(w, r, h.Parent.Root)
- }
- }
|