package loadbalancer import ( "encoding/hex" "net/http" "strings" "time" "unsafe" "github.com/bytedance/gopkg/util/xxhash3" "github.com/yusing/godoxy/internal/types" ) func hashServerKey(key string) string { h := xxhash3.HashString(key) as8bytes := *(*[8]byte)(unsafe.Pointer(&h)) return hex.EncodeToString(as8bytes[:]) } // getStickyServer extracts the sticky session cookie and returns the corresponding server func getStickyServer(r *http.Request, srvs []types.LoadBalancerServer) types.LoadBalancerServer { cookie, err := r.Cookie("godoxy_lb_sticky") if err != nil { return nil } serverKeyHash := cookie.Value for _, srv := range srvs { if hashServerKey(srv.Key()) == serverKeyHash { return srv } } return nil } // setStickyCookie sets a cookie to maintain sticky session with a specific server func setStickyCookie(rw http.ResponseWriter, r *http.Request, srv types.LoadBalancerServer, maxAge time.Duration) { http.SetCookie(rw, &http.Cookie{ Name: "godoxy_lb_sticky", Value: hashServerKey(srv.Key()), Path: "/", MaxAge: int(maxAge.Seconds()), SameSite: http.SameSiteLaxMode, HttpOnly: true, Secure: isSecure(r), }) } func isSecure(r *http.Request) bool { return r.TLS != nil || strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https") }