From 9df1e639cd3aa013215973a559424f37b4e783c0 Mon Sep 17 00:00:00 2001 From: tiannianshou Date: Thu, 11 Jun 2020 13:58:44 +0800 Subject: [PATCH 1/9] Update dependency --- .travis.yml | 2 +- README.md | 2 +- go.mod | 9 +++++---- go.sum | 23 +++++++++++++++++------ 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index bc51dfc..b205250 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: go sudo: false go_import_path: github.com/go-session/session go: - - 1.7 + - 1.13 before_install: - go get -t -v ./... diff --git a/README.md b/README.md index 3e678b9..0d249d2 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ $ ./server ## MIT License - Copyright (c) 2018 Lyric + Copyright (c) 2020 Lyric [Build-Status-Url]: https://travis-ci.org/go-session/session [Build-Status-Image]: https://travis-ci.org/go-session/session.svg?branch=master diff --git a/go.mod b/go.mod index 06abe7f..eb4c65f 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,9 @@ module github.com/go-session/session +go 1.14 + require ( - github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect - github.com/jtolds/gls v4.2.1+incompatible // indirect - github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect - github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c + github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect + github.com/smartystreets/assertions v1.1.0 // indirect + github.com/smartystreets/goconvey v1.6.4 ) diff --git a/go.sum b/go.sum index 2e7f1bd..d2f0ef1 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,19 @@ -github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= -github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= -github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= -github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= From 9d567cb1cd8eebbfce90330418345af0795ffe2d Mon Sep 17 00:00:00 2001 From: tiannianshou Date: Thu, 11 Jun 2020 14:00:23 +0800 Subject: [PATCH 2/9] Update version --- session.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/session.go b/session.go index 94042c8..1e18f9b 100644 --- a/session.go +++ b/session.go @@ -13,6 +13,9 @@ import ( "time" ) +// Version # of session +const Version = "3.1.4" + var ( // ErrInvalidSessionID invalid session id ErrInvalidSessionID = errors.New("invalid session id") From 40e7c530e3ffa8beaa848ec681a14abb18449eb0 Mon Sep 17 00:00:00 2001 From: Shebin Date: Fri, 25 Jun 2021 22:15:20 +0800 Subject: [PATCH 3/9] added samsite support for cookie --- session.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/session.go b/session.go index 1e18f9b..e2ba5e5 100644 --- a/session.go +++ b/session.go @@ -30,6 +30,7 @@ var defaultOptions = options{ cookieLifeTime: 3600 * 24 * 7, expired: 7200, secure: true, + sameSite: http.SameSiteDefaultMode, sessionID: func(_ context.Context) string { return newUUID() }, @@ -43,6 +44,7 @@ type options struct { cookieLifeTime int secure bool domain string + sameSite http.SameSite expired int64 sessionID IDHandlerFunc enableSetCookie bool @@ -90,6 +92,13 @@ func SetSecure(secure bool) Option { } } +// SetSameSite Set SameSite attribute of the cookie +func SetSameSite(sameSite http.SameSite) Option { + return func(o *options) { + o.sameSite = sameSite + } +} + // SetExpired Set session expiration time (in seconds) func SetExpired(expired int64) Option { return func(o *options) { @@ -261,6 +270,7 @@ func (m *Manager) setCookie(sessionID string, w http.ResponseWriter, r *http.Req HttpOnly: true, Secure: m.isSecure(r), Domain: m.opts.domain, + SameSite: m.opts.sameSite, } if v := m.opts.cookieLifeTime; v > 0 { From 01a634a8379b26697042938538782b0c23259787 Mon Sep 17 00:00:00 2001 From: LyricTian Date: Fri, 10 Dec 2021 07:27:36 +0800 Subject: [PATCH 4/9] Use /v3 module and fix some warning --- .gitignore | 2 ++ README.md | 20 +++++++++++--------- context_test.go | 6 +++--- default_test.go | 10 +++++----- doc.go | 2 +- go.mod | 2 +- go.sum | 4 ---- session_test.go | 10 +++++----- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index a1338d6..9e95391 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 .glide/ + +.vscode diff --git a/README.md b/README.md index 0d249d2..eb933b3 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # session -> A efficient, safely and easy-to-use session library for Go. +> A efficient, safely and easy-to-use session library for Go. -[![Build][Build-Status-Image]][Build-Status-Url] [![Codecov][codecov-image]][codecov-url] [![ReportCard][reportcard-image]][reportcard-url] [![GoDoc][godoc-image]][godoc-url] [![License][license-image]][license-url] +[![Build][build-status-image]][build-status-url] [![Codecov][codecov-image]][codecov-url] [![ReportCard][reportcard-image]][reportcard-url] [![GoDoc][godoc-image]][godoc-url] [![License][license-image]][license-url] ## Quick Start ### Download and install ```bash -$ go get -v github.com/go-session/session +go get -v github.com/go-session/session/v3 ``` ### Create file `server.go` @@ -22,7 +22,7 @@ import ( "fmt" "net/http" - "github.com/go-session/session" + session "github.com/go-session/session/v3" ) func main() { @@ -65,15 +65,17 @@ func main() { ### Build and run ```bash -$ go build server.go -$ ./server +go build server.go +./server ``` ### Open in your web browser +```text foo:bar +``` ## Features @@ -102,10 +104,10 @@ $ ./server ## MIT License - Copyright (c) 2020 Lyric + Copyright (c) 2021 Lyric -[Build-Status-Url]: https://travis-ci.org/go-session/session -[Build-Status-Image]: https://travis-ci.org/go-session/session.svg?branch=master +[build-status-url]: https://travis-ci.org/go-session/session +[build-status-image]: https://travis-ci.org/go-session/session.svg?branch=master [codecov-url]: https://codecov.io/gh/go-session/session [codecov-image]: https://codecov.io/gh/go-session/session/branch/master/graph/badge.svg [reportcard-url]: https://goreportcard.com/report/github.com/go-session/session diff --git a/context_test.go b/context_test.go index f769d81..4b171cb 100644 --- a/context_test.go +++ b/context_test.go @@ -12,15 +12,15 @@ import ( func TestContext(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var ctxKey interface{} = "ctx" - ctx := context.WithValue(context.Background(), ctxKey, "bar") + type ctxKey struct{} + ctx := context.WithValue(context.Background(), ctxKey{}, "bar") store, err := Start(ctx, w, r) if err != nil { t.Error(err) return } - ctxValue := store.Context().Value(ctxKey) + ctxValue := store.Context().Value(ctxKey{}) if !reflect.DeepEqual(ctxValue, "bar") { t.Error("Not expected value:", ctxValue) return diff --git a/default_test.go b/default_test.go index d452e1f..3acc28f 100644 --- a/default_test.go +++ b/default_test.go @@ -20,7 +20,7 @@ func init() { func TestDefaultStart(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - store, err := Start(nil, w, r) + store, err := Start(r.Context(), w, r) if err != nil { t.Error(err) return @@ -69,7 +69,7 @@ func TestDefaultStart(t *testing.T) { func TestDefaultDestroy(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Query().Get("logout") == "1" { - err := Destroy(nil, w, r) + err := Destroy(r.Context(), w, r) if err != nil { t.Error(err) return @@ -78,7 +78,7 @@ func TestDefaultDestroy(t *testing.T) { return } - store, err := Start(nil, w, r) + store, err := Start(r.Context(), w, r) if err != nil { t.Error(err) return @@ -133,14 +133,14 @@ func TestDefaultDestroy(t *testing.T) { func TestDefaultRefresh(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - store, err := Start(nil, w, r) + store, err := Start(r.Context(), w, r) if err != nil { t.Error(err) return } if r.URL.Query().Get("refresh") == "1" { - vstore, verr := Refresh(nil, w, r) + vstore, verr := Refresh(r.Context(), w, r) if verr != nil { t.Error(err) return diff --git a/doc.go b/doc.go index 295a420..a6f3c1d 100644 --- a/doc.go +++ b/doc.go @@ -11,7 +11,7 @@ Example: "fmt" "net/http" - "github.com/go-session/session" + session "github.com/go-session/session/v3" ) func main() { diff --git a/go.mod b/go.mod index eb4c65f..30e1195 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/go-session/session +module github.com/go-session/session/v3 go 1.14 diff --git a/go.sum b/go.sum index d2f0ef1..045b839 100644 --- a/go.sum +++ b/go.sum @@ -3,17 +3,13 @@ github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/session_test.go b/session_test.go index 58f3669..6a331cf 100644 --- a/session_test.go +++ b/session_test.go @@ -17,7 +17,7 @@ func TestSessionStart(t *testing.T) { ) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - store, err := manager.Start(nil, w, r) + store, err := manager.Start(r.Context(), w, r) if err != nil { t.Error(err) return @@ -72,7 +72,7 @@ func TestSessionDestroy(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Query().Get("logout") == "1" { - err := manager.Destroy(nil, w, r) + err := manager.Destroy(r.Context(), w, r) if err != nil { t.Error(err) return @@ -81,7 +81,7 @@ func TestSessionDestroy(t *testing.T) { return } - store, err := manager.Start(nil, w, r) + store, err := manager.Start(r.Context(), w, r) if err != nil { t.Error(err) return @@ -142,14 +142,14 @@ func TestSessionRefresh(t *testing.T) { ) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - store, err := manager.Start(nil, w, r) + store, err := manager.Start(r.Context(), w, r) if err != nil { t.Error(err) return } if r.URL.Query().Get("refresh") == "1" { - vstore, verr := manager.Refresh(nil, w, r) + vstore, verr := manager.Refresh(r.Context(), w, r) if verr != nil { t.Error(err) return From 8deeff6dc327578f75b4d4d9620d8bb4936dfabd Mon Sep 17 00:00:00 2001 From: LyricTian Date: Wed, 16 Mar 2022 20:45:56 +0800 Subject: [PATCH 5/9] fix: Update go mod version --- go.mod | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 30e1195..b28867f 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,11 @@ module github.com/go-session/session/v3 -go 1.14 +go 1.17 + +require github.com/smartystreets/goconvey v1.6.4 require ( github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/smartystreets/assertions v1.1.0 // indirect - github.com/smartystreets/goconvey v1.6.4 ) From 0e9e239e8080b47cce38eab0890ee8ef861d9931 Mon Sep 17 00:00:00 2001 From: HHongSeungWoo Date: Tue, 17 May 2022 12:15:58 +0900 Subject: [PATCH 6/9] feat: cookie secure --- session.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/session.go b/session.go index e2ba5e5..f5ea71b 100644 --- a/session.go +++ b/session.go @@ -7,6 +7,7 @@ import ( "encoding/base64" "errors" "fmt" + "net" "net/http" "net/url" "strings" @@ -250,6 +251,11 @@ func (m *Manager) isSecure(r *http.Request) bool { if !m.opts.secure { return false } + host, _, _ := net.SplitHostPort(r.RemoteAddr) + ip := net.ParseIP(host) + if ip.IsLoopback() || ip.IsPrivate() { + return true + } if r.URL.Scheme != "" { return r.URL.Scheme == "https" } From 38cb0525c80b843517bd259852829fe07205519f Mon Sep 17 00:00:00 2001 From: LyricTian Date: Mon, 13 Feb 2023 11:37:57 +0800 Subject: [PATCH 7/9] fix: Use skipmap as memory storage --- context.go | 2 +- context_test.go | 4 +- default.go | 4 +- default_test.go | 8 ++-- go.mod | 1 + go.sum | 10 +++++ session.go | 53 +++++++++++++-------------- session_test.go | 8 ++-- store.go | 97 +++++++++++++++---------------------------------- util.go | 2 +- 10 files changed, 79 insertions(+), 110 deletions(-) diff --git a/context.go b/context.go index 17baf60..9cde2a5 100644 --- a/context.go +++ b/context.go @@ -5,7 +5,7 @@ import ( "net/http" ) -// Define the key in the context +// Define the keys in the context type ( ctxResKey struct{} ctxReqKey struct{} diff --git a/context_test.go b/context_test.go index 4b171cb..2822166 100644 --- a/context_test.go +++ b/context_test.go @@ -3,7 +3,7 @@ package session import ( "context" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "reflect" @@ -48,7 +48,7 @@ func TestContext(t *testing.T) { return } - buf, _ := ioutil.ReadAll(res.Body) + buf, _ := io.ReadAll(res.Body) res.Body.Close() if string(buf) != "ok" { t.Error("Not expected value:", string(buf)) diff --git a/default.go b/default.go index dfd8979..7d8c1dc 100644 --- a/default.go +++ b/default.go @@ -18,7 +18,7 @@ func manager(opt ...Option) *Manager { return internalManager } -// InitManager initialize the global session management instance +// Initialize the global session management instance func InitManager(opt ...Option) { manager(opt...) } @@ -33,7 +33,7 @@ func Destroy(ctx context.Context, w http.ResponseWriter, r *http.Request) error return manager().Destroy(ctx, w, r) } -// Refresh a session and return to session storage +// Refresh and return session storage func Refresh(ctx context.Context, w http.ResponseWriter, r *http.Request) (Store, error) { return manager().Refresh(ctx, w, r) } diff --git a/default_test.go b/default_test.go index 3acc28f..2b0ec36 100644 --- a/default_test.go +++ b/default_test.go @@ -2,7 +2,7 @@ package session import ( "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -59,7 +59,7 @@ func TestDefaultStart(t *testing.T) { So(err, ShouldBeNil) So(res, ShouldNotBeNil) - buf, err := ioutil.ReadAll(res.Body) + buf, err := io.ReadAll(res.Body) So(err, ShouldBeNil) res.Body.Close() So(string(buf), ShouldEqual, "bar:true") @@ -124,7 +124,7 @@ func TestDefaultDestroy(t *testing.T) { So(err, ShouldBeNil) So(res, ShouldNotBeNil) - buf, err := ioutil.ReadAll(res.Body) + buf, err := io.ReadAll(res.Body) So(err, ShouldBeNil) res.Body.Close() So(string(buf), ShouldEqual, ":false") @@ -185,7 +185,7 @@ func TestDefaultRefresh(t *testing.T) { So(len(res.Cookies()), ShouldBeGreaterThan, 0) So(res.Cookies()[0].Value, ShouldNotEqual, cookie.Value) - buf, err := ioutil.ReadAll(res.Body) + buf, err := io.ReadAll(res.Body) So(err, ShouldBeNil) res.Body.Close() So(string(buf), ShouldEqual, "bar:true") diff --git a/go.mod b/go.mod index b28867f..22c7c0e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.17 require github.com/smartystreets/goconvey v1.6.4 require ( + github.com/bytedance/gopkg v0.0.0-20221122125632-68358b8ecec6 // indirect github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/smartystreets/assertions v1.1.0 // indirect diff --git a/go.sum b/go.sum index 045b839..49172dc 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,25 @@ +github.com/bytedance/gopkg v0.0.0-20221122125632-68358b8ecec6 h1:FCLDGi1EmB7JzjVVYNZiqc/zAJj2BQ5M0lfkVOxbfs8= +github.com/bytedance/gopkg v0.0.0-20221122125632-68358b8ecec6/go.mod h1:5FoAH5xUHHCMDvQPy1rnj8moqLkLHFaDVBjHhcFwEi0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/session.go b/session.go index f5ea71b..1c3e11b 100644 --- a/session.go +++ b/session.go @@ -18,11 +18,10 @@ import ( const Version = "3.1.4" var ( - // ErrInvalidSessionID invalid session id - ErrInvalidSessionID = errors.New("invalid session id") + ErrInvalidSessionID = errors.New("Invalid session id") ) -// IDHandlerFunc Define the handler to get the session id +// Define the handler to get the session id type IDHandlerFunc func(context.Context) string // Define default options @@ -55,66 +54,65 @@ type options struct { store ManagerStore } -// Option A session parameter options type Option func(*options) -// SetSign Set the session id signature value +// Set the session id signature value func SetSign(sign []byte) Option { return func(o *options) { o.sign = sign } } -// SetCookieName Set the cookie name +// Set the cookie name func SetCookieName(cookieName string) Option { return func(o *options) { o.cookieName = cookieName } } -// SetCookieLifeTime Set the cookie expiration time (in seconds) +// Set the cookie expiration time (in seconds) func SetCookieLifeTime(cookieLifeTime int) Option { return func(o *options) { o.cookieLifeTime = cookieLifeTime } } -// SetDomain Set the domain name of the cookie +// Set the domain name of the cookie func SetDomain(domain string) Option { return func(o *options) { o.domain = domain } } -// SetSecure Set cookie security +// Set cookie security func SetSecure(secure bool) Option { return func(o *options) { o.secure = secure } } -// SetSameSite Set SameSite attribute of the cookie +// Set SameSite attribute of the cookie func SetSameSite(sameSite http.SameSite) Option { return func(o *options) { o.sameSite = sameSite } } -// SetExpired Set session expiration time (in seconds) +// Set session expiration time (in seconds) func SetExpired(expired int64) Option { return func(o *options) { o.expired = expired } } -// SetSessionID Set callback function to generate session id +// Set callback function to generate session id func SetSessionID(handler IDHandlerFunc) Option { return func(o *options) { o.sessionID = handler } } -// SetEnableSetCookie Enable writing session id to cookie +// Enable writing session id to cookie // (enabled by default, can be turned off if no cookie is written) func SetEnableSetCookie(enableSetCookie bool) Option { return func(o *options) { @@ -122,21 +120,21 @@ func SetEnableSetCookie(enableSetCookie bool) Option { } } -// SetEnableSIDInURLQuery Allow session id from URL query parameters (enabled by default) +// Allow session id from URL query parameters (enabled by default) func SetEnableSIDInURLQuery(enableSIDInURLQuery bool) Option { return func(o *options) { o.enableSIDInURLQuery = enableSIDInURLQuery } } -// SetEnableSIDInHTTPHeader Allow session id to be obtained from the request header +// Allow session id to be obtained from the request header func SetEnableSIDInHTTPHeader(enableSIDInHTTPHeader bool) Option { return func(o *options) { o.enableSIDInHTTPHeader = enableSIDInHTTPHeader } } -// SetSessionNameInHTTPHeader The key name in the request header where the session ID is stored +// The key name in the request header where the session ID is stored // (if it is empty, the default is the cookie name) func SetSessionNameInHTTPHeader(sessionNameInHTTPHeader string) Option { return func(o *options) { @@ -144,14 +142,14 @@ func SetSessionNameInHTTPHeader(sessionNameInHTTPHeader string) Option { } } -// SetStore Set session management storage +// Set session management storage func SetStore(store ManagerStore) Option { return func(o *options) { o.store = store } } -// NewManager Create a session management instance +// Create a session management instance func NewManager(opt ...Option) *Manager { opts := defaultOptions for _, o := range opt { @@ -168,7 +166,7 @@ func NewManager(opt ...Option) *Manager { return &Manager{opts: &opts} } -// Manager A session management instance, including start and destroy operations +// A session management instance, including start and destroy operations type Manager struct { opts *options } @@ -305,8 +303,8 @@ func (m *Manager) Start(ctx context.Context, w http.ResponseWriter, r *http.Requ } if sid != "" { - if exists, verr := m.opts.store.Check(ctx, sid); verr != nil { - return nil, verr + if exists, err := m.opts.store.Check(ctx, sid); err != nil { + return nil, err } else if exists { return m.opts.store.Update(ctx, sid, m.opts.expired) } @@ -322,19 +320,19 @@ func (m *Manager) Start(ctx context.Context, w http.ResponseWriter, r *http.Requ return store, nil } -// Refresh a session and return to session storage +// Refresh and return session storage func (m *Manager) Refresh(ctx context.Context, w http.ResponseWriter, r *http.Request) (Store, error) { ctx = m.getContext(ctx, w, r) - oldsid, err := m.sessionID(r) + oldSID, err := m.sessionID(r) if err != nil { return nil, err - } else if oldsid == "" { - oldsid = m.opts.sessionID(ctx) + } else if oldSID == "" { + oldSID = m.opts.sessionID(ctx) } sid := m.opts.sessionID(ctx) - store, err := m.opts.store.Refresh(ctx, oldsid, sid, m.opts.expired) + store, err := m.opts.store.Refresh(ctx, oldSID, sid, m.opts.expired) if err != nil { return nil, err } @@ -354,8 +352,7 @@ func (m *Manager) Destroy(ctx context.Context, w http.ResponseWriter, r *http.Re return nil } - exists, err := m.opts.store.Check(ctx, sid) - if err != nil { + if exists, err := m.opts.store.Check(ctx, sid); err != nil { return err } else if !exists { return nil diff --git a/session_test.go b/session_test.go index 6a331cf..c7ffc24 100644 --- a/session_test.go +++ b/session_test.go @@ -2,7 +2,7 @@ package session import ( "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -56,7 +56,7 @@ func TestSessionStart(t *testing.T) { So(err, ShouldBeNil) So(res, ShouldNotBeNil) - buf, err := ioutil.ReadAll(res.Body) + buf, err := io.ReadAll(res.Body) So(err, ShouldBeNil) res.Body.Close() So(string(buf), ShouldEqual, "bar:true") @@ -127,7 +127,7 @@ func TestSessionDestroy(t *testing.T) { So(err, ShouldBeNil) So(res, ShouldNotBeNil) - buf, err := ioutil.ReadAll(res.Body) + buf, err := io.ReadAll(res.Body) So(err, ShouldBeNil) res.Body.Close() So(string(buf), ShouldEqual, ":false") @@ -194,7 +194,7 @@ func TestSessionRefresh(t *testing.T) { So(len(res.Cookies()), ShouldBeGreaterThan, 0) So(res.Cookies()[0].Value, ShouldNotEqual, cookie.Value) - buf, err := ioutil.ReadAll(res.Body) + buf, err := io.ReadAll(res.Body) So(err, ShouldBeNil) res.Body.Close() So(string(buf), ShouldEqual, "bar:true") diff --git a/store.go b/store.go index bc5dbed..73df244 100644 --- a/store.go +++ b/store.go @@ -1,10 +1,11 @@ package session import ( - "container/list" "context" "sync" "time" + + "github.com/bytedance/gopkg/collection/skipmap" ) var ( @@ -13,7 +14,7 @@ var ( now = time.Now ) -// ManagerStore Management of session storage, including creation, update, and delete operations +// Management of session storage, including creation, update, and delete operations type ManagerStore interface { // Check the session store exists Check(ctx context.Context, sid string) (bool, error) @@ -29,7 +30,7 @@ type ManagerStore interface { Close() error } -// Store A session id storage operation +// A session id storage operation type Store interface { // Get a session storage context Context() context.Context @@ -47,16 +48,14 @@ type Store interface { Flush() error } -// NewMemoryStore create an instance of a memory store +// Create a new session storage (memory) func NewMemoryStore() ManagerStore { mstore := &memoryStore{ - data: make(map[string]*dataItem), - list: list.New(), - ticker: time.NewTicker(time.Second), + ticker: time.NewTicker(time.Second * 3), + data: skipmap.NewString(), } go mstore.gc() - return mstore } @@ -75,53 +74,37 @@ func newDataItem(sid string, values map[string]interface{}, expired int64) *data } type memoryStore struct { - sync.RWMutex - data map[string]*dataItem - list *list.List ticker *time.Ticker + data *skipmap.StringMap } func (s *memoryStore) gc() { for range s.ticker.C { - s.RLock() - e := s.list.Front() - s.RUnlock() - - for e != nil { - item := e.Value.(*dataItem) - if item.expiredAt.Before(now()) { - s.Lock() - s.list.Remove(e) - delete(s.data, item.sid) - e = e.Next() - s.Unlock() - } else { - break + s.data.Range(func(key string, value interface{}) bool { + if item, ok := value.(*dataItem); ok && item.expiredAt.Before(now()) { + s.data.Delete(key) } - } + return true + }) } } func (s *memoryStore) save(sid string, values map[string]interface{}, expired int64) { - s.Lock() - defer s.Unlock() - - if item, ok := s.data[sid]; ok { - item.values = values + if dt, ok := s.data.Load(sid); ok { + dt.(*dataItem).values = values return } - item := newDataItem(sid, values, expired) - s.data[sid] = item - s.list.PushBack(item) + s.data.Store(sid, newDataItem(sid, values, expired)) } -func (s *memoryStore) Check(_ context.Context, sid string) (bool, error) { - s.RLock() - item, ok := s.data[sid] - s.RUnlock() +func (s *memoryStore) Check(ctx context.Context, sid string) (bool, error) { + dt, ok := s.data.Load(sid) + if !ok { + return false, nil + } - if ok && item.expiredAt.After(now()) { + if item, ok := dt.(*dataItem); ok && item.expiredAt.After(now()) { return true, nil } return false, nil @@ -132,58 +115,36 @@ func (s *memoryStore) Create(ctx context.Context, sid string, expired int64) (St } func (s *memoryStore) Update(ctx context.Context, sid string, expired int64) (Store, error) { - s.Lock() - defer s.Unlock() - - item, ok := s.data[sid] + dt, ok := s.data.Load(sid) if !ok { return newStore(ctx, s, sid, expired, nil), nil } + item := dt.(*dataItem) item.expiredAt = now().Add(time.Duration(expired) * time.Second) - for e := s.list.Front(); e != nil; e = e.Next() { - if e.Value.(*dataItem).sid == sid { - s.list.MoveToBack(e) - break - } - } - + s.data.Store(sid, item) return newStore(ctx, s, sid, expired, item.values), nil } func (s *memoryStore) delete(sid string) { - delete(s.data, sid) - - for e := s.list.Front(); e != nil; e = e.Next() { - if e.Value.(*dataItem).sid == sid { - s.list.Remove(e) - break - } - } + s.data.Delete(sid) } func (s *memoryStore) Delete(_ context.Context, sid string) error { - s.Lock() - defer s.Unlock() - s.delete(sid) return nil } func (s *memoryStore) Refresh(ctx context.Context, oldsid, sid string, expired int64) (Store, error) { - s.Lock() - defer s.Unlock() - - item, ok := s.data[oldsid] + dt, ok := s.data.Load(oldsid) if !ok { return newStore(ctx, s, sid, expired, nil), nil } + item := dt.(*dataItem) newItem := newDataItem(sid, item.values, expired) - s.data[sid] = newItem - s.list.PushBack(newItem) + s.data.Store(sid, newItem) s.delete(oldsid) - return newStore(ctx, s, sid, expired, newItem.values), nil } diff --git a/util.go b/util.go index 9ae199d..e654951 100644 --- a/util.go +++ b/util.go @@ -9,7 +9,7 @@ import ( // create a UUID, reference: https://github.com/google/uuid func newUUID() string { var buf [16]byte - io.ReadFull(rand.Reader, buf[:]) + _, _ = io.ReadFull(rand.Reader, buf[:]) buf[6] = (buf[6] & 0x0f) | 0x40 buf[8] = (buf[8] & 0x3f) | 0x80 From 03fe55fcb8874d8966dc407fd050dadf7a29280c Mon Sep 17 00:00:00 2001 From: LyricTian Date: Mon, 13 Feb 2023 11:39:48 +0800 Subject: [PATCH 8/9] fix: Update GC interval --- store.go | 2 +- store_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/store.go b/store.go index 73df244..da60210 100644 --- a/store.go +++ b/store.go @@ -51,7 +51,7 @@ type Store interface { // Create a new session storage (memory) func NewMemoryStore() ManagerStore { mstore := &memoryStore{ - ticker: time.NewTicker(time.Second * 3), + ticker: time.NewTicker(time.Second), data: skipmap.NewString(), } diff --git a/store_test.go b/store_test.go index f8d49a5..3e20a4e 100644 --- a/store_test.go +++ b/store_test.go @@ -118,7 +118,7 @@ func testStoreWithExpired(mstore ManagerStore) { So(foo, ShouldEqual, "bar") So(ok, ShouldBeTrue) - time.Sleep(time.Second * 2) + time.Sleep(time.Second * 3) exists, err := mstore.Check(context.Background(), sid) So(err, ShouldBeNil) From 02e68300cd211aa13bab8ae73476dbdb9eb44f17 Mon Sep 17 00:00:00 2001 From: LyricTian Date: Mon, 13 Feb 2023 11:46:44 +0800 Subject: [PATCH 9/9] fix: Update go mod --- go.mod | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 22c7c0e..dc71fae 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,12 @@ module github.com/go-session/session/v3 go 1.17 -require github.com/smartystreets/goconvey v1.6.4 +require ( + github.com/bytedance/gopkg v0.0.0-20221122125632-68358b8ecec6 + github.com/smartystreets/goconvey v1.6.4 +) require ( - github.com/bytedance/gopkg v0.0.0-20221122125632-68358b8ecec6 // indirect github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/smartystreets/assertions v1.1.0 // indirect