Former-commit-id: 5cb64a4121a664d5066312d385ebd36bb05151ce
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-07-19 07:09:14 +03:00
parent a1991a0830
commit c18106166b
5 changed files with 110 additions and 94 deletions

View File

@ -371,6 +371,8 @@ Other Improvements:
![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0) ![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0)
- Fix [#1553](https://github.com/kataras/iris/issues/1553).
- New `DirOptions.PushTargets` and `PushTargetsRegexp` to push index' assets to the client without additional requests. Inspirated by issue [#1562](https://github.com/kataras/iris/issues/1562). Example matching all `.js, .css and .ico` files (recursively): - New `DirOptions.PushTargets` and `PushTargetsRegexp` to push index' assets to the client without additional requests. Inspirated by issue [#1562](https://github.com/kataras/iris/issues/1562). Example matching all `.js, .css and .ico` files (recursively):
```go ```go

View File

@ -3,6 +3,7 @@ package redis
import ( import (
"crypto/tls" "crypto/tls"
"errors" "errors"
"strings"
"time" "time"
"github.com/kataras/iris/v12/sessions" "github.com/kataras/iris/v12/sessions"
@ -133,11 +134,12 @@ func (db *Database) Config() *Config {
// Acquire receives a session's lifetime from the database, // Acquire receives a session's lifetime from the database,
// if the return value is LifeTime{} then the session manager sets the life time based on the expiration duration lives in configuration. // if the return value is LifeTime{} then the session manager sets the life time based on the expiration duration lives in configuration.
func (db *Database) Acquire(sid string, expires time.Duration) sessions.LifeTime { func (db *Database) Acquire(sid string, expires time.Duration) sessions.LifeTime {
seconds, hasExpiration, found := db.c.Driver.TTL(sid) key := db.makeKey(sid, "")
seconds, hasExpiration, found := db.c.Driver.TTL(key)
if !found { if !found {
// fmt.Printf("db.Acquire expires: %s. Seconds: %v\n", expires, expires.Seconds()) // fmt.Printf("db.Acquire expires: %s. Seconds: %v\n", expires, expires.Seconds())
// not found, create an entry with ttl and return an empty lifetime, session manager will do its job. // not found, create an entry with ttl and return an empty lifetime, session manager will do its job.
if err := db.c.Driver.Set(sid, sid, int64(expires.Seconds())); err != nil { if err := db.c.Driver.Set(key, sid, int64(expires.Seconds())); err != nil {
golog.Debug(err) golog.Debug(err)
} }
@ -154,11 +156,14 @@ func (db *Database) Acquire(sid string, expires time.Duration) sessions.LifeTime
// OnUpdateExpiration will re-set the database's session's entry ttl. // OnUpdateExpiration will re-set the database's session's entry ttl.
// https://redis.io/commands/expire#refreshing-expires // https://redis.io/commands/expire#refreshing-expires
func (db *Database) OnUpdateExpiration(sid string, newExpires time.Duration) error { func (db *Database) OnUpdateExpiration(sid string, newExpires time.Duration) error {
return db.c.Driver.UpdateTTLMany(sid, int64(newExpires.Seconds())) return db.c.Driver.UpdateTTLMany(db.makeKey(sid, ""), int64(newExpires.Seconds()))
} }
func (db *Database) makeKey(sid, key string) string { func (db *Database) makeKey(sid, key string) string {
return sid + db.c.Delim + key if key == "" {
return db.c.Prefix + sid
}
return db.c.Prefix + sid + db.c.Delim + key
} }
// Set sets a key value of a specific session. // Set sets a key value of a specific session.
@ -183,20 +188,23 @@ func (db *Database) Get(sid string, key string) (value interface{}) {
return return
} }
func (db *Database) get(key string, outPtr interface{}) { func (db *Database) get(key string, outPtr interface{}) error {
data, err := db.c.Driver.Get(key) data, err := db.c.Driver.Get(key)
if err != nil { if err != nil {
// not found. // not found.
return return err
} }
if err = sessions.DefaultTranscoder.Unmarshal(data.([]byte), outPtr); err != nil { if err = sessions.DefaultTranscoder.Unmarshal(data.([]byte), outPtr); err != nil {
golog.Debugf("unable to unmarshal value of key: '%s': %v", key, err) golog.Debugf("unable to unmarshal value of key: '%s': %v", key, err)
return err
} }
return nil
} }
func (db *Database) keys(sid string) []string { func (db *Database) keys(sid string) []string {
keys, err := db.c.Driver.GetKeys(sid) keys, err := db.c.Driver.GetKeys(db.makeKey(sid, ""))
if err != nil { if err != nil {
golog.Debugf("unable to get all redis keys of session '%s': %v", sid, err) golog.Debugf("unable to get all redis keys of session '%s': %v", sid, err)
return nil return nil
@ -211,6 +219,7 @@ func (db *Database) Visit(sid string, cb func(key string, value interface{})) {
for _, key := range keys { for _, key := range keys {
var value interface{} // new value each time, we don't know what user will do in "cb". var value interface{} // new value each time, we don't know what user will do in "cb".
db.get(key, &value) db.get(key, &value)
key = strings.TrimPrefix(key, db.c.Prefix+sid+db.c.Delim)
cb(key, value) cb(key, value)
} }
} }
@ -245,7 +254,7 @@ func (db *Database) Release(sid string) {
// clear all $sid-$key. // clear all $sid-$key.
db.Clear(sid) db.Clear(sid)
// and remove the $sid. // and remove the $sid.
err := db.c.Driver.Delete(sid) err := db.c.Driver.Delete(db.c.Prefix + sid)
if err != nil { if err != nil {
golog.Debugf("Database.Release.Driver.Delete: %s: %v", sid, err) golog.Debugf("Database.Release.Driver.Delete: %s: %v", sid, err)
} }

View File

@ -149,18 +149,12 @@ func (r *RadixDriver) CloseConnection() error {
// Set sets a key-value to the redis store. // Set sets a key-value to the redis store.
// The expiration is setted by the secondsLifetime. // The expiration is setted by the secondsLifetime.
func (r *RadixDriver) Set(key string, value interface{}, secondsLifetime int64) error { func (r *RadixDriver) Set(key string, value interface{}, secondsLifetime int64) error {
// fmt.Printf("%#+v. %T. %s\n", value, value, value)
// if vB, ok := value.([]byte); ok && secondsLifetime <= 0 {
// return r.pool.Do(radix.Cmd(nil, "MSET", r.Config.Prefix+key, string(vB)))
// }
var cmd radix.CmdAction var cmd radix.CmdAction
// if has expiration, then use the "EX" to delete the key automatically. // if has expiration, then use the "EX" to delete the key automatically.
if secondsLifetime > 0 { if secondsLifetime > 0 {
cmd = radix.FlatCmd(nil, "SETEX", r.Config.Prefix+key, secondsLifetime, value) cmd = radix.FlatCmd(nil, "SETEX", key, secondsLifetime, value)
} else { } else {
cmd = radix.FlatCmd(nil, "SET", r.Config.Prefix+key, value) // MSET same performance... cmd = radix.FlatCmd(nil, "SET", key, value) // MSET same performance...
} }
return r.pool.Do(cmd) return r.pool.Do(cmd)
@ -168,11 +162,11 @@ func (r *RadixDriver) Set(key string, value interface{}, secondsLifetime int64)
// Get returns value, err by its key // Get returns value, err by its key
// returns nil and a filled error if something bad happened. // returns nil and a filled error if something bad happened.
func (r *RadixDriver) Get(key string) (interface{}, error) { func (r *RadixDriver) Get(key string /* full key */) (interface{}, error) {
var redisVal interface{} var redisVal interface{}
mn := radix.MaybeNil{Rcv: &redisVal} mn := radix.MaybeNil{Rcv: &redisVal}
err := r.pool.Do(radix.Cmd(&mn, "GET", r.Config.Prefix+key)) err := r.pool.Do(radix.Cmd(&mn, "GET", key))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -186,7 +180,7 @@ func (r *RadixDriver) Get(key string) (interface{}, error) {
// Read more at: https://redis.io/commands/ttl // Read more at: https://redis.io/commands/ttl
func (r *RadixDriver) TTL(key string) (seconds int64, hasExpiration bool, found bool) { func (r *RadixDriver) TTL(key string) (seconds int64, hasExpiration bool, found bool) {
var redisVal interface{} var redisVal interface{}
err := r.pool.Do(radix.Cmd(&redisVal, "TTL", r.Config.Prefix+key)) err := r.pool.Do(radix.Cmd(&redisVal, "TTL", key))
if err != nil { if err != nil {
return -2, false, false return -2, false, false
} }
@ -198,9 +192,9 @@ func (r *RadixDriver) TTL(key string) (seconds int64, hasExpiration bool, found
return return
} }
func (r *RadixDriver) updateTTLConn(key string, newSecondsLifeTime int64) error { func (r *RadixDriver) updateTTLConn(key string /* full key */, newSecondsLifeTime int64) error {
var reply int var reply int
err := r.pool.Do(radix.FlatCmd(&reply, "EXPIRE", r.Config.Prefix+key, newSecondsLifeTime)) err := r.pool.Do(radix.FlatCmd(&reply, "EXPIRE", key, newSecondsLifeTime))
if err != nil { if err != nil {
return err return err
} }
@ -229,8 +223,8 @@ func (r *RadixDriver) UpdateTTL(key string, newSecondsLifeTime int64) error {
// UpdateTTLMany like `UpdateTTL` but for all keys starting with that "prefix", // UpdateTTLMany like `UpdateTTL` but for all keys starting with that "prefix",
// it is a bit faster operation if you need to update all sessions keys (although it can be even faster if we used hash but this will limit other features), // it is a bit faster operation if you need to update all sessions keys (although it can be even faster if we used hash but this will limit other features),
// look the `sessions/Database#OnUpdateExpiration` for example. // look the `sessions/Database#OnUpdateExpiration` for example.
func (r *RadixDriver) UpdateTTLMany(prefix string, newSecondsLifeTime int64) error { func (r *RadixDriver) UpdateTTLMany(prefix string /* prefix is the sid */, newSecondsLifeTime int64) error {
keys, err := r.getKeys("0", prefix) keys, err := r.getKeys("0", prefix, true)
if err != nil { if err != nil {
return err return err
} }
@ -284,21 +278,26 @@ func (s *scanResult) UnmarshalRESP(br *bufio.Reader) error {
return (resp2.Any{I: &s.keys}).UnmarshalRESP(br) return (resp2.Any{I: &s.keys}).UnmarshalRESP(br)
} }
func (r *RadixDriver) getKeys(cursor, prefix string) ([]string, error) { func (r *RadixDriver) getKeys(cursor, prefix string, includeSID bool) ([]string, error) {
var res scanResult var res scanResult
err := r.pool.Do(radix.Cmd(&res, "SCAN", cursor, "MATCH", r.Config.Prefix+prefix+"*", "COUNT", "300000"))
if !includeSID {
prefix += r.Config.Delim // delim can be used for fast matching of only keys.
}
pattern := prefix + "*"
err := r.pool.Do(radix.Cmd(&res, "SCAN", cursor, "MATCH", pattern, "COUNT", "300000"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(res.keys) <= 1 { if len(res.keys) == 0 {
return nil, nil return nil, nil
} }
keys := res.keys[1:] // the first one is always the session id itself. keys := res.keys[0:]
if res.cur != "0" { if res.cur != "0" {
moreKeys, err := r.getKeys(res.cur, prefix) moreKeys, err := r.getKeys(res.cur, prefix, includeSID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -312,26 +311,11 @@ func (r *RadixDriver) getKeys(cursor, prefix string) ([]string, error) {
// GetKeys returns all redis keys using the "SCAN" with MATCH command. // GetKeys returns all redis keys using the "SCAN" with MATCH command.
// Read more at: https://redis.io/commands/scan#the-match-option. // Read more at: https://redis.io/commands/scan#the-match-option.
func (r *RadixDriver) GetKeys(prefix string) ([]string, error) { func (r *RadixDriver) GetKeys(prefix string) ([]string, error) {
return r.getKeys("0", prefix) return r.getKeys("0", prefix, false)
} }
// // GetBytes returns bytes representation of a value based on given "key".
// func (r *Service) GetBytes(key string) ([]byte, error) {
// var redisVal []byte
// mn := radix.MaybeNil{Rcv: &redisVal}
// err := r.pool.Do(radix.Cmd(&mn, "GET", r.Config.Prefix+key))
// if err != nil {
// return nil, err
// }
// if mn.Nil {
// return nil, ErrKeyNotFound.Format(key)
// }
// return redisVal, nil
// }
// Delete removes redis entry by specific key // Delete removes redis entry by specific key
func (r *RadixDriver) Delete(key string) error { func (r *RadixDriver) Delete(key string) error {
err := r.pool.Do(radix.Cmd(nil, "DEL", r.Config.Prefix+key)) err := r.pool.Do(radix.Cmd(nil, "DEL", key))
return err return err
} }

View File

@ -61,9 +61,9 @@ func (r *RedigoDriver) Set(key string, value interface{}, secondsLifetime int64)
// if has expiration, then use the "EX" to delete the key automatically. // if has expiration, then use the "EX" to delete the key automatically.
if secondsLifetime > 0 { if secondsLifetime > 0 {
_, err = c.Do("SETEX", r.Config.Prefix+key, secondsLifetime, value) _, err = c.Do("SETEX", key, secondsLifetime, value)
} else { } else {
_, err = c.Do("SET", r.Config.Prefix+key, value) _, err = c.Do("SET", key, value)
} }
return return
@ -78,7 +78,7 @@ func (r *RedigoDriver) Get(key string) (interface{}, error) {
return nil, err return nil, err
} }
redisVal, err := c.Do("GET", r.Config.Prefix+key) redisVal, err := c.Do("GET", key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -93,7 +93,7 @@ func (r *RedigoDriver) Get(key string) (interface{}, error) {
func (r *RedigoDriver) TTL(key string) (seconds int64, hasExpiration bool, found bool) { func (r *RedigoDriver) TTL(key string) (seconds int64, hasExpiration bool, found bool) {
c := r.pool.Get() c := r.pool.Get()
defer c.Close() defer c.Close()
redisVal, err := c.Do("TTL", r.Config.Prefix+key) redisVal, err := c.Do("TTL", key)
if err != nil { if err != nil {
return -2, false, false return -2, false, false
} }
@ -106,7 +106,7 @@ func (r *RedigoDriver) TTL(key string) (seconds int64, hasExpiration bool, found
} }
func (r *RedigoDriver) updateTTLConn(c redis.Conn, key string, newSecondsLifeTime int64) error { func (r *RedigoDriver) updateTTLConn(c redis.Conn, key string, newSecondsLifeTime int64) error {
reply, err := c.Do("EXPIRE", r.Config.Prefix+key, newSecondsLifeTime) reply, err := c.Do("EXPIRE", key, newSecondsLifeTime)
if err != nil { if err != nil {
return err return err
} }
@ -143,14 +143,14 @@ func (r *RedigoDriver) UpdateTTL(key string, newSecondsLifeTime int64) error {
// UpdateTTLMany like `UpdateTTL` but for all keys starting with that "prefix", // UpdateTTLMany like `UpdateTTL` but for all keys starting with that "prefix",
// it is a bit faster operation if you need to update all sessions keys (although it can be even faster if we used hash but this will limit other features), // it is a bit faster operation if you need to update all sessions keys (although it can be even faster if we used hash but this will limit other features),
// look the `sessions/Database#OnUpdateExpiration` for example. // look the `sessions/Database#OnUpdateExpiration` for example.
func (r *RedigoDriver) UpdateTTLMany(prefix string, newSecondsLifeTime int64) error { func (r *RedigoDriver) UpdateTTLMany(prefix string /* prefix is the sid */, newSecondsLifeTime int64) error {
c := r.pool.Get() c := r.pool.Get()
defer c.Close() defer c.Close()
if err := c.Err(); err != nil { if err := c.Err(); err != nil {
return err return err
} }
keys, err := r.getKeysConn(c, 0, prefix) keys, err := r.getKeysConn(c, 0, prefix, true)
if err != nil { if err != nil {
return err return err
} }
@ -184,8 +184,13 @@ func (r *RedigoDriver) GetAll() (interface{}, error) {
return redisVal, nil return redisVal, nil
} }
func (r *RedigoDriver) getKeysConn(c redis.Conn, cursor interface{}, prefix string) ([]string, error) { func (r *RedigoDriver) getKeysConn(c redis.Conn, cursor interface{}, prefix string, includeSID bool) ([]string, error) {
if err := c.Send("SCAN", cursor, "MATCH", r.Config.Prefix+prefix+"*", "COUNT", 300000); err != nil { if !includeSID {
prefix += r.Config.Delim // delim can be used for fast matching of only keys.
}
pattern := prefix + "*"
if err := c.Send("SCAN", cursor, "MATCH", pattern, "COUNT", 300000); err != nil {
return nil, err return nil, err
} }
@ -205,7 +210,7 @@ func (r *RedigoDriver) getKeysConn(c redis.Conn, cursor interface{}, prefix stri
if len(replies) == 2 { if len(replies) == 2 {
// take the second, it must contain the slice of keys. // take the second, it must contain the slice of keys.
if keysSliceAsBytes, ok := replies[1].([]interface{}); ok { if keysSliceAsBytes, ok := replies[1].([]interface{}); ok {
n := len(keysSliceAsBytes) - 1 // scan match returns the session id key too. n := len(keysSliceAsBytes)
if n <= 0 { if n <= 0 {
return nil, nil return nil, nil
} }
@ -213,15 +218,15 @@ func (r *RedigoDriver) getKeysConn(c redis.Conn, cursor interface{}, prefix stri
keys := make([]string, n) keys := make([]string, n)
for i, k := range keysSliceAsBytes { for i, k := range keysSliceAsBytes {
key := fmt.Sprintf("%s", k)[len(r.Config.Prefix):] // key := fmt.Sprintf("%s", k)[len(r.Config.Prefix):]
if key == prefix { // if key == prefix {
continue // it's the session id itself. // continue // it's the session id itself.
} // }
keys[i] = key keys[i] = fmt.Sprintf("%s", k)
} }
if cur := fmt.Sprintf("%s", replies[0]); cur != "0" { if cur := fmt.Sprintf("%s", replies[0]); cur != "0" {
moreKeys, err := r.getKeysConn(c, cur, prefix) moreKeys, err := r.getKeysConn(c, cur, prefix, includeSID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -247,7 +252,7 @@ func (r *RedigoDriver) GetKeys(prefix string) ([]string, error) {
return nil, err return nil, err
} }
return r.getKeysConn(c, 0, prefix) return r.getKeysConn(c, 0, prefix, false)
} }
// GetBytes returns value, err by its key // GetBytes returns value, err by its key
@ -260,7 +265,7 @@ func (r *RedigoDriver) GetBytes(key string) ([]byte, error) {
return nil, err return nil, err
} }
redisVal, err := c.Do("GET", r.Config.Prefix+key) redisVal, err := c.Do("GET", key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -276,7 +281,7 @@ func (r *RedigoDriver) Delete(key string) error {
c := r.pool.Get() c := r.pool.Get()
defer c.Close() defer c.Close()
_, err := c.Do("DEL", r.Config.Prefix+key) _, err := c.Do("DEL", key)
return err return err
} }

View File

@ -20,15 +20,30 @@ type Sessions struct {
config Config config Config
provider *provider provider *provider
handlerCookieOpts []context.CookieOption // see `Handler`. cookieOptions []context.CookieOption // options added on each session cookie action.
} }
// New returns a new fast, feature-rich sessions manager // New returns a new fast, feature-rich sessions manager
// it can be adapted to an iris station // it can be adapted to an iris station
func New(cfg Config) *Sessions { func New(cfg Config) *Sessions {
var cookieOptions []context.CookieOption
if cfg.AllowReclaim {
cookieOptions = append(cookieOptions, context.CookieAllowReclaim(cfg.Cookie))
}
if !cfg.DisableSubdomainPersistence {
cookieOptions = append(cookieOptions, context.CookieAllowSubdomains(cfg.Cookie))
}
if cfg.CookieSecureTLS {
cookieOptions = append(cookieOptions, context.CookieSecure)
}
if cfg.Encoding != nil {
cookieOptions = append(cookieOptions, context.CookieEncoding(cfg.Encoding, cfg.Cookie))
}
return &Sessions{ return &Sessions{
config: cfg.Validate(), cookieOptions: cookieOptions,
provider: newProvider(), config: cfg.Validate(),
provider: newProvider(),
} }
} }
@ -38,9 +53,10 @@ func (s *Sessions) UseDatabase(db Database) {
s.provider.RegisterDatabase(db) s.provider.RegisterDatabase(db)
} }
// GetCookieOptions returns any cookie options registered for the `Handler` method. // GetCookieOptions returns the cookie options registered
// for this sessions manager based on the configuration.
func (s *Sessions) GetCookieOptions() []context.CookieOption { func (s *Sessions) GetCookieOptions() []context.CookieOption {
return s.handlerCookieOpts return s.cookieOptions
} }
// updateCookie gains the ability of updating the session browser cookie to any method which wants to update it // updateCookie gains the ability of updating the session browser cookie to any method which wants to update it
@ -65,7 +81,25 @@ func (s *Sessions) updateCookie(ctx *context.Context, sid string, expires time.D
cookie.MaxAge = int(time.Until(cookie.Expires).Seconds()) cookie.MaxAge = int(time.Until(cookie.Expires).Seconds())
} }
ctx.UpsertCookie(cookie, options...) s.upsertCookie(ctx, cookie, options)
}
func (s *Sessions) upsertCookie(ctx *context.Context, cookie *http.Cookie, cookieOptions []context.CookieOption) {
opts := s.cookieOptions
if len(cookieOptions) > 0 {
opts = append(opts, cookieOptions...)
}
ctx.UpsertCookie(cookie, opts...)
}
func (s *Sessions) getCookie(ctx *context.Context, cookieOptions []context.CookieOption) string {
opts := s.cookieOptions
if len(cookieOptions) > 0 {
opts = append(opts, cookieOptions...)
}
return ctx.GetCookie(s.config.Cookie, opts...)
} }
// Start creates or retrieves an existing session for the particular request. // Start creates or retrieves an existing session for the particular request.
@ -77,7 +111,7 @@ func (s *Sessions) updateCookie(ctx *context.Context, sid string, expires time.D
// //
// NOTE: Use `app.Use(sess.Handler())` instead, avoid using `Start` manually. // NOTE: Use `app.Use(sess.Handler())` instead, avoid using `Start` manually.
func (s *Sessions) Start(ctx *context.Context, cookieOptions ...context.CookieOption) *Session { func (s *Sessions) Start(ctx *context.Context, cookieOptions ...context.CookieOption) *Session {
cookieValue := ctx.GetCookie(s.config.Cookie, cookieOptions...) cookieValue := s.getCookie(ctx, cookieOptions)
if cookieValue == "" { // cookie doesn't exist, let's generate a session and set a cookie. if cookieValue == "" { // cookie doesn't exist, let's generate a session and set a cookie.
sid := s.config.SessionIDGenerator(ctx) sid := s.config.SessionIDGenerator(ctx)
@ -106,27 +140,9 @@ const sessionContextKey = "iris.session"
// To return the request's Session call the `Get(ctx)` package-level function. // To return the request's Session call the `Get(ctx)` package-level function.
// //
// Call `Handler()` once per sessions manager. // Call `Handler()` once per sessions manager.
func (s *Sessions) Handler(cookieOptions ...context.CookieOption) context.Handler { func (s *Sessions) Handler(requestOptions ...context.CookieOption) context.Handler {
s.handlerCookieOpts = cookieOptions
var requestOptions []context.CookieOption
if s.config.AllowReclaim {
requestOptions = append(requestOptions, context.CookieAllowReclaim(s.config.Cookie))
}
if !s.config.DisableSubdomainPersistence {
requestOptions = append(requestOptions, context.CookieAllowSubdomains(s.config.Cookie))
}
if s.config.CookieSecureTLS {
requestOptions = append(requestOptions, context.CookieSecure)
}
if s.config.Encoding != nil {
requestOptions = append(requestOptions, context.CookieEncoding(s.config.Encoding, s.config.Cookie))
}
return func(ctx *context.Context) { return func(ctx *context.Context) {
ctx.AddCookieOptions(requestOptions...) // request life-cycle options. session := s.Start(ctx, requestOptions...) // this cookie's end-developer's custom options.
session := s.Start(ctx, cookieOptions...) // this cookie's end-developer's custom options.
ctx.Values().Set(sessionContextKey, session) ctx.Values().Set(sessionContextKey, session)
ctx.Next() ctx.Next()
@ -170,7 +186,7 @@ func (s *Sessions) ShiftExpiration(ctx *context.Context, cookieOptions ...contex
// It will return `ErrNotFound` when trying to update expiration on a non-existence or not valid session entry. // It will return `ErrNotFound` when trying to update expiration on a non-existence or not valid session entry.
// It will return `ErrNotImplemented` if a database is used and it does not support this feature, yet. // It will return `ErrNotImplemented` if a database is used and it does not support this feature, yet.
func (s *Sessions) UpdateExpiration(ctx *context.Context, expires time.Duration, cookieOptions ...context.CookieOption) error { func (s *Sessions) UpdateExpiration(ctx *context.Context, expires time.Duration, cookieOptions ...context.CookieOption) error {
cookieValue := ctx.GetCookie(s.config.Cookie) cookieValue := s.getCookie(ctx, cookieOptions)
if cookieValue == "" { if cookieValue == "" {
return ErrNotFound return ErrNotFound
} }
@ -204,7 +220,7 @@ func (s *Sessions) OnDestroy(listeners ...DestroyListener) {
// use `Sessions#Start` method for renewal // use `Sessions#Start` method for renewal
// or use the Session's Destroy method which does keep the session entry with its values cleared. // or use the Session's Destroy method which does keep the session entry with its values cleared.
func (s *Sessions) Destroy(ctx *context.Context) { func (s *Sessions) Destroy(ctx *context.Context) {
cookieValue := ctx.GetCookie(s.config.Cookie) cookieValue := s.getCookie(ctx, nil)
if cookieValue == "" { // nothing to destroy if cookieValue == "" { // nothing to destroy
return return
} }