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.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. "container/list"
  7. "encoding/json"
  8. "fmt"
  9. "sync"
  10. "gitea.com/macaron/session"
  11. couchbase "gitea.com/macaron/session/couchbase"
  12. memcache "gitea.com/macaron/session/memcache"
  13. mysql "gitea.com/macaron/session/mysql"
  14. nodb "gitea.com/macaron/session/nodb"
  15. postgres "gitea.com/macaron/session/postgres"
  16. redis "gitea.com/macaron/session/redis"
  17. )
  18. // VirtualSessionProvider represents a shadowed session provider implementation.
  19. type VirtualSessionProvider struct {
  20. lock sync.RWMutex
  21. provider session.Provider
  22. }
  23. // Init initializes the cookie session provider with given root path.
  24. func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
  25. var opts session.Options
  26. if err := json.Unmarshal([]byte(config), &opts); err != nil {
  27. return err
  28. }
  29. // Note that these options are unprepared so we can't just use NewManager here.
  30. // Nor can we access the provider map in session.
  31. // So we will just have to do this by hand.
  32. // This is only slightly more wrong than modules/setting/session.go:23
  33. switch opts.Provider {
  34. case "memory":
  35. o.provider = &MemProvider{list: list.New(), data: make(map[string]*list.Element)}
  36. case "file":
  37. o.provider = &session.FileProvider{}
  38. case "redis":
  39. o.provider = &redis.RedisProvider{}
  40. case "mysql":
  41. o.provider = &mysql.MysqlProvider{}
  42. case "postgres":
  43. o.provider = &postgres.PostgresProvider{}
  44. case "couchbase":
  45. o.provider = &couchbase.CouchbaseProvider{}
  46. case "memcache":
  47. o.provider = &memcache.MemcacheProvider{}
  48. case "nodb":
  49. o.provider = &nodb.NodbProvider{}
  50. default:
  51. return fmt.Errorf("VirtualSessionProvider: Unknown Provider: %s", opts.Provider)
  52. }
  53. return o.provider.Init(gclifetime, opts.ProviderConfig)
  54. }
  55. // Read returns raw session store by session ID.
  56. func (o *VirtualSessionProvider) Read(sid string) (session.RawStore, error) {
  57. o.lock.RLock()
  58. defer o.lock.RUnlock()
  59. if o.provider.Exist(sid) {
  60. return o.provider.Read(sid)
  61. }
  62. kv := make(map[interface{}]interface{})
  63. kv["_old_uid"] = "0"
  64. return NewVirtualStore(o, sid, kv), nil
  65. }
  66. // Exist returns true if session with given ID exists.
  67. func (o *VirtualSessionProvider) Exist(sid string) bool {
  68. return true
  69. }
  70. // Destroy deletes a session by session ID.
  71. func (o *VirtualSessionProvider) Destroy(sid string) error {
  72. o.lock.Lock()
  73. defer o.lock.Unlock()
  74. return o.provider.Destroy(sid)
  75. }
  76. // Regenerate regenerates a session store from old session ID to new one.
  77. func (o *VirtualSessionProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
  78. o.lock.Lock()
  79. defer o.lock.Unlock()
  80. return o.provider.Regenerate(oldsid, sid)
  81. }
  82. // Count counts and returns number of sessions.
  83. func (o *VirtualSessionProvider) Count() int {
  84. o.lock.RLock()
  85. defer o.lock.RUnlock()
  86. return o.provider.Count()
  87. }
  88. // GC calls GC to clean expired sessions.
  89. func (o *VirtualSessionProvider) GC() {
  90. o.provider.GC()
  91. }
  92. func init() {
  93. session.Register("VirtualSession", &VirtualSessionProvider{})
  94. }
  95. // VirtualStore represents a virtual session store implementation.
  96. type VirtualStore struct {
  97. p *VirtualSessionProvider
  98. sid string
  99. lock sync.RWMutex
  100. data map[interface{}]interface{}
  101. released bool
  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 !s.released && 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. if err := realStore.Flush(); err != nil {
  154. return err
  155. }
  156. for key, value := range s.data {
  157. if err := realStore.Set(key, value); err != nil {
  158. return err
  159. }
  160. }
  161. err = realStore.Release()
  162. if err == nil {
  163. s.released = true
  164. }
  165. return err
  166. }
  167. return nil
  168. }
  169. // Flush deletes all session data.
  170. func (s *VirtualStore) Flush() error {
  171. s.lock.Lock()
  172. defer s.lock.Unlock()
  173. s.data = make(map[interface{}]interface{})
  174. return nil
  175. }