update
This commit is contained in:
parent
7ce48c6de5
commit
793a11a5b0
5 changed files with 61 additions and 323 deletions
45
doc.go
45
doc.go
|
@ -22,26 +22,26 @@ The key features are:
|
|||
Let's start with an example that shows the sessions API in a nutshell:
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/admpub/sessions"
|
||||
"github.com/webx-top/echo"
|
||||
)
|
||||
|
||||
var store = sessions.NewCookieStore([]byte("something-very-secret"))
|
||||
|
||||
func MyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func MyHandler(ctx echo.Context) error {
|
||||
// Get a session. We're ignoring the error resulted from decoding an
|
||||
// existing session: Get() always returns a session, even if empty.
|
||||
session, err := store.Get(r, "session-name")
|
||||
session, err := store.Get(ctx, "session-name")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Set some session values.
|
||||
session.Values["foo"] = "bar"
|
||||
session.Values[42] = 43
|
||||
// Save it before we write to the response/return from the handler.
|
||||
session.Save(r, w)
|
||||
session.Save(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
First we initialize a session store calling NewCookieStore() and passing a
|
||||
|
@ -72,12 +72,11 @@ Ruby On Rails a few years back. When we request a flash message, it is removed
|
|||
from the session. To add a flash, call session.AddFlash(), and to get all
|
||||
flashes, call session.Flashes(). Here is an example:
|
||||
|
||||
func MyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func MyHandler(ctx echo.Context) error {
|
||||
// Get a session.
|
||||
session, err := store.Get(r, "session-name")
|
||||
session, err := store.Get(ctx, "session-name")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
return error
|
||||
}
|
||||
|
||||
// Get the previously flashes, if any.
|
||||
|
@ -87,7 +86,8 @@ flashes, call session.Flashes(). Here is an example:
|
|||
// Set a new flash.
|
||||
session.AddFlash("Hello, flash messages world!")
|
||||
}
|
||||
session.Save(r, w)
|
||||
session.Save(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
Flash messages are useful to set information to be read after a redirection,
|
||||
|
@ -99,7 +99,8 @@ so it is easy to register new datatypes for storage in sessions:
|
|||
|
||||
import(
|
||||
"encoding/gob"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/admpub/sessions"
|
||||
"github.com/webx-top/echo"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
|
@ -126,11 +127,10 @@ values of those types to and from our sessions.
|
|||
Note that because session values are stored in a map[string]interface{}, there's
|
||||
a need to type-assert data when retrieving it. We'll use the Person struct we registered above:
|
||||
|
||||
func MyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := store.Get(r, "session-name")
|
||||
func MyHandler(ctx echo.Context) error {
|
||||
session, err := store.Get(ctx, "session-name")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Retrieve our struct and type-assert it
|
||||
|
@ -141,6 +141,8 @@ a need to type-assert data when retrieving it. We'll use the Person struct we re
|
|||
}
|
||||
|
||||
// Now we can use our person object
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
By default, session cookies last for a month. This is probably too long for
|
||||
|
@ -182,15 +184,16 @@ at once: it's sessions.Save(). Here's an example:
|
|||
|
||||
var store = sessions.NewCookieStore([]byte("something-very-secret"))
|
||||
|
||||
func MyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func MyHandler(ctx echo.Context) error {
|
||||
// Get a session and set a value.
|
||||
session1, _ := store.Get(r, "session-one")
|
||||
session1, _ := store.Get(ctx, "session-one")
|
||||
session1.Values["foo"] = "bar"
|
||||
// Get another session and set another value.
|
||||
session2, _ := store.Get(r, "session-two")
|
||||
session2, _ := store.Get(ctx, "session-two")
|
||||
session2.Values[42] = 43
|
||||
// Save all sessions.
|
||||
sessions.Save(r, w)
|
||||
sessions.Save(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
This is possible because when we call Get() from a session store, it adds the
|
||||
|
|
45
sessions.go
45
sessions.go
|
@ -11,7 +11,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/webx-top/echo"
|
||||
"github.com/webx-top/echo/engine"
|
||||
)
|
||||
|
||||
// Default flashes key.
|
||||
|
@ -92,7 +91,7 @@ func (s *Session) AddFlash(value interface{}, vars ...string) {
|
|||
// store.Save(request, response, session). You should call Save before writing to
|
||||
// the response or returning from the handler.
|
||||
func (s *Session) Save(ctx echo.Context) error {
|
||||
return s.store.Save(ctx.Request(), ctx.Response(), s)
|
||||
return s.store.Save(ctx, s)
|
||||
}
|
||||
|
||||
// Name returns the name used to register the session.
|
||||
|
@ -113,30 +112,26 @@ type sessionInfo struct {
|
|||
e error
|
||||
}
|
||||
|
||||
// contextKey is the type used to store the registry in the context.
|
||||
type contextKey int
|
||||
|
||||
// registryKey is the key used to store the registry in the context.
|
||||
const registryKey contextKey = 0
|
||||
const registryKey = `webx:mw.sessions`
|
||||
|
||||
// GetRegistry returns a registry instance for the current request.
|
||||
func GetRegistry(ctx echo.Context) *Registry {
|
||||
r := ctx.Request()
|
||||
registry := engine.Get(r, registryKey)
|
||||
if registry != nil {
|
||||
return registry.(*Registry)
|
||||
registry, ok := ctx.Get(registryKey).(*Registry)
|
||||
if ok {
|
||||
return registry
|
||||
}
|
||||
newRegistry := &Registry{
|
||||
request: r,
|
||||
registry = &Registry{
|
||||
context: ctx,
|
||||
sessions: make(map[string]sessionInfo),
|
||||
}
|
||||
engine.Set(r, registryKey, newRegistry)
|
||||
return newRegistry
|
||||
ctx.Set(registryKey, registry)
|
||||
return registry
|
||||
}
|
||||
|
||||
// Registry stores sessions used during a request.
|
||||
type Registry struct {
|
||||
request engine.Request
|
||||
context echo.Context
|
||||
sessions map[string]sessionInfo
|
||||
}
|
||||
|
||||
|
@ -147,7 +142,7 @@ func (s *Registry) Get(store Store, name string) (session *Session, err error) {
|
|||
if info, ok := s.sessions[name]; ok {
|
||||
session, err = info.s, info.e
|
||||
} else {
|
||||
session, err = store.New(s.request, name)
|
||||
session, err = store.New(s.context, name)
|
||||
session.name = name
|
||||
s.sessions[name] = sessionInfo{s: session, e: err}
|
||||
}
|
||||
|
@ -156,14 +151,14 @@ func (s *Registry) Get(store Store, name string) (session *Session, err error) {
|
|||
}
|
||||
|
||||
// Save saves all sessions registered for the current request.
|
||||
func (s *Registry) Save(w engine.Response) error {
|
||||
func (s *Registry) Save(ctx echo.Context) error {
|
||||
var errMulti MultiError
|
||||
for name, info := range s.sessions {
|
||||
session := info.s
|
||||
if session.store == nil {
|
||||
errMulti = append(errMulti, fmt.Errorf(
|
||||
"sessions: missing store for session %q", name))
|
||||
} else if err := session.store.Save(s.request, w, session); err != nil {
|
||||
} else if err := session.store.Save(ctx, session); err != nil {
|
||||
errMulti = append(errMulti, fmt.Errorf(
|
||||
"sessions: error saving session %q -- %v", name, err))
|
||||
}
|
||||
|
@ -182,7 +177,7 @@ func init() {
|
|||
|
||||
// Save saves all sessions used during the current request.
|
||||
func Save(ctx echo.Context) error {
|
||||
return GetRegistry(ctx).Save(ctx.Response())
|
||||
return GetRegistry(ctx).Save(ctx)
|
||||
}
|
||||
|
||||
// NewCookie returns an http.Cookie with the options set. It also sets
|
||||
|
@ -208,6 +203,18 @@ func NewCookie(name, value string, options *Options) *http.Cookie {
|
|||
return cookie
|
||||
}
|
||||
|
||||
// SetCookie for echo
|
||||
func SetCookie(ctx echo.Context, key string, value string, options *Options) {
|
||||
ctx.SetCookie(
|
||||
key, value,
|
||||
options.MaxAge,
|
||||
options.Path,
|
||||
options.Domain,
|
||||
options.Secure,
|
||||
options.HttpOnly,
|
||||
)
|
||||
}
|
||||
|
||||
// Error ----------------------------------------------------------------------
|
||||
|
||||
// MultiError stores multiple errors.
|
||||
|
|
197
sessions_test.go
197
sessions_test.go
|
@ -1,197 +0,0 @@
|
|||
// Copyright 2012 The Gorilla Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sessions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ResponseRecorder
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// ResponseRecorder is an implementation of http.ResponseWriter that
|
||||
// records its mutations for later inspection in tests.
|
||||
type ResponseRecorder struct {
|
||||
Code int // the HTTP response code from WriteHeader
|
||||
HeaderMap http.Header // the HTTP response headers
|
||||
Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
|
||||
Flushed bool
|
||||
}
|
||||
|
||||
// NewRecorder returns an initialized ResponseRecorder.
|
||||
func NewRecorder() *ResponseRecorder {
|
||||
return &ResponseRecorder{
|
||||
HeaderMap: make(http.Header),
|
||||
Body: new(bytes.Buffer),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
|
||||
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
|
||||
const DefaultRemoteAddr = "1.2.3.4"
|
||||
|
||||
// Header returns the response headers.
|
||||
func (rw *ResponseRecorder) Header() http.Header {
|
||||
return rw.HeaderMap
|
||||
}
|
||||
|
||||
// Write always succeeds and writes to rw.Body, if not nil.
|
||||
func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
|
||||
if rw.Body != nil {
|
||||
rw.Body.Write(buf)
|
||||
}
|
||||
if rw.Code == 0 {
|
||||
rw.Code = http.StatusOK
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
// WriteHeader sets rw.Code.
|
||||
func (rw *ResponseRecorder) WriteHeader(code int) {
|
||||
rw.Code = code
|
||||
}
|
||||
|
||||
// Flush sets rw.Flushed to true.
|
||||
func (rw *ResponseRecorder) Flush() {
|
||||
rw.Flushed = true
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type FlashMessage struct {
|
||||
Type int
|
||||
Message string
|
||||
}
|
||||
|
||||
func TestFlashes(t *testing.T) {
|
||||
var req *http.Request
|
||||
var rsp *ResponseRecorder
|
||||
var hdr http.Header
|
||||
var err error
|
||||
var ok bool
|
||||
var cookies []string
|
||||
var session *Session
|
||||
var flashes []interface{}
|
||||
|
||||
store := NewCookieStore([]byte("secret-key"))
|
||||
|
||||
// Round 1 ----------------------------------------------------------------
|
||||
|
||||
req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
|
||||
rsp = NewRecorder()
|
||||
// Get a session.
|
||||
if session, err = store.Get(req, "session-key"); err != nil {
|
||||
t.Fatalf("Error getting session: %v", err)
|
||||
}
|
||||
// Get a flash.
|
||||
flashes = session.Flashes()
|
||||
if len(flashes) != 0 {
|
||||
t.Errorf("Expected empty flashes; Got %v", flashes)
|
||||
}
|
||||
// Add some flashes.
|
||||
session.AddFlash("foo")
|
||||
session.AddFlash("bar")
|
||||
// Custom key.
|
||||
session.AddFlash("baz", "custom_key")
|
||||
// Save.
|
||||
if err = Save(req, rsp); err != nil {
|
||||
t.Fatalf("Error saving session: %v", err)
|
||||
}
|
||||
hdr = rsp.Header()
|
||||
cookies, ok = hdr["Set-Cookie"]
|
||||
if !ok || len(cookies) != 1 {
|
||||
t.Fatal("No cookies. Header:", hdr)
|
||||
}
|
||||
|
||||
// Round 2 ----------------------------------------------------------------
|
||||
|
||||
req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
|
||||
req.Header.Add("Cookie", cookies[0])
|
||||
rsp = NewRecorder()
|
||||
// Get a session.
|
||||
if session, err = store.Get(req, "session-key"); err != nil {
|
||||
t.Fatalf("Error getting session: %v", err)
|
||||
}
|
||||
// Check all saved values.
|
||||
flashes = session.Flashes()
|
||||
if len(flashes) != 2 {
|
||||
t.Fatalf("Expected flashes; Got %v", flashes)
|
||||
}
|
||||
if flashes[0] != "foo" || flashes[1] != "bar" {
|
||||
t.Errorf("Expected foo,bar; Got %v", flashes)
|
||||
}
|
||||
flashes = session.Flashes()
|
||||
if len(flashes) != 0 {
|
||||
t.Errorf("Expected dumped flashes; Got %v", flashes)
|
||||
}
|
||||
// Custom key.
|
||||
flashes = session.Flashes("custom_key")
|
||||
if len(flashes) != 1 {
|
||||
t.Errorf("Expected flashes; Got %v", flashes)
|
||||
} else if flashes[0] != "baz" {
|
||||
t.Errorf("Expected baz; Got %v", flashes)
|
||||
}
|
||||
flashes = session.Flashes("custom_key")
|
||||
if len(flashes) != 0 {
|
||||
t.Errorf("Expected dumped flashes; Got %v", flashes)
|
||||
}
|
||||
|
||||
// Round 3 ----------------------------------------------------------------
|
||||
// Custom type
|
||||
|
||||
req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
|
||||
rsp = NewRecorder()
|
||||
// Get a session.
|
||||
if session, err = store.Get(req, "session-key"); err != nil {
|
||||
t.Fatalf("Error getting session: %v", err)
|
||||
}
|
||||
// Get a flash.
|
||||
flashes = session.Flashes()
|
||||
if len(flashes) != 0 {
|
||||
t.Errorf("Expected empty flashes; Got %v", flashes)
|
||||
}
|
||||
// Add some flashes.
|
||||
session.AddFlash(&FlashMessage{42, "foo"})
|
||||
// Save.
|
||||
if err = Save(req, rsp); err != nil {
|
||||
t.Fatalf("Error saving session: %v", err)
|
||||
}
|
||||
hdr = rsp.Header()
|
||||
cookies, ok = hdr["Set-Cookie"]
|
||||
if !ok || len(cookies) != 1 {
|
||||
t.Fatal("No cookies. Header:", hdr)
|
||||
}
|
||||
|
||||
// Round 4 ----------------------------------------------------------------
|
||||
// Custom type
|
||||
|
||||
req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
|
||||
req.Header.Add("Cookie", cookies[0])
|
||||
rsp = NewRecorder()
|
||||
// Get a session.
|
||||
if session, err = store.Get(req, "session-key"); err != nil {
|
||||
t.Fatalf("Error getting session: %v", err)
|
||||
}
|
||||
// Check all saved values.
|
||||
flashes = session.Flashes()
|
||||
if len(flashes) != 1 {
|
||||
t.Fatalf("Expected flashes; Got %v", flashes)
|
||||
}
|
||||
custom := flashes[0].(FlashMessage)
|
||||
if custom.Type != 42 || custom.Message != "foo" {
|
||||
t.Errorf("Expected %#v, got %#v", FlashMessage{42, "foo"}, custom)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
gob.Register(FlashMessage{})
|
||||
}
|
24
store.go
24
store.go
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/webx-top/echo"
|
||||
"github.com/webx-top/echo/engine"
|
||||
)
|
||||
|
||||
// Store is an interface for custom session stores.
|
||||
|
@ -28,10 +27,10 @@ type Store interface {
|
|||
//
|
||||
// Note that New should never return a nil session, even in the case of
|
||||
// an error if using the Registry infrastructure to cache the session.
|
||||
New(r engine.Request, name string) (*Session, error)
|
||||
New(ctx echo.Context, name string) (*Session, error)
|
||||
|
||||
// Save should persist session to the underlying store implementation.
|
||||
Save(r engine.Request, w engine.Response, s *Session) error
|
||||
Save(ctx echo.Context, s *Session) error
|
||||
}
|
||||
|
||||
// CookieStore ----------------------------------------------------------------
|
||||
|
@ -86,13 +85,13 @@ func (s *CookieStore) Get(ctx echo.Context, name string) (*Session, error) {
|
|||
// The difference between New() and Get() is that calling New() twice will
|
||||
// decode the session data twice, while Get() registers and reuses the same
|
||||
// decoded session after the first call.
|
||||
func (s *CookieStore) New(r engine.Request, name string) (*Session, error) {
|
||||
func (s *CookieStore) New(ctx echo.Context, name string) (*Session, error) {
|
||||
session := NewSession(s, name)
|
||||
opts := *s.Options
|
||||
session.Options = &opts
|
||||
session.IsNew = true
|
||||
var err error
|
||||
if v := r.Cookie(name); v != `` {
|
||||
if v := ctx.Request().Cookie(name); len(v) > 0 {
|
||||
err = securecookie.DecodeMulti(name, v, &session.Values,
|
||||
s.Codecs...)
|
||||
if err == nil {
|
||||
|
@ -103,14 +102,13 @@ func (s *CookieStore) New(r engine.Request, name string) (*Session, error) {
|
|||
}
|
||||
|
||||
// Save adds a single session to the response.
|
||||
func (s *CookieStore) Save(r engine.Request, w engine.Response,
|
||||
session *Session) error {
|
||||
func (s *CookieStore) Save(ctx echo.Context, session *Session) error {
|
||||
encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
|
||||
s.Codecs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.SetCookie(NewCookie(session.Name(), encoded, session.Options))
|
||||
SetCookie(ctx, session.Name(), encoded, session.Options)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -187,13 +185,13 @@ func (s *FilesystemStore) Get(ctx echo.Context, name string) (*Session, error) {
|
|||
// New returns a session for the given name without adding it to the registry.
|
||||
//
|
||||
// See CookieStore.New().
|
||||
func (s *FilesystemStore) New(r engine.Request, name string) (*Session, error) {
|
||||
func (s *FilesystemStore) New(ctx echo.Context, name string) (*Session, error) {
|
||||
session := NewSession(s, name)
|
||||
opts := *s.Options
|
||||
session.Options = &opts
|
||||
session.IsNew = true
|
||||
var err error
|
||||
if v := r.Cookie(name); v != `` {
|
||||
if v := ctx.Request().Cookie(name); len(v) > 0 {
|
||||
err = securecookie.DecodeMulti(name, v, &session.ID, s.Codecs...)
|
||||
if err == nil {
|
||||
err = s.load(session)
|
||||
|
@ -206,9 +204,9 @@ func (s *FilesystemStore) New(r engine.Request, name string) (*Session, error) {
|
|||
}
|
||||
|
||||
// Save adds a single session to the response.
|
||||
func (s *FilesystemStore) Save(r engine.Request, w engine.Response,
|
||||
func (s *FilesystemStore) Save(ctx echo.Context,
|
||||
session *Session) error {
|
||||
if session.ID == "" {
|
||||
if len(session.ID) == 0 {
|
||||
// Because the ID is used in the filename, encode it to
|
||||
// use alphanumeric characters only.
|
||||
session.ID = strings.TrimRight(
|
||||
|
@ -223,7 +221,7 @@ func (s *FilesystemStore) Save(r engine.Request, w engine.Response,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.SetCookie(NewCookie(session.Name(), encoded, session.Options))
|
||||
SetCookie(ctx, session.Name(), encoded, session.Options)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
package sessions
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test for GH-8 for CookieStore
|
||||
func TestGH8CookieStore(t *testing.T) {
|
||||
originalPath := "/"
|
||||
store := NewCookieStore()
|
||||
store.Options.Path = originalPath
|
||||
req, err := http.NewRequest("GET", "http://www.example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create request", err)
|
||||
}
|
||||
|
||||
session, err := store.New(req, "hello")
|
||||
if err != nil {
|
||||
t.Fatal("failed to create session", err)
|
||||
}
|
||||
|
||||
store.Options.Path = "/foo"
|
||||
if session.Options.Path != originalPath {
|
||||
t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for GH-8 for FilesystemStore
|
||||
func TestGH8FilesystemStore(t *testing.T) {
|
||||
originalPath := "/"
|
||||
store := NewFilesystemStore("")
|
||||
store.Options.Path = originalPath
|
||||
req, err := http.NewRequest("GET", "http://www.example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create request", err)
|
||||
}
|
||||
|
||||
session, err := store.New(req, "hello")
|
||||
if err != nil {
|
||||
t.Fatal("failed to create session", err)
|
||||
}
|
||||
|
||||
store.Options.Path = "/foo"
|
||||
if session.Options.Path != originalPath {
|
||||
t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for GH-2.
|
||||
func TestGH2MaxLength(t *testing.T) {
|
||||
store := NewFilesystemStore("", []byte("some key"))
|
||||
req, err := http.NewRequest("GET", "http://www.example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create request", err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
session, err := store.New(req, "my session")
|
||||
session.Values["big"] = make([]byte, base64.StdEncoding.DecodedLen(4096*2))
|
||||
err = session.Save(req, w)
|
||||
if err == nil {
|
||||
t.Fatal("expected an error, got nil")
|
||||
}
|
||||
|
||||
store.MaxLength(4096 * 3) // A bit more than the value size to account for encoding overhead.
|
||||
err = session.Save(req, w)
|
||||
if err != nil {
|
||||
t.Fatal("failed to Save:", err)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue