mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Partial fix for #11155 - the Macaron session middleware panics if mysql returns an error. This fix recovers from the panic and retries once
175 lines
3.8 KiB
Go
175 lines
3.8 KiB
Go
package session
|
|
|
|
import (
|
|
"math/rand"
|
|
"time"
|
|
|
|
ms "github.com/go-macaron/session"
|
|
_ "github.com/go-macaron/session/memcache"
|
|
_ "github.com/go-macaron/session/mysql"
|
|
_ "github.com/go-macaron/session/postgres"
|
|
_ "github.com/go-macaron/session/redis"
|
|
"github.com/grafana/grafana/pkg/log"
|
|
"gopkg.in/macaron.v1"
|
|
)
|
|
|
|
const (
|
|
SESS_KEY_USERID = "uid"
|
|
SESS_KEY_OAUTH_STATE = "state"
|
|
SESS_KEY_APIKEY = "apikey_id" // used for render requests with api keys
|
|
SESS_KEY_LASTLDAPSYNC = "last_ldap_sync"
|
|
)
|
|
|
|
var sessionManager *ms.Manager
|
|
var sessionOptions *ms.Options
|
|
var StartSessionGC func()
|
|
var GetSessionCount func() int
|
|
var sessionLogger = log.New("session")
|
|
|
|
func init() {
|
|
StartSessionGC = func() {
|
|
sessionManager.GC()
|
|
sessionLogger.Debug("Session GC")
|
|
time.AfterFunc(time.Duration(sessionOptions.Gclifetime)*time.Second, StartSessionGC)
|
|
}
|
|
GetSessionCount = func() int {
|
|
return sessionManager.Count()
|
|
}
|
|
}
|
|
|
|
func Init(options *ms.Options) {
|
|
var err error
|
|
sessionOptions = prepareOptions(options)
|
|
sessionManager, err = ms.NewManager(options.Provider, *options)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// start GC threads after some random seconds
|
|
rndSeconds := 10 + rand.Int63n(180)
|
|
time.AfterFunc(time.Duration(rndSeconds)*time.Second, StartSessionGC)
|
|
}
|
|
|
|
func prepareOptions(opt *ms.Options) *ms.Options {
|
|
if len(opt.Provider) == 0 {
|
|
opt.Provider = "memory"
|
|
}
|
|
if len(opt.ProviderConfig) == 0 {
|
|
opt.ProviderConfig = "data/sessions"
|
|
}
|
|
if len(opt.CookieName) == 0 {
|
|
opt.CookieName = "grafana_sess"
|
|
}
|
|
if len(opt.CookiePath) == 0 {
|
|
opt.CookiePath = "/"
|
|
}
|
|
if opt.Gclifetime == 0 {
|
|
opt.Gclifetime = 3600
|
|
}
|
|
if opt.Maxlifetime == 0 {
|
|
opt.Maxlifetime = opt.Gclifetime
|
|
}
|
|
if opt.IDLength == 0 {
|
|
opt.IDLength = 16
|
|
}
|
|
|
|
return opt
|
|
}
|
|
|
|
func GetSession() SessionStore {
|
|
return &SessionWrapper{manager: sessionManager}
|
|
}
|
|
|
|
type SessionStore interface {
|
|
// Set sets value to given key in session.
|
|
Set(interface{}, interface{}) error
|
|
// Get gets value by given key in session.
|
|
Get(interface{}) interface{}
|
|
// Delete deletes a key from session.
|
|
Delete(interface{}) interface{}
|
|
// ID returns current session ID.
|
|
ID() string
|
|
// Release releases session resource and save data to provider.
|
|
Release() error
|
|
// Destory deletes a session.
|
|
Destory(*macaron.Context) error
|
|
// init
|
|
Start(*macaron.Context) error
|
|
// RegenerateId regenerates the session id
|
|
RegenerateId(*macaron.Context) error
|
|
}
|
|
|
|
type SessionWrapper struct {
|
|
session ms.RawStore
|
|
manager *ms.Manager
|
|
}
|
|
|
|
func (s *SessionWrapper) Start(c *macaron.Context) error {
|
|
// See https://github.com/grafana/grafana/issues/11155 for details on why
|
|
// a recover and retry is needed
|
|
defer func() error {
|
|
if err := recover(); err != nil {
|
|
var retryErr error
|
|
s.session, retryErr = s.manager.Start(c)
|
|
return retryErr
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
var err error
|
|
s.session, err = s.manager.Start(c)
|
|
return err
|
|
}
|
|
|
|
func (s *SessionWrapper) RegenerateId(c *macaron.Context) error {
|
|
var err error
|
|
s.session, err = s.manager.RegenerateId(c)
|
|
return err
|
|
}
|
|
|
|
func (s *SessionWrapper) Set(k interface{}, v interface{}) error {
|
|
if s.session != nil {
|
|
return s.session.Set(k, v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SessionWrapper) Get(k interface{}) interface{} {
|
|
if s.session != nil {
|
|
return s.session.Get(k)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SessionWrapper) Delete(k interface{}) interface{} {
|
|
if s.session != nil {
|
|
return s.session.Delete(k)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SessionWrapper) ID() string {
|
|
if s.session != nil {
|
|
return s.session.ID()
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (s *SessionWrapper) Release() error {
|
|
if s.session != nil {
|
|
return s.session.Release()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SessionWrapper) Destory(c *macaron.Context) error {
|
|
if s.session != nil {
|
|
if err := s.manager.Destory(c); err != nil {
|
|
return err
|
|
}
|
|
s.session = nil
|
|
}
|
|
return nil
|
|
}
|