Browse Source

Merged Github PR and removed error log in servehttp

Toby Chui 6 months ago
parent
commit
5671d9fbd3

+ 1 - 1
main.go

@@ -61,7 +61,7 @@ var (
 	name        = "Zoraxy"
 	version     = "3.1.1"
 	nodeUUID    = "generic" //System uuid, in uuidv4 format
-	development = false     //Set this to false to use embedded web fs
+	development = true      //Set this to false to use embedded web fs
 	bootTime    = time.Now().Unix()
 
 	/*

+ 6 - 2
mod/dynamicproxy/loadbalance/loadbalance.go

@@ -83,6 +83,10 @@ func GetUpstreamsAsString(upstreams []*Upstream) string {
 	for _, upstream := range upstreams {
 		targets = append(targets, upstream.String())
 	}
+	if len(targets) == 0 {
+		//No upstream
+		return "(no upstream config)"
+	}
 	return strings.Join(targets, ", ")
 }
 
@@ -93,7 +97,7 @@ func (m *RouteManager) Close() {
 
 }
 
-// Print debug message
-func (m *RouteManager) debugPrint(message string, err error) {
+// Log Println, replace all log.Println or fmt.Println with this
+func (m *RouteManager) println(message string, err error) {
 	m.Options.Logger.PrintAndLog("LoadBalancer", message, err)
 }

+ 52 - 29
mod/dynamicproxy/loadbalance/originPicker.go

@@ -2,8 +2,6 @@ package loadbalance
 
 import (
 	"errors"
-	"fmt"
-	"log"
 	"math/rand"
 	"net/http"
 )
@@ -29,7 +27,7 @@ func (m *RouteManager) GetRequestUpstreamTarget(w http.ResponseWriter, r *http.R
 			//No valid session found. Assign a new upstream
 			targetOrigin, index, err := getRandomUpstreamByWeight(origins)
 			if err != nil {
-				fmt.Println("Oops. Unable to get random upstream")
+				m.println("Unable to get random upstream", err)
 				targetOrigin = origins[0]
 				index = 0
 			}
@@ -44,7 +42,7 @@ func (m *RouteManager) GetRequestUpstreamTarget(w http.ResponseWriter, r *http.R
 		var err error
 		targetOrigin, _, err = getRandomUpstreamByWeight(origins)
 		if err != nil {
-			log.Println(err)
+			m.println("Failed to get next origin", err)
 			targetOrigin = origins[0]
 		}
 
@@ -102,42 +100,66 @@ func (m *RouteManager) getSessionHandler(r *http.Request, upstreams []*Upstream)
 /* Functions related to random upstream picking */
 // Get a random upstream by the weights defined in Upstream struct, return the upstream, index value and any error
 func getRandomUpstreamByWeight(upstreams []*Upstream) (*Upstream, int, error) {
-	var ret *Upstream
-	sum := 0
-	for _, c := range upstreams {
-		sum += c.Weight
+	// If there is only one upstream, return it
+	if len(upstreams) == 1 {
+		return upstreams[0], 0, nil
 	}
-	r, err := intRange(0, sum)
-	if err != nil {
-		return ret, -1, err
+
+	// Preserve the index with upstreams
+	type upstreamWithIndex struct {
+		Upstream *Upstream
+		Index    int
 	}
-	counter := 0
-	for _, c := range upstreams {
-		r -= c.Weight
-		if r < 0 {
-			return c, counter, nil
+
+	// Calculate total weight for upstreams with weight > 0
+	totalWeight := 0
+	fallbackUpstreams := make([]upstreamWithIndex, 0, len(upstreams))
+
+	for index, upstream := range upstreams {
+		if upstream.Weight > 0 {
+			totalWeight += upstream.Weight
+		} else {
+			// Collect fallback upstreams
+			fallbackUpstreams = append(fallbackUpstreams, upstreamWithIndex{upstream, index})
+		}
+	}
+
+	// If there are no upstreams with weight > 0, return a fallback upstream if available
+	if totalWeight == 0 {
+		if len(fallbackUpstreams) > 0 {
+			// Randomly select one of the fallback upstreams
+			randIndex := rand.Intn(len(fallbackUpstreams))
+			return fallbackUpstreams[randIndex].Upstream, fallbackUpstreams[randIndex].Index, nil
 		}
-		counter++
+		// No upstreams available at all
+		return nil, -1, errors.New("no valid upstream servers available")
 	}
 
-	if ret == nil {
-		//All fallback
-		//use the first one that is with weight = 0
-		fallbackUpstreams := []*Upstream{}
-		fallbackUpstreamsOriginalID := []int{}
-		for ix, upstream := range upstreams {
-			if upstream.Weight == 0 {
-				fallbackUpstreams = append(fallbackUpstreams, upstream)
-				fallbackUpstreamsOriginalID = append(fallbackUpstreamsOriginalID, ix)
+	// Random weight between 0 and total weight
+	randomWeight := rand.Intn(totalWeight)
+
+	// Select an upstream based on the random weight
+	for index, upstream := range upstreams {
+		if upstream.Weight > 0 { // Only consider upstreams with weight > 0
+			if randomWeight < upstream.Weight {
+				// Return the selected upstream and its index
+				return upstream, index, nil
 			}
+			randomWeight -= upstream.Weight
 		}
-		upstreamID := rand.Intn(len(fallbackUpstreams))
-		return fallbackUpstreams[upstreamID], fallbackUpstreamsOriginalID[upstreamID], nil
 	}
-	return ret, -1, errors.New("failed to pick an upstream origin server")
+
+	// If we reach here, it means we should return a fallback upstream if available
+	if len(fallbackUpstreams) > 0 {
+		randIndex := rand.Intn(len(fallbackUpstreams))
+		return fallbackUpstreams[randIndex].Upstream, fallbackUpstreams[randIndex].Index, nil
+	}
+
+	return nil, -1, errors.New("failed to pick an upstream origin server")
 }
 
 // IntRange returns a random integer in the range from min to max.
+/*
 func intRange(min, max int) (int, error) {
 	var result int
 	switch {
@@ -152,3 +174,4 @@ func intRange(min, max int) (int, error) {
 	}
 	return result, nil
 }
+*/

+ 2 - 3
mod/dynamicproxy/proxyRequestHandler.go

@@ -117,7 +117,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
 	selectedUpstream, err := h.Parent.loadBalancer.GetRequestUpstreamTarget(w, r, target.ActiveOrigins, target.UseStickySession)
 	if err != nil {
 		http.ServeFile(w, r, "./web/rperror.html")
-		log.Println(err.Error())
+		h.Parent.Option.Logger.PrintAndLog("proxy", "Failed to assign an upstream for this request", err)
 		h.Parent.logRequest(r, false, 521, "subdomain-http", r.URL.Hostname())
 		return
 	}
@@ -178,11 +178,10 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
 	if err != nil {
 		if errors.As(err, &dnsError) {
 			http.ServeFile(w, r, "./web/hosterror.html")
-			log.Println(err.Error())
 			h.Parent.logRequest(r, false, 404, "host-http", r.URL.Hostname())
 		} else {
 			http.ServeFile(w, r, "./web/rperror.html")
-			log.Println(err.Error())
+			//TODO: Take this upstream offline automatically
 			h.Parent.logRequest(r, false, 521, "host-http", r.URL.Hostname())
 		}
 	}

+ 5 - 0
mod/dynamicproxy/router.go

@@ -70,6 +70,11 @@ func (router *Router) PrepareProxyRoute(endpoint *ProxyEndpoint) (*ProxyEndpoint
 
 // Add Proxy Route to current runtime. Call to PrepareProxyRoute before adding to runtime
 func (router *Router) AddProxyRouteToRuntime(endpoint *ProxyEndpoint) error {
+	if len(endpoint.ActiveOrigins) == 0 {
+		//There are no active origins. No need to check for ready
+		router.ProxyEndpoints.Store(endpoint.RootOrMatchingDomain, endpoint)
+		return nil
+	}
 	if !router.loadBalancer.UpstreamsReady(endpoint.ActiveOrigins) {
 		//This endpoint is not prepared
 		return errors.New("proxy endpoint not ready. Use PrepareProxyRoute before adding to runtime")

+ 29 - 21
mod/utils/utils.go

@@ -41,12 +41,12 @@ func SendOK(w http.ResponseWriter) {
 
 // Get GET parameter
 func GetPara(r *http.Request, key string) (string, error) {
-	keys, ok := r.URL.Query()[key]
-	if !ok || len(keys[0]) < 1 {
+	// Get first value from the URL query
+	value := r.URL.Query().Get(key)
+	if len(value) == 0 {
 		return "", errors.New("invalid " + key + " given")
-	} else {
-		return keys[0], nil
 	}
+	return value, nil
 }
 
 // Get GET paramter as boolean, accept 1 or true
@@ -56,26 +56,29 @@ func GetBool(r *http.Request, key string) (bool, error) {
 		return false, err
 	}
 
-	x = strings.TrimSpace(x)
-
-	if x == "1" || strings.ToLower(x) == "true" || strings.ToLower(x) == "on" {
+	// Convert to lowercase and trim spaces just once to compare
+	switch strings.ToLower(strings.TrimSpace(x)) {
+	case "1", "true", "on":
 		return true, nil
-	} else if x == "0" || strings.ToLower(x) == "false" || strings.ToLower(x) == "off" {
+	case "0", "false", "off":
 		return false, nil
 	}
 
 	return false, errors.New("invalid boolean given")
 }
 
-// Get POST paramter
+// Get POST parameter
 func PostPara(r *http.Request, key string) (string, error) {
-	r.ParseForm()
+	// Try to parse the form
+	if err := r.ParseForm(); err != nil {
+		return "", err
+	}
+	// Get first value from the form
 	x := r.Form.Get(key)
-	if x == "" {
+	if len(x) == 0 {
 		return "", errors.New("invalid " + key + " given")
-	} else {
-		return x, nil
 	}
+	return x, nil
 }
 
 // Get POST paramter as boolean, accept 1 or true
@@ -85,11 +88,11 @@ func PostBool(r *http.Request, key string) (bool, error) {
 		return false, err
 	}
 
-	x = strings.TrimSpace(x)
-
-	if x == "1" || strings.ToLower(x) == "true" || strings.ToLower(x) == "on" {
+	// Convert to lowercase and trim spaces just once to compare
+	switch strings.ToLower(strings.TrimSpace(x)) {
+	case "1", "true", "on":
 		return true, nil
-	} else if x == "0" || strings.ToLower(x) == "false" || strings.ToLower(x) == "off" {
+	case "0", "false", "off":
 		return false, nil
 	}
 
@@ -114,14 +117,19 @@ func PostInt(r *http.Request, key string) (int, error) {
 
 func FileExists(filename string) bool {
 	_, err := os.Stat(filename)
-	if os.IsNotExist(err) {
+	if err == nil {
+		// File exists
+		return true
+	} else if errors.Is(err, os.ErrNotExist) {
+		// File does not exist
 		return false
 	}
-	return true
+	// Some other error
+	return false
 }
 
 func IsDir(path string) bool {
-	if FileExists(path) == false {
+	if !FileExists(path) {
 		return false
 	}
 	fi, err := os.Stat(path)
@@ -191,4 +199,4 @@ func ValidateListeningAddress(address string) bool {
 	}
 
 	return true
-}
+}

+ 0 - 2
reverseproxy.go

@@ -910,7 +910,6 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
 		results := []*dynamicproxy.ProxyEndpoint{}
 		dynamicProxyRouter.ProxyEndpoints.Range(func(key, value interface{}) bool {
 			thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
-
 			//Clear the auth passwords before showing to front-end
 			cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
 			for _, user := range thisEndpoint.BasicAuthCredentials {
@@ -919,7 +918,6 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
 					PasswordHash: "",
 				})
 			}
-
 			thisEndpoint.BasicAuthCredentials = cleanedCredentials
 			results = append(results, thisEndpoint)
 			return true