diff --git a/roundrobin/rebalancer_test.go b/roundrobin/rebalancer_test.go index 46bde460..d0ee7c96 100644 --- a/roundrobin/rebalancer_test.go +++ b/roundrobin/rebalancer_test.go @@ -345,7 +345,7 @@ func (s *RBSuite) TestRebalancerStickySession(c *C) { defer b.Close() defer x.Close() - sticky := NewStickySession("test") + sticky := NewStickySession("test", nil) c.Assert(sticky, NotNil) fwd, err := forward.New() @@ -367,7 +367,7 @@ func (s *RBSuite) TestRebalancerStickySession(c *C) { for i := 0; i < 10; i++ { req, err := http.NewRequest(http.MethodGet, proxy.URL, nil) c.Assert(err, IsNil) - req.AddCookie(&http.Cookie{Name: "test", Value: a.URL}) + req.AddCookie(&http.Cookie{Name: "test", Value: MD5(a.URL, defaultSalt)}) resp, err := http.DefaultClient.Do(req) c.Assert(err, IsNil) diff --git a/roundrobin/stickysessions.go b/roundrobin/stickysessions.go index 3fabeb97..3fa8efb1 100644 --- a/roundrobin/stickysessions.go +++ b/roundrobin/stickysessions.go @@ -2,16 +2,62 @@ package roundrobin import ( + "crypto/md5" + "fmt" "net/http" "net/url" ) +var ( + defaultSalt = "vulcand/oxy" + defaultObfuscator = &MD5Obfucator{salt: defaultSalt, data: make(map[string]string)} +) + +type Obfuscator interface { + Obfuscate(string) string + Normalize(string) string +} + +// md5Table stores two mappings, one is plaintext to md5, the other is md5 to plaintext +type MD5Obfucator struct { + salt string + data map[string]string +} + +func MD5(text, salt string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(text+salt))) +} + +func (m *MD5Obfucator) Obfuscate(text string) string { + v, ok := m.data[text] + if ok { + return v + } + + md5_value := MD5(text, m.salt) + m.data[md5_value] = text + m.data[text] = md5_value + return md5_value +} + +func (m *MD5Obfucator) Normalize(md5_value string) string { + v, ok := m.data[md5_value] + if !ok { + return "" + } + return v +} + type StickySession struct { cookieName string + obfuscator Obfuscator } -func NewStickySession(cookieName string) *StickySession { - return &StickySession{cookieName} +func NewStickySession(cookieName string, o Obfuscator) *StickySession { + if o == nil { + o = defaultObfuscator + } + return &StickySession{cookieName: cookieName, obfuscator: o} } // GetBackend returns the backend URL stored in the sticky cookie, iff the backend is still in the valid list of servers. @@ -24,8 +70,8 @@ func (s *StickySession) GetBackend(req *http.Request, servers []*url.URL) (*url. default: return nil, false, err } - - serverURL, err := url.Parse(cookie.Value) + backend := s.obfuscator.Normalize(cookie.Value) + serverURL, err := url.Parse(backend) if err != nil { return nil, false, err } @@ -38,7 +84,8 @@ func (s *StickySession) GetBackend(req *http.Request, servers []*url.URL) (*url. } func (s *StickySession) StickBackend(backend *url.URL, w *http.ResponseWriter) { - cookie := &http.Cookie{Name: s.cookieName, Value: backend.String(), Path: "/"} + cookieValue := s.obfuscator.Obfuscate(backend.String()) + cookie := &http.Cookie{Name: s.cookieName, Value: cookieValue, Path: "/"} http.SetCookie(*w, cookie) } diff --git a/roundrobin/stickysessions_test.go b/roundrobin/stickysessions_test.go index 08f49391..96465de6 100644 --- a/roundrobin/stickysessions_test.go +++ b/roundrobin/stickysessions_test.go @@ -28,7 +28,7 @@ func (s *StickySessionSuite) TestBasic(c *C) { fwd, err := forward.New() c.Assert(err, IsNil) - sticky := NewStickySession("test") + sticky := NewStickySession("test", nil) c.Assert(sticky, NotNil) lb, err := New(fwd, EnableStickySession(sticky)) @@ -47,7 +47,7 @@ func (s *StickySessionSuite) TestBasic(c *C) { for i := 0; i < 10; i++ { req, err := http.NewRequest(http.MethodGet, proxy.URL, nil) c.Assert(err, IsNil) - req.AddCookie(&http.Cookie{Name: "test", Value: a.URL}) + req.AddCookie(&http.Cookie{Name: "test", Value: MD5(a.URL, defaultSalt)}) resp, err := client.Do(req) c.Assert(err, IsNil) @@ -70,7 +70,7 @@ func (s *StickySessionSuite) TestStickCookie(c *C) { fwd, err := forward.New() c.Assert(err, IsNil) - sticky := NewStickySession("test") + sticky := NewStickySession("test", nil) c.Assert(sticky, NotNil) lb, err := New(fwd, EnableStickySession(sticky)) @@ -89,7 +89,7 @@ func (s *StickySessionSuite) TestStickCookie(c *C) { cookie := resp.Cookies()[0] c.Assert(cookie.Name, Equals, "test") - c.Assert(cookie.Value, Equals, a.URL) + c.Assert(cookie.Value, Equals, MD5(a.URL, defaultSalt)) } func (s *StickySessionSuite) TestRemoveRespondingServer(c *C) { @@ -102,7 +102,7 @@ func (s *StickySessionSuite) TestRemoveRespondingServer(c *C) { fwd, err := forward.New() c.Assert(err, IsNil) - sticky := NewStickySession("test") + sticky := NewStickySession("test", nil) c.Assert(sticky, NotNil) lb, err := New(fwd, EnableStickySession(sticky)) @@ -121,7 +121,7 @@ func (s *StickySessionSuite) TestRemoveRespondingServer(c *C) { for i := 0; i < 10; i++ { req, errReq := http.NewRequest(http.MethodGet, proxy.URL, nil) c.Assert(errReq, IsNil) - req.AddCookie(&http.Cookie{Name: "test", Value: a.URL}) + req.AddCookie(&http.Cookie{Name: "test", Value: MD5(a.URL, defaultSalt)}) resp, errReq := client.Do(req) c.Assert(errReq, IsNil) @@ -139,12 +139,12 @@ func (s *StickySessionSuite) TestRemoveRespondingServer(c *C) { // Now, use the organic cookie response in our next requests. req, err := http.NewRequest(http.MethodGet, proxy.URL, nil) c.Assert(err, IsNil) - req.AddCookie(&http.Cookie{Name: "test", Value: a.URL}) + req.AddCookie(&http.Cookie{Name: "test", Value: MD5(a.URL, defaultSalt)}) resp, err := client.Do(req) c.Assert(err, IsNil) c.Assert(resp.Cookies()[0].Name, Equals, "test") - c.Assert(resp.Cookies()[0].Value, Equals, b.URL) + c.Assert(resp.Cookies()[0].Value, Equals, MD5(b.URL, defaultSalt)) for i := 0; i < 10; i++ { req, err := http.NewRequest(http.MethodGet, proxy.URL, nil) @@ -171,7 +171,7 @@ func (s *StickySessionSuite) TestRemoveAllServers(c *C) { fwd, err := forward.New() c.Assert(err, IsNil) - sticky := NewStickySession("test") + sticky := NewStickySession("test", nil) c.Assert(sticky, NotNil) lb, err := New(fwd, EnableStickySession(sticky)) @@ -190,7 +190,7 @@ func (s *StickySessionSuite) TestRemoveAllServers(c *C) { for i := 0; i < 10; i++ { req, errReq := http.NewRequest(http.MethodGet, proxy.URL, nil) c.Assert(errReq, IsNil) - req.AddCookie(&http.Cookie{Name: "test", Value: a.URL}) + req.AddCookie(&http.Cookie{Name: "test", Value: MD5(a.URL, defaultSalt)}) resp, errReq := client.Do(req) c.Assert(errReq, IsNil) @@ -210,7 +210,7 @@ func (s *StickySessionSuite) TestRemoveAllServers(c *C) { // Now, use the organic cookie response in our next requests. req, err := http.NewRequest(http.MethodGet, proxy.URL, nil) c.Assert(err, IsNil) - req.AddCookie(&http.Cookie{Name: "test", Value: a.URL}) + req.AddCookie(&http.Cookie{Name: "test", Value: MD5(a.URL, defaultSalt)}) resp, err := client.Do(req) c.Assert(err, IsNil) c.Assert(resp.StatusCode, Equals, http.StatusInternalServerError) @@ -224,7 +224,7 @@ func (s *StickySessionSuite) TestBadCookieVal(c *C) { fwd, err := forward.New() c.Assert(err, IsNil) - sticky := NewStickySession("test") + sticky := NewStickySession("test", nil) c.Assert(sticky, NotNil) lb, err := New(fwd, EnableStickySession(sticky))