Browse Source

auto update script executed

Toby Chui 1 year ago
parent
commit
c7f333ae61

+ 9 - 0
mod/dynamicproxy/dynamicproxy.go

@@ -15,6 +15,7 @@ import (
 	"time"
 
 	"imuslab.com/arozos/ReverseProxy/mod/dynamicproxy/dpcore"
+	"imuslab.com/arozos/ReverseProxy/mod/dynamicproxy/redirection"
 	"imuslab.com/arozos/ReverseProxy/mod/reverseproxy"
 	"imuslab.com/arozos/ReverseProxy/mod/tlscert"
 )
@@ -35,6 +36,7 @@ type Router struct {
 	useHttpToHttpsRedirect bool
 	server                 *http.Server
 	tlsListener            net.Listener
+	redirectionRuleTable   *redirection.RuleTable
 }
 
 type RouterOption struct {
@@ -42,6 +44,7 @@ type RouterOption struct {
 	UseTls             bool
 	ForceHttpsRedirect bool
 	TlsManager         *tlscert.Manager
+	RedirectRuleTable  *redirection.RuleTable
 }
 
 type ProxyEndpoint struct {
@@ -73,6 +76,7 @@ func NewDynamicProxy(option RouterOption) (*Router, error) {
 		tlsCertManager:         option.TlsManager,
 		useTLS:                 option.UseTls,
 		useHttpToHttpsRedirect: option.ForceHttpsRedirect,
+		redirectionRuleTable:   option.RedirectRuleTable,
 		server:                 nil,
 	}
 
@@ -299,6 +303,11 @@ func (router *Router) SetRootProxy(proxyLocation string, requireTLS bool) error
 
 // Do all the main routing in here
 func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	//Check if this is a redirection url
+	if h.Parent.redirectionRuleTable.IsRedirectable(r) {
+		h.Parent.redirectionRuleTable.HandleRedirect(w, r)
+		return
+	}
 	domainOnly := r.Host
 	if strings.Contains(r.Host, ":") {
 		hostPath := strings.Split(r.Host, ":")

+ 52 - 0
mod/dynamicproxy/redirection/handler.go

@@ -0,0 +1,52 @@
+package redirection
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"strings"
+)
+
+/*
+	handler.go
+
+	This script store the handlers use for handling
+	redirection request
+*/
+
+//Check if a request URL is a redirectable URI
+func (t *RuleTable) IsRedirectable(r *http.Request) bool {
+	requestPath := r.Host + r.URL.Path
+	rr := t.MatchRedirectRule(requestPath)
+	return rr != nil
+}
+
+//Handle the redirect request, return after calling this function to prevent
+//multiple write to the response writer
+func (t *RuleTable) HandleRedirect(w http.ResponseWriter, r *http.Request) {
+	requestPath := r.Host + r.URL.Path
+	rr := t.MatchRedirectRule(requestPath)
+	if rr != nil {
+		redirectTarget := rr.TargetURL
+		//Always pad a / at the back of the target URL
+		if redirectTarget[len(redirectTarget)-1:] != "/" {
+			redirectTarget += "/"
+		}
+		if rr.ForwardChildpath {
+			//Remove the first / in the path
+			redirectTarget += r.URL.Path[1:]
+		}
+
+		if !strings.HasPrefix(redirectTarget, "http://") && !strings.HasPrefix(redirectTarget, "https://") {
+			redirectTarget = "http://" + redirectTarget
+		}
+
+		fmt.Println(redirectTarget)
+		http.Redirect(w, r, redirectTarget, rr.StatusCode)
+	} else {
+		//Invalid usage
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("500 - Internal Server Error"))
+		log.Println("Target request URL do not have matching redirect rule. Check with IsRedirectable before calling HandleRedirect!")
+	}
+}

+ 10 - 5
mod/dynamicproxy/redirection/redirection.go

@@ -143,15 +143,20 @@ func (t *RuleTable) GetAllRedirectRules() []*RedirectRules {
 // Check if a given request URL matched any of the redirection rule
 func (t *RuleTable) MatchRedirectRule(requestedURL string) *RedirectRules {
 	// Iterate through all the keys in the rules map
+	var targetRedirectionRule *RedirectRules = nil
+	var maxMatch int = 0
+
 	t.rules.Range(func(key interface{}, value interface{}) bool {
 		// Check if the requested URL starts with the key as a prefix
 		if strings.HasPrefix(requestedURL, key.(string)) {
-			//This request URL matched the domain
-
-			return true
+			// This request URL matched the domain
+			if len(key.(string)) > maxMatch {
+				maxMatch = len(key.(string))
+				targetRedirectionRule = value.(*RedirectRules)
+			}
 		}
-		return false
+		return true
 	})
 
-	return nil
+	return targetRedirectionRule
 }

+ 1 - 0
reverseproxy.go

@@ -47,6 +47,7 @@ func ReverseProxtInit() {
 		UseTls:             useTls,
 		ForceHttpsRedirect: forceHttpsRedirect,
 		TlsManager:         tlsCertManager,
+		RedirectRuleTable:  redirectTable,
 	})
 	if err != nil {
 		log.Println(err.Error())

BIN
sys.db


+ 51 - 9
web/components/redirection.html

@@ -5,9 +5,11 @@
         <thead>
             <tr>
                 <th>Redirection URL</th>
+                <th></th>
                 <th>Destination URL</th>
                 <th>Copy Pathname</th>
                 <th>Status Code</th>
+                <th>Remove</th>
             </tr>
         </thead>
         <tbody id="redirectionRuleList">
@@ -19,6 +21,9 @@
             </tr>
         </tbody>
     </table>
+    <div class="ui green message" id="delRuleSucc" style="display:none;">
+      <i class="ui green checkmark icon"></i> Redirection Rule Deleted
+    </div>
 </div>
 <div class="ui divider"></div>
 <p>Add path redirection to your domain</p>
@@ -26,12 +31,13 @@
 <div class="ui form">
     <div class="field">
       <label>Redirection URL</label>
-      <input type="text" name="redirection-url" placeholder="Redirection URL">
-      <small><i class="ui circle info icon"></i> Redirection URL, any matching prefix of the request URL will be redirected to the following destination URL.</small>
+      <input type="text" id="rurl" name="redirection-url" placeholder="Redirection URL">
+      <small><i class="ui circle info icon"></i> Any matching prefix of the request URL will be redirected to the destination URL, e.g. redirect.example.com</small>
     </div>
     <div class="field">
       <label>Destination URL</label>
       <input type="text" name="destination-url" placeholder="Destination URL">
+      <small><i class="ui circle info icon"></i> The target URL request being redirected to, e.g. dest.example.com/mysite</small>
     </div>
     <div class="field">
       <div class="ui checkbox">
@@ -59,7 +65,10 @@
           </div>
         </div>
     </div>
-    <button class="ui button" onclick="addRules();">Add</button>
+    <button class="ui teal button" onclick="addRules();"><i class="ui plus icon"></i> Add Redirection Rule</button>
+    <div class="ui green message" id="ruleAddSucc" style="display:none;">
+      <i class="ui green checkmark icon"></i> Redirection Rules Added
+    </div>
 </div>
 <script>
     $(".checkbox").checkbox();
@@ -80,30 +89,63 @@
                 redirectType: parseInt(redirectType),
             },
             success: function(data){
-                alert(data);
+                if (data.error != undefined){
+                  alert(data.error);
+                }else{
+                  $("#ruleAddSucc").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
+                }
+                initRedirectionRuleList();
             }
-        })
+        });
     }
 
-    function deleteRule(redirectDomain){
-
+    function deleteRule(obj){
+      let targetURL = $(obj).attr("rurl");
+      targetURL = JSON.parse(decodeURIComponent(targetURL));
+      if (confirm("Confirm remove redirection from " + targetURL + " ?")){
+        $.ajax({
+              url: "/redirect/delete", 
+              method: "POST",
+              data: {
+                  redirectUrl: targetURL,
+              },
+              success: function(data){
+                  if (data.error != undefined){
+                    alert(data.error);
+                  }else{
+                    $("#delRuleSucc").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
+                  }
+                  initRedirectionRuleList();
+              }
+          });
+        }
     }
 
     function initRedirectionRuleList(){
         $("#redirectionRuleList").html("");
         $.get("/redirect/list", function(data){
-            console.log(data);
             data.forEach(function(entry){
                 $("#redirectionRuleList").append(`<tr>
-                    <td>${entry.RedirectURL}</td>
+                    <td>${entry.RedirectURL} </td>
+                    <td style="text-align: center;"><i class="blue arrow right icon"></i></td>
                     <td>${entry.TargetURL}</td>
                     <td>${entry.ForwardChildpath?"<i class='ui green checkmark icon'></i>":"<i class='ui red remove icon'></i>"}</td>
                     <td>${entry.StatusCode==307?"Temporary Redirect (307)":"Moved Permanently (301)"}</td>
+                    <td><button onclick="deleteRule(this);" rurl="${encodeURIComponent(JSON.stringify(entry.RedirectURL))}" title="Delete redirection rule" class="ui mini red icon basic button"><i class="trash icon"></i></button></td>
                 </tr>`);
             });
+
+            if (data.length == 0){
+              $("#redirectionRuleList").append(`<tr colspan="4"><td><i class="checkmark icon"></i> No redirection rule</td></tr>`);
+            }
             
         });
     }
     initRedirectionRuleList();
+
+    $("#rurl").on('change', (event) => {
+      const value = event.target.value.trim().replace(/^(https?:\/\/)/, '');
+      event.target.value = value;
+    });
     
 </script>