Skip to content

Commit dae9d31

Browse files
committed
Fix panic 500 page rendering
1 parent 19b8e51 commit dae9d31

File tree

14 files changed

+1283
-9
lines changed

14 files changed

+1283
-9
lines changed

modules/middlewares/redis.go

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// Copyright 2013 Beego Authors
2+
// Copyright 2014 The Macaron Authors
3+
// Copyright 2020 The Gitea Authors. All rights reserved.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License"): you may
6+
// not use this file except in compliance with the License. You may obtain
7+
// a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
// License for the specific language governing permissions and limitations
15+
// under the License.
16+
17+
package middlewares
18+
19+
import (
20+
"fmt"
21+
"sync"
22+
"time"
23+
24+
"code.gitea.io/gitea/modules/nosql"
25+
26+
"gitea.com/go-chi/session"
27+
"github.com/go-redis/redis/v7"
28+
)
29+
30+
// RedisStore represents a redis session store implementation.
31+
type RedisStore struct {
32+
c redis.UniversalClient
33+
prefix, sid string
34+
duration time.Duration
35+
lock sync.RWMutex
36+
data map[interface{}]interface{}
37+
}
38+
39+
// NewRedisStore creates and returns a redis session store.
40+
func NewRedisStore(c redis.UniversalClient, prefix, sid string, dur time.Duration, kv map[interface{}]interface{}) *RedisStore {
41+
return &RedisStore{
42+
c: c,
43+
prefix: prefix,
44+
sid: sid,
45+
duration: dur,
46+
data: kv,
47+
}
48+
}
49+
50+
// Set sets value to given key in session.
51+
func (s *RedisStore) Set(key, val interface{}) error {
52+
s.lock.Lock()
53+
defer s.lock.Unlock()
54+
55+
s.data[key] = val
56+
return nil
57+
}
58+
59+
// Get gets value by given key in session.
60+
func (s *RedisStore) Get(key interface{}) interface{} {
61+
s.lock.RLock()
62+
defer s.lock.RUnlock()
63+
64+
return s.data[key]
65+
}
66+
67+
// Delete delete a key from session.
68+
func (s *RedisStore) Delete(key interface{}) error {
69+
s.lock.Lock()
70+
defer s.lock.Unlock()
71+
72+
delete(s.data, key)
73+
return nil
74+
}
75+
76+
// ID returns current session ID.
77+
func (s *RedisStore) ID() string {
78+
return s.sid
79+
}
80+
81+
// Release releases resource and save data to provider.
82+
func (s *RedisStore) Release() error {
83+
// Skip encoding if the data is empty
84+
if len(s.data) == 0 {
85+
return nil
86+
}
87+
88+
data, err := session.EncodeGob(s.data)
89+
if err != nil {
90+
return err
91+
}
92+
93+
return s.c.Set(s.prefix+s.sid, string(data), s.duration).Err()
94+
}
95+
96+
// Flush deletes all session data.
97+
func (s *RedisStore) Flush() error {
98+
s.lock.Lock()
99+
defer s.lock.Unlock()
100+
101+
s.data = make(map[interface{}]interface{})
102+
return nil
103+
}
104+
105+
// RedisProvider represents a redis session provider implementation.
106+
type RedisProvider struct {
107+
c redis.UniversalClient
108+
duration time.Duration
109+
prefix string
110+
}
111+
112+
// Init initializes redis session provider.
113+
// configs: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180,prefix=session;
114+
func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) {
115+
p.duration, err = time.ParseDuration(fmt.Sprintf("%ds", maxlifetime))
116+
if err != nil {
117+
return err
118+
}
119+
120+
uri := nosql.ToRedisURI(configs)
121+
122+
for k, v := range uri.Query() {
123+
switch k {
124+
case "prefix":
125+
p.prefix = v[0]
126+
}
127+
}
128+
129+
p.c = nosql.GetManager().GetRedisClient(uri.String())
130+
return p.c.Ping().Err()
131+
}
132+
133+
// Read returns raw session store by session ID.
134+
func (p *RedisProvider) Read(sid string) (session.RawStore, error) {
135+
psid := p.prefix + sid
136+
if !p.Exist(sid) {
137+
if err := p.c.Set(psid, "", p.duration).Err(); err != nil {
138+
return nil, err
139+
}
140+
}
141+
142+
var kv map[interface{}]interface{}
143+
kvs, err := p.c.Get(psid).Result()
144+
if err != nil {
145+
return nil, err
146+
}
147+
if len(kvs) == 0 {
148+
kv = make(map[interface{}]interface{})
149+
} else {
150+
kv, err = session.DecodeGob([]byte(kvs))
151+
if err != nil {
152+
return nil, err
153+
}
154+
}
155+
156+
return NewRedisStore(p.c, p.prefix, sid, p.duration, kv), nil
157+
}
158+
159+
// Exist returns true if session with given ID exists.
160+
func (p *RedisProvider) Exist(sid string) bool {
161+
v, err := p.c.Exists(p.prefix + sid).Result()
162+
return err == nil && v == 1
163+
}
164+
165+
// Destroy deletes a session by session ID.
166+
func (p *RedisProvider) Destroy(sid string) error {
167+
return p.c.Del(p.prefix + sid).Err()
168+
}
169+
170+
// Regenerate regenerates a session store from old session ID to new one.
171+
func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
172+
poldsid := p.prefix + oldsid
173+
psid := p.prefix + sid
174+
175+
if p.Exist(sid) {
176+
return nil, fmt.Errorf("new sid '%s' already exists", sid)
177+
} else if !p.Exist(oldsid) {
178+
// Make a fake old session.
179+
if err = p.c.Set(poldsid, "", p.duration).Err(); err != nil {
180+
return nil, err
181+
}
182+
}
183+
184+
if err = p.c.Rename(poldsid, psid).Err(); err != nil {
185+
return nil, err
186+
}
187+
188+
var kv map[interface{}]interface{}
189+
kvs, err := p.c.Get(psid).Result()
190+
if err != nil {
191+
return nil, err
192+
}
193+
194+
if len(kvs) == 0 {
195+
kv = make(map[interface{}]interface{})
196+
} else {
197+
kv, err = session.DecodeGob([]byte(kvs))
198+
if err != nil {
199+
return nil, err
200+
}
201+
}
202+
203+
return NewRedisStore(p.c, p.prefix, sid, p.duration, kv), nil
204+
}
205+
206+
// Count counts and returns number of sessions.
207+
func (p *RedisProvider) Count() int {
208+
return int(p.c.DBSize().Val())
209+
}
210+
211+
// GC calls GC to clean expired sessions.
212+
func (*RedisProvider) GC() {}
213+
214+
func init() {
215+
session.Register("redis", &RedisProvider{})
216+
}

0 commit comments

Comments
 (0)