mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-03 06:07:20 +02:00
Optimized upstream & loadbalancer
- Test and optimized load balancer origin picker - Fixed no active origin cannot load proxy rule bug - Implemented logger design in websocket proxy module - Added more quickstart tours - Fixed #270 (I guess) - Fixed #90 (I guess)
This commit is contained in:
parent
b558bcbfcf
commit
608cc0c523
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
||||
|
||||
@ -161,6 +159,7 @@ func getRandomUpstreamByWeight(upstreams []*Upstream) (*Upstream, int, error) {
|
||||
}
|
||||
|
||||
// IntRange returns a random integer in the range from min to max.
|
||||
/*
|
||||
func intRange(min, max int) (int, error) {
|
||||
var result int
|
||||
switch {
|
||||
@ -175,3 +174,4 @@ func intRange(min, max int) (int, error) {
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
@ -144,6 +144,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
||||
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
||||
SkipTLSValidation: selectedUpstream.SkipCertValidations,
|
||||
SkipOriginCheck: selectedUpstream.SkipWebSocketOriginCheck,
|
||||
Logger: h.Parent.Option.Logger,
|
||||
})
|
||||
wspHandler.ServeHTTP(w, r)
|
||||
return
|
||||
@ -177,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())
|
||||
}
|
||||
}
|
||||
@ -212,6 +212,7 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
|
||||
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
||||
SkipTLSValidation: target.SkipCertValidations,
|
||||
SkipOriginCheck: true, //You should not use websocket via virtual directory. But keep this to true for compatibility
|
||||
Logger: h.Parent.Option.Logger,
|
||||
})
|
||||
wspHandler.ServeHTTP(w, r)
|
||||
return
|
||||
|
@ -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")
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -88,6 +88,7 @@ func (m *Manager) HandleHttpByInstanceId(instanceId string, w http.ResponseWrite
|
||||
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
||||
SkipTLSValidation: false,
|
||||
SkipOriginCheck: false,
|
||||
Logger: nil,
|
||||
})
|
||||
wspHandler.ServeHTTP(w, r)
|
||||
return
|
||||
|
@ -3,6 +3,7 @@ package websocketproxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@ -12,6 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"imuslab.com/zoraxy/mod/info/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -54,8 +56,9 @@ type WebsocketProxy struct {
|
||||
|
||||
// Additional options for websocket proxy runtime
|
||||
type Options struct {
|
||||
SkipTLSValidation bool //Skip backend TLS validation
|
||||
SkipOriginCheck bool //Skip origin check
|
||||
SkipTLSValidation bool //Skip backend TLS validation
|
||||
SkipOriginCheck bool //Skip origin check
|
||||
Logger *logger.Logger //Logger, can be nil
|
||||
}
|
||||
|
||||
// ProxyHandler returns a new http.Handler interface that reverse proxies the
|
||||
@ -78,17 +81,26 @@ func NewProxy(target *url.URL, options Options) *WebsocketProxy {
|
||||
return &WebsocketProxy{Backend: backend, Verbal: false, Options: options}
|
||||
}
|
||||
|
||||
// Utilities function for log printing
|
||||
func (w *WebsocketProxy) Println(messsage string, err error) {
|
||||
if w.Options.Logger != nil {
|
||||
w.Options.Logger.PrintAndLog("websocket", messsage, err)
|
||||
return
|
||||
}
|
||||
log.Println("[websocketproxy] [system:info]"+messsage, err)
|
||||
}
|
||||
|
||||
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
|
||||
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
if w.Backend == nil {
|
||||
log.Println("websocketproxy: backend function is not defined")
|
||||
w.Println("Invalid websocket backend configuration", errors.New("backend function not found"))
|
||||
http.Error(rw, "internal server error (code: 1)", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
backendURL := w.Backend(req)
|
||||
if backendURL == nil {
|
||||
log.Println("websocketproxy: backend URL is nil")
|
||||
w.Println("Invalid websocket backend configuration", errors.New("backend URL is nil"))
|
||||
http.Error(rw, "internal server error (code: 2)", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@ -158,13 +170,13 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
// http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-01
|
||||
connBackend, resp, err := dialer.Dial(backendURL.String(), requestHeader)
|
||||
if err != nil {
|
||||
log.Printf("websocketproxy: couldn't dial to remote backend url %s", err)
|
||||
w.Println("Couldn't dial to remote backend url "+backendURL.String(), err)
|
||||
if resp != nil {
|
||||
// If the WebSocket handshake fails, ErrBadHandshake is returned
|
||||
// along with a non-nil *http.Response so that callers can handle
|
||||
// redirects, authentication, etcetera.
|
||||
if err := copyResponse(rw, resp); err != nil {
|
||||
log.Printf("websocketproxy: couldn't write response after failed remote backend handshake: %s", err)
|
||||
w.Println("Couldn't write response after failed remote backend handshake to "+backendURL.String(), err)
|
||||
}
|
||||
} else {
|
||||
http.Error(rw, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
|
||||
@ -198,7 +210,7 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
// Also pass the header that we gathered from the Dial handshake.
|
||||
connPub, err := upgrader.Upgrade(rw, req, upgradeHeader)
|
||||
if err != nil {
|
||||
log.Printf("websocketproxy: couldn't upgrade %s", err)
|
||||
w.Println("Couldn't upgrade incoming request", err)
|
||||
return
|
||||
}
|
||||
defer connPub.Close()
|
||||
|
@ -31,6 +31,7 @@ func TestProxy(t *testing.T) {
|
||||
proxy := NewProxy(u, Options{
|
||||
SkipTLSValidation: false,
|
||||
SkipOriginCheck: false,
|
||||
Logger: nil,
|
||||
})
|
||||
proxy.Upgrader = upgrader
|
||||
|
||||
|
@ -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
|
||||
|
@ -2,8 +2,8 @@
|
||||
<div id="quickstart" class="standardContainer">
|
||||
<div class="ui container">
|
||||
<h1 class="ui header">
|
||||
<img src="img/res/1F387.png">
|
||||
<div class="content">
|
||||
<img src="img/res/1F44B.png">
|
||||
<div class="content" style="font-weight: lighter;">
|
||||
Welcome to Zoraxy!
|
||||
<div class="sub header">What services are you planning to setup today?</div>
|
||||
</div>
|
||||
|
@ -496,6 +496,7 @@ var tourSteps = {
|
||||
<br><br>Now, you can try to visit your website with https:// and see your green lock shows up next to your domain name!`,
|
||||
element: "#cert div[tourstep='certTable']",
|
||||
scrollto: "#cert div[tourstep='certTable']",
|
||||
tab: "cert",
|
||||
pos: "bottomright",
|
||||
callback: function(){
|
||||
hideSideWrapperInTourMode();
|
||||
|
Loading…
x
Reference in New Issue
Block a user