Skip to content

Commit

Permalink
Donn't override old value when seting same value
Browse files Browse the repository at this point in the history
  • Loading branch information
pengwei committed Feb 11, 2017
1 parent 5adcb1e commit 93b8e7d
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 90 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ go run cookiesession/main.go
```
##Usage
```go
store := sessions.New([]string{"key"})
store := sessions.NewCookieStore([]string{"key"})
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store.Init(w, r, false)
session, _ := sessions.Get(sessionkey, store)
session, _ := store.Get(sessionkey, w, r)
session.Values["name"] = "mushroom"
session.Values["name"] = "mushroom"
println(session.Values["name"].(string)) //get session
session.Save()
Expand Down
9 changes: 4 additions & 5 deletions cookiesession/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ func main() {

sessionkey := "sessionid"

store := sessions.NewCookieStore([]string{"key"})

req, _ := http.NewRequest("GET", "/", nil)

recorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

store := sessions.NewCookieStore([]string{"key"})

session, _ := sessions.New(sessionkey, store, w, r)
session, _ := store.Get(sessionkey, w, r)

session.Values["name"] = "mushroom"

Expand All @@ -31,9 +31,8 @@ func main() {
cookies, _ := getCookie(sessionkey, recorder)
req.AddCookie(cookies)
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"key"})

session, _ := sessions.New(sessionkey, store, w, r)
session, _ := store.Get(sessionkey, w, r)

println(session.Values["name"].(string))
})
Expand Down
36 changes: 19 additions & 17 deletions cookiestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,34 +35,35 @@ func NewCookieStore(Keys []string, options ...*Options) (store *CookieStore) {

// CookieStore stores sessions using secure cookies.
type CookieStore struct {
cookie *cookie.Cookies
options *Options
keys []string
signed bool // optional
}

// Init an CookieStore instance
func (c *CookieStore) Init(w http.ResponseWriter, r *http.Request, signed bool) {
c.cookie = cookie.New(w, r, c.keys)
c.signed = signed
return
}

// Get existed session from Request's cookies
func (c *CookieStore) Get(name string) (data map[string]interface{}, err error) {
val, _ := c.cookie.Get(name, c.signed)
// Get a session instance by name and any kind of stores
func (c *CookieStore) Get(name string, w http.ResponseWriter, r *http.Request, signed ...bool) (session *Session, err error) {
b := false
if len(signed) > 0 {
b = signed[0]
}
session = NewSession(name, c, w, r, b)
cookie := cookie.New(nil, r, c.keys)
val, _ := cookie.Get(name, b)
if val != "" {
Decode(val, &data)
Decode(val, &session.Values)
}
session.SetCache(session.Values)
return
}

// Save session to Response's cookie
func (c *CookieStore) Save(name string, data map[string]interface{}) (err error) {
func (c *CookieStore) Save(w http.ResponseWriter, r *http.Request, session *Session) (err error) {
if session.IsCache() {
return
}
opts := &cookie.Options{
Path: "/",
HTTPOnly: true,
Signed: c.signed,
Signed: session.IsSigned(),
MaxAge: 24 * 60 * 60,
}
if c.options != nil {
Expand All @@ -72,9 +73,10 @@ func (c *CookieStore) Save(name string, data map[string]interface{}) (err error)
opts.Secure = c.options.Secure
opts.HTTPOnly = c.options.HTTPOnly
}
val, err := Encode(data)
val, err := Encode(session.Values)
if err == nil {
c.cookie.Set(name, val, opts)
cookie := cookie.New(w, r, c.keys)
cookie.Set(session.Name(), val, opts)
}
return
}
82 changes: 39 additions & 43 deletions sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,31 @@ import (
"encoding/base64"
"encoding/json"
"net/http"
"reflect"
)

// Session stores the values and optional configuration for a session.
type Session struct {
sid string
Values map[string]interface{}
store Store
name string
//oldval string
Values map[string]interface{}
store Store
name string
signed bool
lastVal map[string]interface{}
req *http.Request
w http.ResponseWriter
}

// NewSession to create new session instance
func NewSession(name string, store Store, w http.ResponseWriter, r *http.Request, signed bool) (session *Session) {
session = &Session{
Values: make(map[string]interface{}),
store: store,
name: name,
signed: signed,
req: r,
w: w,
}
return
}

// Name returns the name used to register the session
Expand All @@ -25,50 +41,32 @@ func (s *Session) Store() Store {
return s.store
}

// New a session instance by name and any kind of stores
func New(name string, store Store, w http.ResponseWriter, r *http.Request, signed ...bool) (session *Session, err error) {
session = &Session{
store: store,
name: name,
}
var issigned = false
if len(signed) > 0 {
issigned = signed[0]
}
store.Init(w, r, issigned)
session.Values, err = store.Get(name)

if session.Values == nil {
session.Values = make(map[string]interface{})
}
return
// IsSigned to check if setting sign for data
func (s *Session) IsSigned() bool {
return s.signed
}

// New a new session instance by name base on current store
func (s *Session) New(name string) *Session {
session := &Session{
Values: make(map[string]interface{}),
store: s.store,
name: name,
// SetCache to set the last data to session
func (s *Session) SetCache(cache map[string]interface{}) {
s.lastVal = make(map[string]interface{})
for k, v := range cache {
s.lastVal[k] = v
}
return session
}

// Get a new session instance by name base on current store
func (s *Session) Get(name string) (session *Session, err error) {
session = &Session{
// IsCache to check the data whether there's any modification by comparing with old data
func (s *Session) IsCache() bool {
return reflect.DeepEqual(s.lastVal, s.Values)
}

Values: make(map[string]interface{}),
store: s.store,
name: name,
}
session.Values, err = s.store.Get(session.name)
return
// New a session instance by name base on current store
func (s *Session) New(name string) (*Session, error) {
return s.store.Get(name, s.w, s.req, s.signed)
}

// Save is a convenience method to save current session
func (s *Session) Save() (err error) {
s.store.Save(s.name, s.Values)
s.store.Save(s.w, s.req, s)
return
}

Expand Down Expand Up @@ -97,11 +95,9 @@ func Decode(value string, dst interface{}) (err error) {

// Store is an interface for custom session stores.
type Store interface {
Init(w http.ResponseWriter, r *http.Request, signed bool)

// Get should return a cached session string.
Get(name string) (map[string]interface{}, error)
Get(name string, w http.ResponseWriter, r *http.Request, signed ...bool) (session *Session, err error)

// Save should persist session to the underlying store implementation.
Save(name string, data map[string]interface{}) error
Save(w http.ResponseWriter, r *http.Request, session *Session) error
}
71 changes: 49 additions & 22 deletions sessions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (

func TestSessions(t *testing.T) {

store := sessions.NewCookieStore([]string{"key"})

cookiekey := "teambition"
cookieNewKey := "teambition-new"
t.Run("Sessions use default options that should be", func(t *testing.T) {
Expand All @@ -19,27 +21,25 @@ func TestSessions(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"key"})
session, _ := sessions.New(cookiekey, store, w, r)

session, _ := store.Get(cookiekey, w, r)
session.Values["name"] = "mushroom"
session.Values["num"] = 99
session.Save()

err = session.Save()
assert.Nil(err)
})
handler.ServeHTTP(recorder, req)

//======reuse=====
cookies, err := getCookie(cookiekey, recorder)
assert.Nil(err)
assert.NotNil(cookies.Value)
t.Log(cookies.Value)
req, err = http.NewRequest("GET", "/", nil)

req.AddCookie(cookies)

handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"key"})
session, _ := sessions.New(cookiekey, store, w, r)
session, _ := store.Get(cookiekey, w, r)

assert.Equal("mushroom", session.Values["name"])
assert.Equal(float64(99), session.Values["num"])
Expand All @@ -50,32 +50,30 @@ func TestSessions(t *testing.T) {
req, err = http.NewRequest("GET", "/", nil)
req.AddCookie(cookies)
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"key"})
session, _ := sessions.New(cookiekey, store, w, r)
session, _ := store.Get(cookiekey, w, r)

assert.Equal("mushroom", session.Values["name"])
assert.Equal(float64(99), session.Values["num"])
})
handler.ServeHTTP(recorder, req)
})
t.Run("Sessions with New session that should be", func(t *testing.T) {
t.Run("Sessions with sign session that should be", func(t *testing.T) {
assert := assert.New(t)

recorder := httptest.NewRecorder()

req, _ := http.NewRequest("GET", "/", nil)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"key"})

session, _ := sessions.New(cookiekey, store, w, r, true)
session, err := store.Get(cookiekey, w, r, true)
session.Values["name"] = "mushroom"
session.Values["num"] = 99
session.Save()

session = session.New(cookieNewKey)
assert.Nil(err)
session, err = session.New(cookieNewKey)
session.Values["name"] = "teambition-n"
session.Values["num"] = 100
session.Save()
assert.Nil(err)
})
handler.ServeHTTP(recorder, req)

Expand All @@ -93,19 +91,18 @@ func TestSessions(t *testing.T) {
req.AddCookie(cookies)

handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"key"})
session, err := store.Get(cookiekey, w, r, true)

session, err := sessions.New(cookiekey, store, w, r, true)
assert.Nil(err)
assert.Equal("mushroom", session.Values["name"])
assert.Equal(float64(99), session.Values["num"])

session, err = session.Get(cookieNewKey)
session, err = session.New(cookieNewKey)
assert.Nil(err)
assert.Equal("teambition-n", session.Values["name"])
assert.Equal(float64(100), session.Values["num"])

session, err = session.Get(cookieNewKey + "new")
session, err = session.New(cookieNewKey + "new")
assert.Nil(err)
assert.Equal(0, len(session.Values))

Expand All @@ -128,7 +125,7 @@ func TestSessions(t *testing.T) {
Domain: "ttt.com",
Secure: true,
})
session, err := sessions.New(cookiekey, store, w, r)
session, err := store.Get(cookiekey, w, r, true)
session.Values["name"] = "mushroom"
session.Values["num"] = 99
session.Save()
Expand Down Expand Up @@ -174,9 +171,40 @@ func TestSessions(t *testing.T) {

})

t.Run("Sessions donn't override old value when seting same value that should be", func(t *testing.T) {

assert := assert.New(t)
req, err := http.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(cookiekey, w, r)
session.Values["name"] = "mushroom"
session.Values["num"] = 99
session.Save()
assert.Nil(err)
})
handler.ServeHTTP(recorder, req)

//======reuse=====
cookies, err := getCookie(cookiekey, recorder)
assert.Nil(err)
assert.NotNil(cookies.Value)
req, err = http.NewRequest("GET", "/", nil)

req.AddCookie(cookies)

handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(cookiekey, w, r)
session.Save()
assert.Nil(err)
})
handler.ServeHTTP(recorder, req)
})

}
func TestSessionCompatible(t *testing.T) {
cookiekey := "TEAMBITION_SESSIONID"
store := sessions.NewCookieStore([]string{"tb-accounts"})

t.Run("gearsession should be compatible with old session component that should be", func(t *testing.T) {
assert := assert.New(t)
Expand All @@ -185,9 +213,8 @@ func TestSessionCompatible(t *testing.T) {
req, _ := http.NewRequest("GET", "/", nil)
req.Header.Set("Cookie", "TEAMBITION_SESSIONID=eyJhdXRoVXBkYXRlZCI6MTQ4NTE1ODg3NDgxMywibmV4dFVybCI6Imh0dHA6Ly9wcm9qZWN0LmNpL3Byb2plY3RzIiwidHMiOjE0ODY2MDkzNTA5NjAsInVpZCI6IjU1YzE3MTBkZjk2YmJlODQ3NjgzMjUyYSIsInVzZXIiOnsiYXZhdGFyVXJsIjoiaHR0cDovL3N0cmlrZXIucHJvamVjdC5jaS90aHVtYm5haWwvMDEwa2UyZTMzODQ3ZjQzNzhlY2E4ZTQxMjBkYTFlMjcyZGI5L3cvMjAwL2gvMjAwIiwibmFtZSI6Iumds+aYjDAyIiwiZW1haWwiOiJjaGFuZ0BjaGFuZy5jb20iLCJfaWQiOiI1NWMxNzEwZGY5NmJiZTg0NzY4MzI1MmEiLCJpc05ldyI6dHJ1ZSwicmVnaW9uIjoiY24ifX0=; TEAMBITION_SESSIONID.sig=PfTE50ypOxA4uf09mgP9DR2IjKQ")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
store := sessions.NewCookieStore([]string{"tb-accounts"})

session, err := sessions.New(cookiekey, store, w, r, true)
session, err := store.Get(cookiekey, w, r, true)
assert.Nil(err)
assert.Equal(float64(1485158874813), session.Values["authUpdated"])
assert.Equal("55c1710df96bbe847683252a", session.Values["uid"])
Expand Down

0 comments on commit 93b8e7d

Please sign in to comment.