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 4.8KB

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