Fix concurrent map bug in session handling (See #590)

pull/1082/head
James Mills 2 weeks ago
parent 60acef3ddd
commit f5a9213e8a
Signed by: prologic
GPG Key ID: AC4C014F1440EBD6
  1. 59
      internal/session/session.go
  2. 2
      internal/session/sid.go
  3. 2
      internal/session/sid_test.go

@ -6,6 +6,8 @@ package session
import (
"encoding/json"
"time"
sync "github.com/sasha-s/go-deadlock"
)
// Map ...
@ -13,6 +15,7 @@ type Map map[string]string
// Session ...
type Session struct {
sync.RWMutex
store Store
ID string `json:"id"`
@ -62,43 +65,55 @@ func LoadSession(data []byte, sess *Session) error {
return nil
}
func (sess *Session) Expired() bool {
return sess.ExpiresAt.Before(time.Now())
func (s *Session) Expired() bool {
s.RLock()
defer s.RUnlock()
return s.ExpiresAt.Before(time.Now())
}
func (sess *Session) Set(key, val string) error {
sess.Data[key] = val
if sess.trulyNeededCallback != nil {
sess.trulyNeededCallback()
sess.trulyNeededCallback = nil
func (s *Session) Set(key, val string) error {
s.Lock()
s.Data[key] = val
s.Unlock()
if s.trulyNeededCallback != nil {
s.trulyNeededCallback()
s.trulyNeededCallback = nil
}
return sess.store.SyncSession(sess)
return s.store.SyncSession(s)
}
func (sess *Session) Get(key string) (val string, ok bool) {
val, ok = sess.Data[key]
func (s *Session) Get(key string) (val string, ok bool) {
s.RLock()
defer s.RUnlock()
val, ok = s.Data[key]
return
}
func (sess *Session) Has(key string) bool {
_, ok := sess.Data[key]
func (s *Session) Has(key string) bool {
s.RLock()
defer s.RUnlock()
_, ok := s.Data[key]
return ok
}
func (sess *Session) Del(key string) error {
delete(sess.Data, key)
if len(sess.Data) == 0 {
if sess.trulyRemovableCallback != nil {
sess.trulyRemovableCallback()
sess.trulyRemovableCallback = nil
func (s *Session) Del(key string) error {
s.Lock()
delete(s.Data, key)
s.Unlock()
if len(s.Data) == 0 {
if s.trulyRemovableCallback != nil {
s.trulyRemovableCallback()
s.trulyRemovableCallback = nil
}
return sess.store.DelSession(sess.ID)
return s.store.DelSession(s.ID)
}
return sess.store.SyncSession(sess)
return s.store.SyncSession(s)
}
func (sess *Session) Bytes() ([]byte, error) {
data, err := json.Marshal(sess)
func (s *Session) Bytes() ([]byte, error) {
s.RLock()
defer s.RUnlock()
data, err := json.Marshal(s)
if err != nil {
return nil, err
}

@ -21,7 +21,7 @@ const signedLength = idLength + sha256.Size
type ID string
// ErrInvalidID is returned when an invalid session id is passed to ValidateID()
var ErrInvalidID = errors.New("Invalid Session ID")
var ErrInvalidID = errors.New("error: invalid session id")
// NewSessionID creates and returns a new digitally-signed session ID,
// using `signingKey` as the HMAC signing key. An error is returned only

@ -18,7 +18,7 @@ func TestNewID(t *testing.T) {
t.Fatal(err)
}
if 0 == len(sid) {
if len(sid) == 0 {
t.Errorf("Signed ID string was empty")
}

Loading…
Cancel
Save