Set sameSite field for wrr load balancer sticky cookie

This commit is contained in:
Yakun Sun 2023-08-08 21:12:06 +08:00 committed by GitHub
parent ca2b9e8e77
commit d6457e6cbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 3 deletions

View file

@ -22,6 +22,20 @@ type stickyCookie struct {
name string name string
secure bool secure bool
httpOnly bool httpOnly bool
sameSite string
}
func convertSameSite(sameSite string) http.SameSite {
switch sameSite {
case "none":
return http.SameSiteNoneMode
case "lax":
return http.SameSiteLaxMode
case "strict":
return http.SameSiteStrictMode
default:
return http.SameSiteDefaultMode
}
} }
// Balancer is a WeightedRoundRobin load balancer based on Earliest Deadline First (EDF). // Balancer is a WeightedRoundRobin load balancer based on Earliest Deadline First (EDF).
@ -57,6 +71,7 @@ func New(sticky *dynamic.Sticky, wantHealthCheck bool) *Balancer {
name: sticky.Cookie.Name, name: sticky.Cookie.Name,
secure: sticky.Cookie.Secure, secure: sticky.Cookie.Secure,
httpOnly: sticky.Cookie.HTTPOnly, httpOnly: sticky.Cookie.HTTPOnly,
sameSite: sticky.Cookie.SameSite,
} }
} }
return balancer return balancer
@ -214,7 +229,14 @@ func (b *Balancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
if b.stickyCookie != nil { if b.stickyCookie != nil {
cookie := &http.Cookie{Name: b.stickyCookie.name, Value: server.name, Path: "/", HttpOnly: b.stickyCookie.httpOnly, Secure: b.stickyCookie.secure} cookie := &http.Cookie{
Name: b.stickyCookie.name,
Value: server.name,
Path: "/",
HttpOnly: b.stickyCookie.httpOnly,
Secure: b.stickyCookie.secure,
SameSite: convertSameSite(b.stickyCookie.sameSite),
}
http.SetCookie(w, cookie) http.SetCookie(w, cookie)
} }

View file

@ -220,7 +220,12 @@ func TestBalancerAllServersZeroWeight(t *testing.T) {
func TestSticky(t *testing.T) { func TestSticky(t *testing.T) {
balancer := New(&dynamic.Sticky{ balancer := New(&dynamic.Sticky{
Cookie: &dynamic.Cookie{Name: "test"}, Cookie: &dynamic.Cookie{
Name: "test",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
}, false) }, false)
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -233,7 +238,11 @@ func TestSticky(t *testing.T) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
}), Int(2)) }), Int(2))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}} recorder := &responseRecorder{
ResponseRecorder: httptest.NewRecorder(),
save: map[string]int{},
cookies: make(map[string]*http.Cookie),
}
req := httptest.NewRequest(http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
@ -247,6 +256,9 @@ func TestSticky(t *testing.T) {
assert.Equal(t, 0, recorder.save["first"]) assert.Equal(t, 0, recorder.save["first"])
assert.Equal(t, 3, recorder.save["second"]) assert.Equal(t, 3, recorder.save["second"])
assert.Equal(t, true, recorder.cookies["test"].HttpOnly)
assert.Equal(t, true, recorder.cookies["test"].Secure)
assert.Equal(t, http.SameSiteNoneMode, recorder.cookies["test"].SameSite)
} }
// TestBalancerBias makes sure that the WRR algorithm spreads elements evenly right from the start, // TestBalancerBias makes sure that the WRR algorithm spreads elements evenly right from the start,
@ -282,11 +294,15 @@ type responseRecorder struct {
save map[string]int save map[string]int
sequence []string sequence []string
status []int status []int
cookies map[string]*http.Cookie
} }
func (r *responseRecorder) WriteHeader(statusCode int) { func (r *responseRecorder) WriteHeader(statusCode int) {
r.save[r.Header().Get("server")]++ r.save[r.Header().Get("server")]++
r.sequence = append(r.sequence, r.Header().Get("server")) r.sequence = append(r.sequence, r.Header().Get("server"))
r.status = append(r.status, statusCode) r.status = append(r.status, statusCode)
for _, cookie := range r.Result().Cookies() {
r.cookies[cookie.Name] = cookie
}
r.ResponseRecorder.WriteHeader(statusCode) r.ResponseRecorder.WriteHeader(statusCode)
} }