From 49fc0e5aa46de720249553cb1d4a9fe325925ac2 Mon Sep 17 00:00:00 2001 From: chea1505 Date: Fri, 5 Jan 2018 01:09:16 +0700 Subject: [PATCH] Use request's standard context instead of Gorillar's context. Use request's standard context (context.Context) instead of Gorillar's Context. You DON'T need to wrap your handlers with Gorillar context.ClearHandler(). There is no memory leak. --- README.md | 12 ------------ doc.go | 8 -------- sessions.go | 33 ++++++++++++++++----------------- store.go | 12 +++++------- store_test.go | 12 ++++++------ 5 files changed, 27 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 10eb7f0..30aa6a8 100644 --- a/README.md +++ b/README.md @@ -48,18 +48,6 @@ secret key used to authenticate the session. Inside the handler, we call some session values in session.Values, which is a `map[interface{}]interface{}`. And finally we call `session.Save()` to save the session in the response. -Important Note: If you aren't using gorilla/mux, you need to wrap your handlers -with -[`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler) -or else you will leak memory! An easy way to do this is to wrap the top-level -mux when calling http.ListenAndServe: - -```go - http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux)) -``` - -The ClearHandler function is provided by the gorilla/context package. - More examples are available [on the Gorilla website](http://www.gorillatoolkit.org/pkg/sessions). diff --git a/doc.go b/doc.go index 591d932..cf5ddc2 100644 --- a/doc.go +++ b/doc.go @@ -55,14 +55,6 @@ session.Save(r, w), and either display an error message or otherwise handle it. Save must be called before writing to the response, otherwise the session cookie will not be sent to the client. -Important Note: If you aren't using gorilla/mux, you need to wrap your handlers -with context.ClearHandler as or else you will leak memory! An easy way to do this -is to wrap the top-level mux when calling http.ListenAndServe: - - http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux)) - -The ClearHandler function is provided by the gorilla/context package. - That's all you need to know for the basic usage. Let's take a look at other options, starting with flash messages. diff --git a/sessions.go b/sessions.go index fe0d2bc..e668866 100644 --- a/sessions.go +++ b/sessions.go @@ -5,12 +5,11 @@ package sessions import ( + "context" "encoding/gob" "fmt" "net/http" "time" - - "github.com/gorilla/context" ) // Default flashes key. @@ -93,8 +92,8 @@ func (s *Session) AddFlash(value interface{}, vars ...string) { // Save is a convenience method to save this session. It is the same as calling // store.Save(request, response, session). You should call Save before writing to // the response or returning from the handler. -func (s *Session) Save(r *http.Request, w http.ResponseWriter) error { - return s.store.Save(r, w, s) +func (s *Session) Save(w http.ResponseWriter) error { + return s.store.Save(w, s) } // Name returns the name used to register the session. @@ -122,52 +121,52 @@ type contextKey int const registryKey contextKey = 0 // GetRegistry returns a registry instance for the current request. +// If there is no registry in the context, create a new Registry and +// add it to the request's context. func GetRegistry(r *http.Request) *Registry { - registry := context.Get(r, registryKey) + c := r.Context() + registry, _ := c.Value(registryKey).(*Registry) if registry != nil { - return registry.(*Registry) + return registry } newRegistry := &Registry{ - request: r, sessions: make(map[string]sessionInfo), } - context.Set(r, registryKey, newRegistry) + *r = *(r.WithContext(context.WithValue(c, registryKey, newRegistry))) return newRegistry } // Registry stores sessions used during a request. type Registry struct { - request *http.Request sessions map[string]sessionInfo } // Get registers and returns a session for the given name and session store. // // It returns a new session if there are no sessions registered for the name. -func (s *Registry) Get(store Store, name string) (session *Session, err error) { +func (registry *Registry) Get(r *http.Request, store Store, name string) (session *Session, err error) { if !isCookieNameValid(name) { return nil, fmt.Errorf("sessions: invalid character in cookie name: %s", name) } - if info, ok := s.sessions[name]; ok { + if info, ok := registry.sessions[name]; ok { session, err = info.s, info.e } else { - session, err = store.New(s.request, name) - session.name = name - s.sessions[name] = sessionInfo{s: session, e: err} + session, err = store.New(r, name) + registry.sessions[name] = sessionInfo{s: session, e: err} } session.store = store return } // Save saves all sessions registered for the current request. -func (s *Registry) Save(w http.ResponseWriter) error { +func (registry *Registry) Save(w http.ResponseWriter) error { var errMulti MultiError - for name, info := range s.sessions { + for name, info := range registry.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(w, session); err != nil { errMulti = append(errMulti, fmt.Errorf( "sessions: error saving session %q -- %v", name, err)) } diff --git a/store.go b/store.go index 4ff6b6c..4b326eb 100644 --- a/store.go +++ b/store.go @@ -30,7 +30,7 @@ type Store interface { New(r *http.Request, name string) (*Session, error) // Save should persist session to the underlying store implementation. - Save(r *http.Request, w http.ResponseWriter, s *Session) error + Save(w http.ResponseWriter, s *Session) error } // CookieStore ---------------------------------------------------------------- @@ -77,7 +77,7 @@ type CookieStore struct { // It returns a new session and an error if the session exists but could // not be decoded. func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) { - return GetRegistry(r).Get(s, name) + return GetRegistry(r).Get(r, s, name) } // New returns a session for the given name without adding it to the registry. @@ -102,8 +102,7 @@ func (s *CookieStore) New(r *http.Request, name string) (*Session, error) { } // Save adds a single session to the response. -func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter, - session *Session) error { +func (s *CookieStore) Save(w http.ResponseWriter, session *Session) error { encoded, err := securecookie.EncodeMulti(session.Name(), session.Values, s.Codecs...) if err != nil { @@ -180,7 +179,7 @@ func (s *FilesystemStore) MaxLength(l int) { // // See CookieStore.Get(). func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) { - return GetRegistry(r).Get(s, name) + return GetRegistry(r).Get(r, s, name) } // New returns a session for the given name without adding it to the registry. @@ -210,8 +209,7 @@ func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) { // deleted from the store path. With this process it enforces the properly // session cookie handling so no need to trust in the cookie management in the // web browser. -func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter, - session *Session) error { +func (s *FilesystemStore) Save(w http.ResponseWriter, session *Session) error { // Delete if max-age is <= 0 if session.Options.MaxAge <= 0 { if err := s.erase(session); err != nil { diff --git a/store_test.go b/store_test.go index 3561e5d..396ca1c 100644 --- a/store_test.go +++ b/store_test.go @@ -64,13 +64,13 @@ func TestGH2MaxLength(t *testing.T) { } session.Values["big"] = make([]byte, base64.StdEncoding.DecodedLen(4096*2)) - err = session.Save(req, w) + err = session.Save(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) + err = session.Save(w) if err != nil { t.Fatal("failed to Save:", err) } @@ -90,13 +90,13 @@ func TestGH8FilesystemStoreDelete(t *testing.T) { t.Fatal("failed to create session", err) } - err = session.Save(req, w) + err = session.Save(w) if err != nil { t.Fatal("failed to save session", err) } session.Options.MaxAge = -1 - err = session.Save(req, w) + err = session.Save(w) if err != nil { t.Fatal("failed to delete session", err) } @@ -116,13 +116,13 @@ func TestGH8FilesystemStoreDelete2(t *testing.T) { t.Fatal("failed to create session", err) } - err = session.Save(req, w) + err = session.Save(w) if err != nil { t.Fatal("failed to save session", err) } session.Options.MaxAge = 0 - err = session.Save(req, w) + err = session.Save(w) if err != nil { t.Fatal("failed to delete session", err) }