You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

virtual.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package session
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "sync"
  9. "github.com/go-macaron/session"
  10. couchbase "github.com/go-macaron/session/couchbase"
  11. memcache "github.com/go-macaron/session/memcache"
  12. mysql "github.com/go-macaron/session/mysql"
  13. nodb "github.com/go-macaron/session/nodb"
  14. postgres "github.com/go-macaron/session/postgres"
  15. redis "github.com/go-macaron/session/redis"
  16. )
  17. // VirtualSessionProvider represents a shadowed session provider implementation.
  18. type VirtualSessionProvider struct {
  19. lock sync.RWMutex
  20. maxlifetime int64
  21. rootPath string
  22. provider session.Provider
  23. }
  24. // Init initializes the cookie session provider with given root path.
  25. func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
  26. var opts session.Options
  27. if err := json.Unmarshal([]byte(config), &opts); err != nil {
  28. return err
  29. }
  30. // Note that these options are unprepared so we can't just use NewManager here.
  31. // Nor can we access the provider map in session.
  32. // So we will just have to do this by hand.
  33. // This is only slightly more wrong than modules/setting/session.go:23
  34. switch opts.Provider {
  35. case "memory":
  36. o.provider = &session.MemProvider{}
  37. case "file":
  38. o.provider = &session.FileProvider{}
  39. case "redis":
  40. o.provider = &redis.RedisProvider{}
  41. case "mysql":
  42. o.provider = &mysql.MysqlProvider{}
  43. case "postgres":
  44. o.provider = &postgres.PostgresProvider{}
  45. case "couchbase":
  46. o.provider = &couchbase.CouchbaseProvider{}
  47. case "memcache":
  48. o.provider = &memcache.MemcacheProvider{}
  49. case "nodb":
  50. o.provider = &nodb.NodbProvider{}
  51. default:
  52. return fmt.Errorf("VirtualSessionProvider: Unknown Provider: %s", opts.Provider)
  53. }
  54. return o.provider.Init(gclifetime, opts.ProviderConfig)
  55. }
  56. // Read returns raw session store by session ID.
  57. func (o *VirtualSessionProvider) Read(sid string) (session.RawStore, error) {
  58. o.lock.RLock()
  59. defer o.lock.RUnlock()
  60. if o.provider.Exist(sid) {
  61. return o.provider.Read(sid)
  62. }
  63. kv := make(map[interface{}]interface{})
  64. kv["_old_uid"] = "0"
  65. return NewVirtualStore(o, sid, kv), nil
  66. }
  67. // Exist returns true if session with given ID exists.
  68. func (o *VirtualSessionProvider) Exist(sid string) bool {
  69. return true
  70. }
  71. // Destory deletes a session by session ID.
  72. func (o *VirtualSessionProvider) Destory(sid string) error {
  73. o.lock.Lock()
  74. defer o.lock.Unlock()
  75. return o.provider.Destory(sid)
  76. }
  77. // Regenerate regenerates a session store from old session ID to new one.
  78. func (o *VirtualSessionProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
  79. o.lock.Lock()
  80. defer o.lock.Unlock()
  81. return o.provider.Regenerate(oldsid, sid)
  82. }
  83. // Count counts and returns number of sessions.
  84. func (o *VirtualSessionProvider) Count() int {
  85. o.lock.RLock()
  86. defer o.lock.RUnlock()
  87. return o.provider.Count()
  88. }
  89. // GC calls GC to clean expired sessions.
  90. func (o *VirtualSessionProvider) GC() {
  91. o.provider.GC()
  92. }
  93. func init() {
  94. session.Register("VirtualSession", &VirtualSessionProvider{})
  95. }
  96. // VirtualStore represents a virtual session store implementation.
  97. type VirtualStore struct {
  98. p *VirtualSessionProvider
  99. sid string
  100. lock sync.RWMutex
  101. data map[interface{}]interface{}
  102. }
  103. // NewVirtualStore creates and returns a virtual session store.
  104. func NewVirtualStore(p *VirtualSessionProvider, sid string, kv map[interface{}]interface{}) *VirtualStore {
  105. return &VirtualStore{
  106. p: p,
  107. sid: sid,
  108. data: kv,
  109. }
  110. }
  111. // Set sets value to given key in session.
  112. func (s *VirtualStore) Set(key, val interface{}) error {
  113. s.lock.Lock()
  114. defer s.lock.Unlock()
  115. s.data[key] = val
  116. return nil
  117. }
  118. // Get gets value by given key in session.
  119. func (s *VirtualStore) Get(key interface{}) interface{} {
  120. s.lock.RLock()
  121. defer s.lock.RUnlock()
  122. return s.data[key]
  123. }
  124. // Delete delete a key from session.
  125. func (s *VirtualStore) Delete(key interface{}) error {
  126. s.lock.Lock()
  127. defer s.lock.Unlock()
  128. delete(s.data, key)
  129. return nil
  130. }
  131. // ID returns current session ID.
  132. func (s *VirtualStore) ID() string {
  133. return s.sid
  134. }
  135. // Release releases resource and save data to provider.
  136. func (s *VirtualStore) Release() error {
  137. s.lock.Lock()
  138. defer s.lock.Unlock()
  139. // Now need to lock the provider
  140. s.p.lock.Lock()
  141. defer s.p.lock.Unlock()
  142. if oldUID, ok := s.data["_old_uid"]; (ok && (oldUID != "0" || len(s.data) > 1)) || (!ok && len(s.data) > 0) {
  143. // Now ensure that we don't exist!
  144. realProvider := s.p.provider
  145. if realProvider.Exist(s.sid) {
  146. // This is an error!
  147. return fmt.Errorf("new sid '%s' already exists", s.sid)
  148. }
  149. realStore, err := realProvider.Read(s.sid)
  150. if err != nil {
  151. return err
  152. }
  153. for key, value := range s.data {
  154. if err := realStore.Set(key, value); err != nil {
  155. return err
  156. }
  157. }
  158. return realStore.Release()
  159. }
  160. return nil
  161. }
  162. // Flush deletes all session data.
  163. func (s *VirtualStore) Flush() error {
  164. s.lock.Lock()
  165. defer s.lock.Unlock()
  166. s.data = make(map[interface{}]interface{})
  167. return nil
  168. }