This commit is contained in:
Darko Luketic 2018-04-27 18:01:24 +02:00
commit dbc12bc64e
10 changed files with 962 additions and 0 deletions

21
sscookie/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Gin-Gonic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

38
sscookie/cookie.go Normal file
View File

@ -0,0 +1,38 @@
package sessions
import (
"github.com/gorilla/sessions"
)
// CookieStore interface
type CookieStore interface {
Store
}
// NewCookieStore creates a new cookieStore.
// Keys are defined in pairs to allow key rotation, but the common case is to set a single
// authentication key and optionally an encryption key.
//
// The first key in a pair is used for authentication and the second for encryption. The
// encryption key can be set to nil or omitted in the last pair, but the authentication key
// is required in all pairs.
//
// It is recommended to use an authentication key with 32 or 64 bytes. The encryption key,
// if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes.
func NewCookieStore(keyPairs ...[]byte) CookieStore {
return &cookieStore{sessions.NewCookieStore(keyPairs...)}
}
type cookieStore struct {
*sessions.CookieStore
}
func (c *cookieStore) Options(options Options) {
c.CookieStore.Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HTTPOnly,
}
}

30
sscookie/cookie_test.go Normal file
View File

@ -0,0 +1,30 @@
package sessions
import (
"testing"
)
var newCookieStore = func(_ *testing.T) Store {
store := NewCookieStore([]byte("secret"))
return store
}
func TestCookie_SessionGetSet(t *testing.T) {
sessionGetSet(t, newCookieStore)
}
func TestCookie_SessionDeleteKey(t *testing.T) {
sessionDeleteKey(t, newCookieStore)
}
func TestCookie_SessionFlashes(t *testing.T) {
sessionFlashes(t, newCookieStore)
}
func TestCookie_SessionClear(t *testing.T) {
sessionClear(t, newCookieStore)
}
func TestCookie_SessionOptions(t *testing.T) {
sessionOptions(t, newCookieStore)
}

154
sscookie/sessions.go Normal file
View File

@ -0,0 +1,154 @@
package sessions
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gorilla/context"
"github.com/gorilla/sessions"
)
const (
DefaultKey = "github.com/gin-contrib/sessions"
errorFormat = "[sessions] ERROR! %s\n"
)
type Store interface {
sessions.Store
Options(Options)
}
// Options stores configuration for a session or session store.
// Fields are a subset of http.Cookie fields.
type Options struct {
Path string
Domain string
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
// MaxAge>0 means Max-Age attribute present and given in seconds.
MaxAge int
Secure bool
HTTPOnly bool
}
// Session thinly Wraps gorilla-session methods and stores the values and optional configuration for a session.
type Session interface {
// Get returns the session value associated to the given key.
Get(key interface{}) interface{}
// Set sets the session value associated to the given key.
Set(key interface{}, val interface{})
// Delete removes the session value associated to the given key.
Delete(key interface{})
// Clear deletes all values in the session.
Clear()
// AddFlash adds a flash message to the session.
// A single variadic argument is accepted, and it is optional: it defines the flash key.
// If not defined "_flash" is used by default.
AddFlash(value interface{}, vars ...string)
// Flashes returns a slice of flash messages from the session.
// A single variadic argument is accepted, and it is optional: it defines the flash key.
// If not defined "_flash" is used by default.
Flashes(vars ...string) []interface{}
// Options sets confuguration for a session.
Options(Options)
// Save saves all sessions used during the current request.
Save() error
}
// Sessions is used to create middleware
func Sessions(name string, store Store) gin.HandlerFunc {
return func(c *gin.Context) {
s := &session{
name: name,
request: c.Request,
store: store,
session: nil,
written: false,
writer: c.Writer,
}
c.Set(DefaultKey, s)
defer context.Clear(c.Request)
c.Next()
}
}
type session struct {
name string
request *http.Request
store Store
session *sessions.Session
written bool
writer http.ResponseWriter
}
func (s *session) Get(key interface{}) interface{} {
return s.Session().Values[key]
}
func (s *session) Set(key interface{}, val interface{}) {
s.Session().Values[key] = val
s.written = true
}
func (s *session) Delete(key interface{}) {
delete(s.Session().Values, key)
s.written = true
}
func (s *session) Clear() {
for key := range s.Session().Values {
s.Delete(key)
}
}
func (s *session) AddFlash(value interface{}, vars ...string) {
s.Session().AddFlash(value, vars...)
s.written = true
}
func (s *session) Flashes(vars ...string) []interface{} {
s.written = true
return s.Session().Flashes(vars...)
}
func (s *session) Options(options Options) {
s.Session().Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HTTPOnly,
}
}
func (s *session) Save() error {
if s.Written() {
e := s.Session().Save(s.request, s.writer)
if e == nil {
s.written = false
}
return e
}
return nil
}
func (s *session) Session() *sessions.Session {
if s.session == nil {
var err error
s.session, err = s.store.Get(s.request, s.name)
if err != nil {
log.Printf(errorFormat, err)
}
}
return s.session
}
func (s *session) Written() bool {
return s.written
}
// Default is a shortcut to get session
func Default(c *gin.Context) Session {
return c.MustGet(DefaultKey).(Session)
}

220
sscookie/sessions_test.go Normal file
View File

@ -0,0 +1,220 @@
package sessions
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
)
type storeFactory func(*testing.T) Store
const sessionName = "mysession"
const ok = "ok"
func sessionGetSet(t *testing.T, newStore storeFactory) {
r := gin.Default()
r.Use(Sessions(sessionName, newStore(t)))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
r.GET("/get", func(c *gin.Context) {
session := Default(c)
if session.Get("key") != ok {
t.Error("Session writing failed")
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/get", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
}
func sessionDeleteKey(t *testing.T, newStore storeFactory) {
r := gin.Default()
r.Use(Sessions(sessionName, newStore(t)))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
r.GET("/delete", func(c *gin.Context) {
session := Default(c)
session.Delete("key")
session.Save()
c.String(200, ok)
})
r.GET("/get", func(c *gin.Context) {
session := Default(c)
if session.Get("key") != nil {
t.Error("Session deleting failed")
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/delete", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
res3 := httptest.NewRecorder()
req3, _ := http.NewRequest("GET", "/get", nil)
req3.Header.Set("Cookie", res2.Header().Get("Set-Cookie"))
r.ServeHTTP(res3, req3)
}
func sessionFlashes(t *testing.T, newStore storeFactory) {
r := gin.Default()
store := newStore(t)
store.Options(Options{
Domain: "localhost",
})
r.Use(Sessions(sessionName, store))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.AddFlash(ok)
session.Save()
c.String(200, ok)
})
r.GET("/flash", func(c *gin.Context) {
session := Default(c)
l := len(session.Flashes())
if l != 1 {
t.Error("Flashes count does not equal 1. Equals ", l)
}
session.Save()
c.String(200, ok)
})
r.GET("/check", func(c *gin.Context) {
session := Default(c)
l := len(session.Flashes())
if l != 0 {
t.Error("flashes count is not 0 after reading. Equals ", l)
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/flash", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
res3 := httptest.NewRecorder()
req3, _ := http.NewRequest("GET", "/check", nil)
req3.Header.Set("Cookie", res2.Header().Get("Set-Cookie"))
r.ServeHTTP(res3, req3)
}
func sessionClear(t *testing.T, newStore storeFactory) {
data := map[string]string{
"key": "val",
"foo": "bar",
}
r := gin.Default()
store := newStore(t)
r.Use(Sessions(sessionName, store))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
for k, v := range data {
session.Set(k, v)
}
session.Clear()
session.Save()
c.String(200, ok)
})
r.GET("/check", func(c *gin.Context) {
session := Default(c)
for k, v := range data {
if session.Get(k) == v {
t.Fatal("Session clear failed")
}
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/check", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
}
func sessionOptions(t *testing.T, newStore storeFactory) {
r := gin.Default()
store := newStore(t)
store.Options(Options{
Domain: "localhost",
})
r.Use(Sessions(sessionName, store))
r.GET("/domain", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Options(Options{
Path: "/foo/bar/bat",
})
session.Save()
c.String(200, ok)
})
r.GET("/path", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/domain", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/path", nil)
r.ServeHTTP(res2, req2)
s := strings.Split(res1.Header().Get("Set-Cookie"), ";")
if s[1] != " Path=/foo/bar/bat" {
t.Error("Error writing path with options:", s[1])
}
s = strings.Split(res2.Header().Get("Set-Cookie"), ";")
if s[1] != " Domain=localhost" {
t.Error("Error writing domain with options:", s[1])
}
}

21
ssredis/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Gin-Gonic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

69
ssredis/redis.go Normal file
View File

@ -0,0 +1,69 @@
package sessions
import (
"github.com/boj/redistore"
"github.com/garyburd/redigo/redis"
"github.com/gorilla/sessions"
)
type RedisStore interface {
Store
}
// size: maximum number of idle connections.
// network: tcp or udp
// address: host:port
// password: redis-password
// Keys are defined in pairs to allow key rotation, but the common case is to set a single
// authentication key and optionally an encryption key.
//
// The first key in a pair is used for authentication and the second for encryption. The
// encryption key can be set to nil or omitted in the last pair, but the authentication key
// is required in all pairs.
//
// It is recommended to use an authentication key with 32 or 64 bytes. The encryption key,
// if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes.
func NewRedisStore(size int, network, address, password string, keyPairs ...[]byte) (RedisStore, error) {
store, err := redistore.NewRediStore(size, network, address, password, keyPairs...)
if err != nil {
return nil, err
}
return &redisStore{store}, nil
}
// NewRedisStoreWithDB - like NewRedisStore but accepts `DB` parameter to select
// redis DB instead of using the default one ("0")
//
// Ref: https://godoc.org/github.com/boj/redistore#NewRediStoreWithDB
func NewRedisStoreWithDB(size int, network, address, password, DB string, keyPairs ...[]byte) (RedisStore, error) {
store, err := redistore.NewRediStoreWithDB(size, network, address, password, DB, keyPairs...)
if err != nil {
return nil, err
}
return &redisStore{store}, nil
}
// NewRedisStoreWithPool instantiates a RediStore with a *redis.Pool passed in.
//
// Ref: https://godoc.org/github.com/boj/redistore#NewRediStoreWithPool
func NewRedisStoreWithPool(pool *redis.Pool, keyPairs ...[]byte) (RedisStore, error) {
store, err := redistore.NewRediStoreWithPool(pool, keyPairs...)
if err != nil {
return nil, err
}
return &redisStore{store}, nil
}
type redisStore struct {
*redistore.RediStore
}
func (c *redisStore) Options(options Options) {
c.RediStore.Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HttpOnly,
}
}

35
ssredis/redis_test.go Normal file
View File

@ -0,0 +1,35 @@
package sessions
import (
"testing"
)
const redisTestServer = "localhost:6379"
var newRedisStore = func(_ *testing.T) Store {
store, err := NewRedisStore(10, "tcp", redisTestServer, "", []byte("secret"))
if err != nil {
panic(err)
}
return store
}
func TestRedis_SessionGetSet(t *testing.T) {
sessionGetSet(t, newRedisStore)
}
func TestRedis_SessionDeleteKey(t *testing.T) {
sessionDeleteKey(t, newRedisStore)
}
func TestRedis_SessionFlashes(t *testing.T) {
sessionFlashes(t, newRedisStore)
}
func TestRedis_SessionClear(t *testing.T) {
sessionClear(t, newRedisStore)
}
func TestRedis_SessionOptions(t *testing.T) {
sessionOptions(t, newRedisStore)
}

154
ssredis/sessions.go Normal file
View File

@ -0,0 +1,154 @@
package sessions
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gorilla/context"
"github.com/gorilla/sessions"
)
const (
DefaultKey = "github.com/gin-contrib/sessions"
errorFormat = "[sessions] ERROR! %s\n"
)
type Store interface {
sessions.Store
Options(Options)
}
// Options stores configuration for a session or session store.
// Fields are a subset of http.Cookie fields.
type Options struct {
Path string
Domain string
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
// MaxAge>0 means Max-Age attribute present and given in seconds.
MaxAge int
Secure bool
HttpOnly bool
}
// Wraps thinly gorilla-session methods.
// Session stores the values and optional configuration for a session.
type Session interface {
// Get returns the session value associated to the given key.
Get(key interface{}) interface{}
// Set sets the session value associated to the given key.
Set(key interface{}, val interface{})
// Delete removes the session value associated to the given key.
Delete(key interface{})
// Clear deletes all values in the session.
Clear()
// AddFlash adds a flash message to the session.
// A single variadic argument is accepted, and it is optional: it defines the flash key.
// If not defined "_flash" is used by default.
AddFlash(value interface{}, vars ...string)
// Flashes returns a slice of flash messages from the session.
// A single variadic argument is accepted, and it is optional: it defines the flash key.
// If not defined "_flash" is used by default.
Flashes(vars ...string) []interface{}
// Options sets confuguration for a session.
Options(Options)
// Save saves all sessions used during the current request.
Save() error
}
func Sessions(name string, store Store) gin.HandlerFunc {
return func(c *gin.Context) {
s := &session{
name: name,
request: c.Request,
store: store,
session: nil,
written: false,
writer: c.Writer,
}
c.Set(DefaultKey, s)
defer context.Clear(c.Request)
c.Next()
}
}
type session struct {
name string
request *http.Request
store Store
session *sessions.Session
written bool
writer http.ResponseWriter
}
func (s *session) Get(key interface{}) interface{} {
return s.Session().Values[key]
}
func (s *session) Set(key interface{}, val interface{}) {
s.Session().Values[key] = val
s.written = true
}
func (s *session) Delete(key interface{}) {
delete(s.Session().Values, key)
s.written = true
}
func (s *session) Clear() {
for key := range s.Session().Values {
s.Delete(key)
}
}
func (s *session) AddFlash(value interface{}, vars ...string) {
s.Session().AddFlash(value, vars...)
s.written = true
}
func (s *session) Flashes(vars ...string) []interface{} {
s.written = true
return s.Session().Flashes(vars...)
}
func (s *session) Options(options Options) {
s.Session().Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HttpOnly,
}
}
func (s *session) Save() error {
if s.Written() {
e := s.Session().Save(s.request, s.writer)
if e == nil {
s.written = false
}
return e
}
return nil
}
func (s *session) Session() *sessions.Session {
if s.session == nil {
var err error
s.session, err = s.store.Get(s.request, s.name)
if err != nil {
log.Printf(errorFormat, err)
}
}
return s.session
}
func (s *session) Written() bool {
return s.written
}
// shortcut to get session
func Default(c *gin.Context) Session {
return c.MustGet(DefaultKey).(Session)
}

220
ssredis/sessions_test.go Normal file
View File

@ -0,0 +1,220 @@
package sessions
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
)
type storeFactory func(*testing.T) Store
const sessionName = "mysession"
const ok = "ok"
func sessionGetSet(t *testing.T, newStore storeFactory) {
r := gin.Default()
r.Use(Sessions(sessionName, newStore(t)))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
r.GET("/get", func(c *gin.Context) {
session := Default(c)
if session.Get("key") != ok {
t.Error("Session writing failed")
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/get", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
}
func sessionDeleteKey(t *testing.T, newStore storeFactory) {
r := gin.Default()
r.Use(Sessions(sessionName, newStore(t)))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
r.GET("/delete", func(c *gin.Context) {
session := Default(c)
session.Delete("key")
session.Save()
c.String(200, ok)
})
r.GET("/get", func(c *gin.Context) {
session := Default(c)
if session.Get("key") != nil {
t.Error("Session deleting failed")
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/delete", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
res3 := httptest.NewRecorder()
req3, _ := http.NewRequest("GET", "/get", nil)
req3.Header.Set("Cookie", res2.Header().Get("Set-Cookie"))
r.ServeHTTP(res3, req3)
}
func sessionFlashes(t *testing.T, newStore storeFactory) {
r := gin.Default()
store := newStore(t)
store.Options(Options{
Domain: "localhost",
})
r.Use(Sessions(sessionName, store))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.AddFlash(ok)
session.Save()
c.String(200, ok)
})
r.GET("/flash", func(c *gin.Context) {
session := Default(c)
l := len(session.Flashes())
if l != 1 {
t.Error("Flashes count does not equal 1. Equals ", l)
}
session.Save()
c.String(200, ok)
})
r.GET("/check", func(c *gin.Context) {
session := Default(c)
l := len(session.Flashes())
if l != 0 {
t.Error("flashes count is not 0 after reading. Equals ", l)
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/flash", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
res3 := httptest.NewRecorder()
req3, _ := http.NewRequest("GET", "/check", nil)
req3.Header.Set("Cookie", res2.Header().Get("Set-Cookie"))
r.ServeHTTP(res3, req3)
}
func sessionClear(t *testing.T, newStore storeFactory) {
data := map[string]string{
"key": "val",
"foo": "bar",
}
r := gin.Default()
store := newStore(t)
r.Use(Sessions(sessionName, store))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
for k, v := range data {
session.Set(k, v)
}
session.Clear()
session.Save()
c.String(200, ok)
})
r.GET("/check", func(c *gin.Context) {
session := Default(c)
for k, v := range data {
if session.Get(k) == v {
t.Fatal("Session clear failed")
}
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/check", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
}
func sessionOptions(t *testing.T, newStore storeFactory) {
r := gin.Default()
store := newStore(t)
store.Options(Options{
Domain: "localhost",
})
r.Use(Sessions(sessionName, store))
r.GET("/domain", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Options(Options{
Path: "/foo/bar/bat",
})
session.Save()
c.String(200, ok)
})
r.GET("/path", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/domain", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/path", nil)
r.ServeHTTP(res2, req2)
s := strings.Split(res1.Header().Get("Set-Cookie"), ";")
if s[1] != " Path=/foo/bar/bat" {
t.Error("Error writing path with options:", s[1])
}
s = strings.Split(res2.Header().Get("Set-Cookie"), ";")
if s[1] != " Domain=localhost" {
t.Error("Error writing domain with options:", s[1])
}
}