1
0
mirror of https://github.com/gofiber/fiber.git synced 2025-02-24 08:03:42 +00:00
fiber/middleware/session/session.go

201 lines
4.2 KiB
Go
Raw Normal View History

2020-11-06 19:43:57 +01:00
package session
2020-11-06 19:32:56 +01:00
import (
2020-11-11 19:22:40 +01:00
"sync"
2020-11-06 19:32:56 +01:00
"time"
"github.com/gofiber/fiber/v2"
2020-11-26 12:05:43 +01:00
"github.com/gofiber/fiber/v2/internal/gotiny"
2020-11-06 19:32:56 +01:00
"github.com/gofiber/fiber/v2/utils"
"github.com/valyala/fasthttp"
)
type Session struct {
2020-11-16 14:22:44 +01:00
id string // session id
fresh bool // if new session
ctx *fiber.Ctx // fiber context
config *Store // store configuration
data *data // key value data
2020-11-06 19:32:56 +01:00
}
2020-11-11 19:22:40 +01:00
var sessionPool = sync.Pool{
New: func() interface{} {
return new(Session)
},
}
func acquireSession() *Session {
s := sessionPool.Get().(*Session)
if s.data == nil {
2020-11-26 12:05:43 +01:00
s.data = acquireData()
}
s.fresh = true
return s
2020-11-11 19:22:40 +01:00
}
func releaseSession(s *Session) {
s.id = ""
s.ctx = nil
s.config = nil
if s.data != nil {
s.data.Reset()
}
2020-11-11 19:22:40 +01:00
sessionPool.Put(s)
}
// Fresh is true if the current session is new
2020-11-06 19:32:56 +01:00
func (s *Session) Fresh() bool {
return s.fresh
}
// ID returns the session id
func (s *Session) ID() string {
return s.id
}
// Get will return the value
func (s *Session) Get(key string) interface{} {
2020-11-16 14:22:44 +01:00
// Better safe than sorry
if s.data == nil {
return nil
}
return s.data.Get(key)
2020-11-06 19:32:56 +01:00
}
// Set will update or create a new key value
func (s *Session) Set(key string, val interface{}) {
2020-11-16 14:22:44 +01:00
// Better safe than sorry
if s.data == nil {
return
}
s.data.Set(key, val)
2020-11-06 19:32:56 +01:00
}
// Delete will delete the value
func (s *Session) Delete(key string) {
2020-11-16 14:22:44 +01:00
// Better safe than sorry
if s.data == nil {
return
}
s.data.Delete(key)
2020-11-06 19:32:56 +01:00
}
2020-11-13 18:30:14 +01:00
// Destroy will delete the session from Storage and expire session cookie
func (s *Session) Destroy() error {
2020-11-16 14:22:44 +01:00
// Better safe than sorry
if s.data == nil {
return nil
}
2020-11-13 18:30:14 +01:00
2020-11-16 14:22:44 +01:00
// Reset local data
s.data.Reset()
// Use external Storage if exist
if err := s.config.Storage.Delete(s.id); err != nil {
return err
2020-11-13 18:30:14 +01:00
}
// Expire cookie
s.delCookie()
return nil
}
// Regenerate generates a new session id and delete the old one from Storage
func (s *Session) Regenerate() error {
// Delete old id from storage
if err := s.config.Storage.Delete(s.id); err != nil {
return err
2020-11-13 18:30:14 +01:00
}
2020-11-16 14:22:44 +01:00
2020-11-13 18:30:14 +01:00
// Create new ID
s.id = s.config.KeyGenerator()
return nil
2020-11-06 19:32:56 +01:00
}
// Save will update the storage and client cookie
func (s *Session) Save() error {
2020-11-26 15:27:05 +01:00
2020-11-16 14:22:44 +01:00
// Better safe than sorry
if s.data == nil {
2020-11-06 19:32:56 +01:00
return nil
}
2020-12-02 15:34:16 +09:00
// Create cookie with the session ID if fresh
if s.fresh {
s.setCookie()
}
2020-11-16 14:22:44 +01:00
// Don't save to Storage if no data is available
if s.data.Len() <= 0 {
return nil
2020-11-06 19:32:56 +01:00
}
// Convert data to bytes
2020-11-26 22:33:35 +01:00
mux.Lock()
2020-11-26 12:05:43 +01:00
data := gotiny.Marshal(&s.data)
2020-11-26 22:33:35 +01:00
mux.Unlock()
// pass raw bytes with session id to provider
if err := s.config.Storage.Set(s.id, data, s.config.Expiration); err != nil {
return err
2020-11-06 19:32:56 +01:00
}
// Release session
// TODO: It's not safe to use the Session after called Save()
2020-11-11 19:22:40 +01:00
releaseSession(s)
2020-11-06 19:32:56 +01:00
return nil
}
func (s *Session) setCookie() {
fcookie := fasthttp.AcquireCookie()
2020-11-11 23:51:32 +01:00
fcookie.SetKey(s.config.CookieName)
2020-11-06 19:32:56 +01:00
fcookie.SetValue(s.id)
2020-11-11 23:51:32 +01:00
fcookie.SetPath(s.config.CookiePath)
fcookie.SetDomain(s.config.CookieDomain)
2020-11-13 18:30:14 +01:00
fcookie.SetMaxAge(int(s.config.Expiration.Seconds()))
2020-11-06 19:43:57 +01:00
fcookie.SetExpire(time.Now().Add(s.config.Expiration))
2020-11-11 23:51:32 +01:00
fcookie.SetSecure(s.config.CookieSecure)
fcookie.SetHTTPOnly(s.config.CookieHTTPOnly)
2020-11-06 19:43:57 +01:00
2020-11-11 23:51:32 +01:00
switch utils.ToLower(s.config.CookieSameSite) {
2020-11-06 19:32:56 +01:00
case "strict":
fcookie.SetSameSite(fasthttp.CookieSameSiteStrictMode)
case "none":
fcookie.SetSameSite(fasthttp.CookieSameSiteNoneMode)
default:
fcookie.SetSameSite(fasthttp.CookieSameSiteLaxMode)
}
s.ctx.Response().Header.SetCookie(fcookie)
fasthttp.ReleaseCookie(fcookie)
}
2020-11-13 18:30:14 +01:00
func (s *Session) delCookie() {
2020-11-11 23:51:32 +01:00
s.ctx.Request().Header.DelCookie(s.config.CookieName)
s.ctx.Response().Header.DelCookie(s.config.CookieName)
2020-11-06 19:32:56 +01:00
fcookie := fasthttp.AcquireCookie()
2020-11-11 23:51:32 +01:00
fcookie.SetKey(s.config.CookieName)
fcookie.SetPath(s.config.CookiePath)
fcookie.SetDomain(s.config.CookieDomain)
2020-11-13 18:30:14 +01:00
fcookie.SetMaxAge(-1)
2020-11-06 19:32:56 +01:00
fcookie.SetExpire(time.Now().Add(-1 * time.Minute))
2020-11-11 23:51:32 +01:00
fcookie.SetSecure(s.config.CookieSecure)
fcookie.SetHTTPOnly(s.config.CookieHTTPOnly)
2020-11-06 19:32:56 +01:00
2020-11-11 23:51:32 +01:00
switch utils.ToLower(s.config.CookieSameSite) {
2020-11-06 19:32:56 +01:00
case "strict":
fcookie.SetSameSite(fasthttp.CookieSameSiteStrictMode)
case "none":
fcookie.SetSameSite(fasthttp.CookieSameSiteNoneMode)
default:
fcookie.SetSameSite(fasthttp.CookieSameSiteLaxMode)
}
s.ctx.Response().Header.SetCookie(fcookie)
fasthttp.ReleaseCookie(fcookie)
}