Skip to content

Commit fbe80e6

Browse files
authored
Add proper error message if session provider can not be created (#35520)
the middleware that creates the session provider just panics if on creation the config is wrong. this is not catched and so you just get an cryptic stacktrace with no point where to look at (as user). ## Before ``` 2025/09/16 03:56:37 ...xer/stats/indexer.go:87:populateRepoIndexer() [I] Done (re)populating the repo stats indexer with existing repositories 2025/09/16 03:56:37 modules/ssh/ssh.go:387:Listen() [I] Adding SSH host key: /var/lib/gitea/data/ssh/gitea.rsa 2025/09/16 03:56:37 modules/ssh/init.go:26:Init() [I] SSH server started on :1234. Cipher list ([[email protected] aes128-ctr aes192-ctr aes256-ctr [email protected] [email protected]]), key exchange algorithms ([curve25519-sha256 ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1]), MACs ([[email protected] hmac-sha2-256 hmac-sha1]) 2025/09/16 03:56:37 ...s/graceful/server.go:50:NewServer() [I] Starting new SSH server: tcp::1234 on PID: 83337 2025/09/16 03:56:38 cmd/web.go:231:func1() [F] PANIC: dial tcp 127.0.0.1:6379: connect: connection refused gitea.com/go-chi/[email protected]/session.go:239 (0x1cdb908) code.gitea.io/gitea/routers/common/middleware.go:108 (0x2547f5a) code.gitea.io/gitea/routers/web/web.go:270 (0x278b8e9) code.gitea.io/gitea/routers/init.go:185 (0x2850d89) code.gitea.io/gitea/cmd/web.go:211 (0x295c5ad) code.gitea.io/gitea/cmd/web.go:262 (0x295cacb) code.gitea.io/gitea/cmd/main.go:111 (0x2953422) github.com/urfave/cli/[email protected]/command.go:276 (0x1cc3dfd) github.com/urfave/cli/[email protected]/command.go:269 (0x1cc4084) github.com/urfave/cli/[email protected]/app.go:333 (0x1cc086a) github.com/urfave/cli/[email protected]/app.go:307 (0x2953f18) code.gitea.io/gitea/cmd/main.go:172 (0x2953efc) code.gitea.io/gitea/main.go:46 (0x2998498) runtime/proc.go:283 (0x4471ca) runtime/asm_amd64.s:1700 (0x484a20) ``` ## After ``` 2025/09/22 22:52:35 .../templates/htmlrenderer.go:118:initHTMLRenderer() [D] Creating static HTML Renderer 2025/09/22 22:52:35 routers/web/web.go:273:Routes() [F] common.Sessioner failed: failed to create session middleware: dial tcp 127.0.0.1:6379: connect: connection refused ``` --------- Signed-off-by: 6543 <[email protected]>
1 parent 151ef80 commit fbe80e6

File tree

8 files changed

+56
-31
lines changed

8 files changed

+56
-31
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
1717
gitea.com/go-chi/cache v0.2.1
1818
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098
19-
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96
19+
gitea.com/go-chi/session v0.0.0-20250926004215-636cadd82e15
2020
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
2121
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
2222
github.com/42wim/httpsig v1.2.3

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g=
4343
gitea.com/go-chi/cache v0.2.1/go.mod h1:Qic0HZ8hOHW62ETGbonpwz8WYypj9NieU9659wFUJ8Q=
4444
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo=
4545
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098/go.mod h1:LjzIOHlRemuUyO7WR12fmm18VZIlCAaOt9L3yKw40pk=
46-
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 h1:IFDiMBObsP6CZIRaDLd54SR6zPYAffPXiXck5Xslu0Q=
47-
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96/go.mod h1:0iEpFKnwO5dG0aF98O4eq6FMsAiXkNBaDIlUOlq4BtM=
46+
gitea.com/go-chi/session v0.0.0-20250926004215-636cadd82e15 h1:qFYmz05u/s9664o7+XEgrlHXSPQ4uHO8/ccZGUb1uxA=
47+
gitea.com/go-chi/session v0.0.0-20250926004215-636cadd82e15/go.mod h1:0iEpFKnwO5dG0aF98O4eq6FMsAiXkNBaDIlUOlq4BtM=
4848
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:+wWBi6Qfruqu7xJgjOIrKVQGiLUZdpKYCZewJ4clqhw=
4949
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:VyMQP6ue6MKHM8UsOXfNfuMKD0oSAWZdXVcpHIN2yaY=
5050
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o=

modules/session/db.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package session
55

66
import (
77
"context"
8+
"fmt"
89
"log"
910
"sync"
1011

@@ -121,12 +122,12 @@ func (p *DBProvider) Read(sid string) (session.RawStore, error) {
121122
}
122123

123124
// Exist returns true if session with given ID exists.
124-
func (p *DBProvider) Exist(sid string) bool {
125+
func (p *DBProvider) Exist(sid string) (bool, error) {
125126
has, err := auth.ExistSession(dbContext(), sid)
126127
if err != nil {
127-
panic("session/DB: error checking existence: " + err.Error())
128+
return false, fmt.Errorf("session/DB: error checking existence: %w", err)
128129
}
129-
return has
130+
return has, nil
130131
}
131132

132133
// Destroy deletes a session by session ID.
@@ -155,12 +156,12 @@ func (p *DBProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err err
155156
}
156157

157158
// Count counts and returns number of sessions.
158-
func (p *DBProvider) Count() int {
159+
func (p *DBProvider) Count() (int, error) {
159160
total, err := auth.CountSessions(dbContext())
160161
if err != nil {
161-
panic("session/DB: error counting records: " + err.Error())
162+
return 0, fmt.Errorf("session/DB: error counting records: %w", err)
162163
}
163-
return int(total)
164+
return int(total), nil
164165
}
165166

166167
// GC calls GC to clean expired sessions.

modules/session/redis.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,12 @@ func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) {
135135
// Read returns raw session store by session ID.
136136
func (p *RedisProvider) Read(sid string) (session.RawStore, error) {
137137
psid := p.prefix + sid
138-
if !p.Exist(sid) {
138+
if exist, err := p.Exist(sid); err == nil && !exist {
139139
if err := p.c.Set(graceful.GetManager().HammerContext(), psid, "", p.duration).Err(); err != nil {
140140
return nil, err
141141
}
142+
} else if err != nil {
143+
return nil, err
142144
}
143145

144146
var kv map[any]any
@@ -159,9 +161,9 @@ func (p *RedisProvider) Read(sid string) (session.RawStore, error) {
159161
}
160162

161163
// Exist returns true if session with given ID exists.
162-
func (p *RedisProvider) Exist(sid string) bool {
164+
func (p *RedisProvider) Exist(sid string) (bool, error) {
163165
v, err := p.c.Exists(graceful.GetManager().HammerContext(), p.prefix+sid).Result()
164-
return err == nil && v == 1
166+
return err == nil && v == 1, err
165167
}
166168

167169
// Destroy deletes a session by session ID.
@@ -174,13 +176,18 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err
174176
poldsid := p.prefix + oldsid
175177
psid := p.prefix + sid
176178

177-
if p.Exist(sid) {
179+
if exist, err := p.Exist(sid); err != nil {
180+
return nil, err
181+
} else if exist {
178182
return nil, fmt.Errorf("new sid '%s' already exists", sid)
179-
} else if !p.Exist(oldsid) {
183+
}
184+
if exist, err := p.Exist(oldsid); err == nil && !exist {
180185
// Make a fake old session.
181-
if err = p.c.Set(graceful.GetManager().HammerContext(), poldsid, "", p.duration).Err(); err != nil {
186+
if err := p.c.Set(graceful.GetManager().HammerContext(), poldsid, "", p.duration).Err(); err != nil {
182187
return nil, err
183188
}
189+
} else if err != nil {
190+
return nil, err
184191
}
185192

186193
// do not use Rename here, because the old sid and new sid may be in different redis cluster slot.
@@ -211,12 +218,9 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err
211218
}
212219

213220
// Count counts and returns number of sessions.
214-
func (p *RedisProvider) Count() int {
221+
func (p *RedisProvider) Count() (int, error) {
215222
size, err := p.c.DBSize(graceful.GetManager().HammerContext()).Result()
216-
if err != nil {
217-
return 0
218-
}
219-
return int(size)
223+
return int(size), err
220224
}
221225

222226
// GC calls GC to clean expired sessions.

modules/session/virtual.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,19 @@ func (o *VirtualSessionProvider) Init(gcLifetime int64, config string) error {
5959
func (o *VirtualSessionProvider) Read(sid string) (session.RawStore, error) {
6060
o.lock.RLock()
6161
defer o.lock.RUnlock()
62-
if o.provider.Exist(sid) {
62+
if exist, err := o.provider.Exist(sid); err == nil && exist {
6363
return o.provider.Read(sid)
64+
} else if err != nil {
65+
return nil, fmt.Errorf("check if '%s' exist failed: %w", sid, err)
6466
}
6567
kv := make(map[any]any)
6668
kv["_old_uid"] = "0"
6769
return NewVirtualStore(o, sid, kv), nil
6870
}
6971

7072
// Exist returns true if session with given ID exists.
71-
func (o *VirtualSessionProvider) Exist(sid string) bool {
72-
return true
73+
func (o *VirtualSessionProvider) Exist(sid string) (bool, error) {
74+
return true, nil
7375
}
7476

7577
// Destroy deletes a session by session ID.
@@ -87,7 +89,7 @@ func (o *VirtualSessionProvider) Regenerate(oldsid, sid string) (session.RawStor
8789
}
8890

8991
// Count counts and returns number of sessions.
90-
func (o *VirtualSessionProvider) Count() int {
92+
func (o *VirtualSessionProvider) Count() (int, error) {
9193
o.lock.RLock()
9294
defer o.lock.RUnlock()
9395
return o.provider.Count()
@@ -162,9 +164,13 @@ func (s *VirtualStore) Release() error {
162164
// Now ensure that we don't exist!
163165
realProvider := s.p.provider
164166

165-
if !s.released && realProvider.Exist(s.sid) {
166-
// This is an error!
167-
return fmt.Errorf("new sid '%s' already exists", s.sid)
167+
if !s.released {
168+
if exist, err := realProvider.Exist(s.sid); err == nil && exist {
169+
// This is an error!
170+
return fmt.Errorf("new sid '%s' already exists", s.sid)
171+
} else if err != nil {
172+
return fmt.Errorf("check if '%s' exist failed: %w", s.sid, err)
173+
}
168174
}
169175
realStore, err := realProvider.Read(s.sid)
170176
if err != nil {

routers/common/middleware.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ func ForwardedHeadersHandler(limit int, trustedProxies []string) func(h http.Han
107107
return proxy.ForwardedHeaders(opt)
108108
}
109109

110-
func Sessioner() func(next http.Handler) http.Handler {
111-
return session.Sessioner(session.Options{
110+
func Sessioner() (func(next http.Handler) http.Handler, error) {
111+
middleware, err := session.Sessioner(session.Options{
112112
Provider: setting.SessionConfig.Provider,
113113
ProviderConfig: setting.SessionConfig.ProviderConfig,
114114
CookieName: setting.SessionConfig.CookieName,
@@ -119,4 +119,9 @@ func Sessioner() func(next http.Handler) http.Handler {
119119
SameSite: setting.SessionConfig.SameSite,
120120
Domain: setting.SessionConfig.Domain,
121121
})
122+
if err != nil {
123+
return nil, fmt.Errorf("failed to create session middleware: %w", err)
124+
}
125+
126+
return middleware, nil
122127
}

routers/install/routes.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"html"
99
"net/http"
1010

11+
"code.gitea.io/gitea/modules/log"
1112
"code.gitea.io/gitea/modules/public"
1213
"code.gitea.io/gitea/modules/setting"
1314
"code.gitea.io/gitea/modules/web"
@@ -23,7 +24,11 @@ func Routes() *web.Router {
2324
base.Methods("GET, HEAD", "/assets/*", public.FileHandlerFunc())
2425

2526
r := web.NewRouter()
26-
r.Use(common.Sessioner(), Contexter())
27+
if sessionMid, err := common.Sessioner(); err == nil && sessionMid != nil {
28+
r.Use(sessionMid, Contexter())
29+
} else {
30+
log.Fatal("common.Sessioner failed: %v", err)
31+
}
2732
r.Get("/", Install) // it must be on the root, because the "install.js" use the window.location to replace the "localhost" AppURL
2833
r.Post("/", web.Bind(forms.InstallForm{}), SubmitInstall)
2934
r.Get("/post-install", InstallDone)

routers/web/web.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,11 @@ func Routes() *web.Router {
267267
routes.Get("/ssh_info", misc.SSHInfo)
268268
routes.Get("/api/healthz", healthcheck.Check)
269269

270-
mid = append(mid, common.Sessioner(), context.Contexter())
270+
if sessionMid, err := common.Sessioner(); err == nil && sessionMid != nil {
271+
mid = append(mid, sessionMid, context.Contexter())
272+
} else {
273+
log.Fatal("common.Sessioner failed: %v", err)
274+
}
271275

272276
// Get user from session if logged in.
273277
mid = append(mid, webAuth(buildAuthGroup()))

0 commit comments

Comments
 (0)