From 29bf846bd11cc896e5d24493a7ac466daf115dd9 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Wed, 24 Jul 2019 19:51:42 +0300 Subject: [PATCH] minor version 11.2.2 - register sessions as middleware and Context.HTML/Text like Context.Writef Former-commit-id: 6f5f1c502fb06d739c350c3ecc891f495dc03a6e --- _examples/README.md | 2 +- _examples/README_ZH.md | 2 +- .../custom-context/method-overriding/main.go | 4 +- _examples/routing/route-state/main.go | 6 ++ .../{standalone => middleware}/main.go | 65 ++++++++++++------- context/context.go | 12 ++-- doc.go | 4 +- iris.go | 2 +- sessions/session.go | 5 ++ sessions/sessions.go | 32 ++++++++- 10 files changed, 95 insertions(+), 39 deletions(-) rename _examples/sessions/{standalone => middleware}/main.go (70%) diff --git a/_examples/README.md b/_examples/README.md index c6d2172c..f81d8873 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -308,7 +308,7 @@ iris cache library lives on its own [package](https://github.com/kataras/iris/tr iris session manager lives on its own [package](https://github.com/kataras/iris/tree/master/sessions). - [Overview](sessions/overview/main.go) -- [Standalone](sessions/standalone/main.go) +- [Middleware](sessions/middleware/main.go) - [Secure Cookie](sessions/securecookie/main.go) - [Flash Messages](sessions/flash-messages/main.go) - [Databases](sessions/database) diff --git a/_examples/README_ZH.md b/_examples/README_ZH.md index ad0ac9dd..98e927cf 100644 --- a/_examples/README_ZH.md +++ b/_examples/README_ZH.md @@ -416,7 +416,7 @@ Iris 独立缓存包 [package](https://github.com/kataras/iris/tree/master/cache Iris session 管理独立包 [package](https://github.com/kataras/iris/tree/master/sessions). - [概览](sessions/overview/main.go) -- [独立使用](sessions/standalone/main.go) +- [中间件](sessions/middleware/main.go) - [安全cookie](sessions/securecookie/main.go) - [临时消息](sessions/flash-messages/main.go) - [数据库](sessions/database) diff --git a/_examples/routing/custom-context/method-overriding/main.go b/_examples/routing/custom-context/method-overriding/main.go index 8747be93..15108123 100644 --- a/_examples/routing/custom-context/method-overriding/main.go +++ b/_examples/routing/custom-context/method-overriding/main.go @@ -37,11 +37,11 @@ func (ctx *MyContext) Next() { // Override any context's method you want... // [...] -func (ctx *MyContext) HTML(htmlContents string) (int, error) { +func (ctx *MyContext) HTML(format string, args ...interface{}) (int, error) { ctx.Application().Logger().Infof("Executing .HTML function from MyContext") ctx.ContentType("text/html") - return ctx.WriteString(htmlContents) + return ctx.Writef(format, args...) } func main() { diff --git a/_examples/routing/route-state/main.go b/_examples/routing/route-state/main.go index 59d06763..58058598 100644 --- a/_examples/routing/route-state/main.go +++ b/_examples/routing/route-state/main.go @@ -28,6 +28,12 @@ func main() { }) app.Get("/execute", func(ctx iris.Context) { + if !none.IsOnline() { + ctx.Values().Set("from", "/execute with offline access") + ctx.Exec("NONE", "/invisible/iris") + return + } + // same as navigating to "http://localhost:8080/invisible/iris" when /change has being invoked and route state changed // from "offline" to "online" ctx.Values().Set("from", "/execute") // values and session can be shared when calling Exec from a "foreign" context. diff --git a/_examples/sessions/standalone/main.go b/_examples/sessions/middleware/main.go similarity index 70% rename from _examples/sessions/standalone/main.go rename to _examples/sessions/middleware/main.go index e413b0e9..54010b47 100644 --- a/_examples/sessions/standalone/main.go +++ b/_examples/sessions/middleware/main.go @@ -26,26 +26,33 @@ func main() { // if you want to invalid cookies on different subdomains // of the same host, then enable it. // Defaults to false. - DisableSubdomainPersistence: true, - // AllowReclaim will allow to - // Destroy and Start a session in the same request handler. - // All it does is that it removes the cookie for both `Request` and `ResponseWriter` while `Destroy` - // or add a new cookie to `Request` while `Start`. - // - // Defaults to false. - AllowReclaim: true, + DisableSubdomainPersistence: false, }) + app.Use(sess.Handler()) // session is always non-nil inside handlers now. + app.Get("/", func(ctx iris.Context) { - ctx.Writef("You should navigate to the /set, /get, /delete, /clear,/destroy instead") + session := sessions.Get(ctx) // same as sess.Start(ctx, cookieOptions...) + if session.Len() == 0 { + ctx.HTML(`no session values stored yet. Navigate to: set page`) + return + } + + ctx.HTML("") }) + + //set session values. app.Get("/set", func(ctx iris.Context) { - //set session values. - s := sess.Start(ctx) - s.Set("name", "iris") + session := sessions.Get(ctx) + session.Set("name", "iris") //test if set here. - ctx.Writef("All ok session set to: %s", s.GetString("name")) + ctx.Writef("All ok session set to: %s", session.GetString("name")) // Set will set the value as-it-is, // if it's a slice or map @@ -56,22 +63,32 @@ func main() { // Read more about muttable and immutable go types: https://stackoverflow.com/a/8021081 }) + app.Get("/set/{key}/{value}", func(ctx iris.Context) { + key, value := ctx.Params().Get("key"), ctx.Params().Get("value") + + session := sessions.Get(ctx) + session.Set(key, value) + + // test if set here + ctx.Writef("All ok session value of the '%s' is: %s", key, session.GetString(key)) + }) + app.Get("/get", func(ctx iris.Context) { // get a specific value, as string, // if not found then it returns just an empty string. - name := sess.Start(ctx).GetString("name") + name := sessions.Get(ctx).GetString("name") ctx.Writef("The name on the /set was: %s", name) }) app.Get("/delete", func(ctx iris.Context) { // delete a specific key - sess.Start(ctx).Delete("name") + sessions.Get(ctx).Delete("name") }) app.Get("/clear", func(ctx iris.Context) { // removes all entries. - sess.Start(ctx).Clear() + sessions.Get(ctx).Clear() }) app.Get("/update", func(ctx iris.Context) { @@ -81,13 +98,15 @@ func main() { app.Get("/destroy", func(ctx iris.Context) { //destroy, removes the entire session data and cookie - sess.Destroy(ctx) + // sess.Destroy(ctx) + // or + sessions.Get(ctx).Destroy() }) // Note about Destroy: // // You can destroy a session outside of a handler too, using the: - // mySessions.DestroyByID - // mySessions.DestroyAll + // sess.DestroyByID + // sess.DestroyAll // remember: slices and maps are muttable by-design // The `SetImmutable` makes sure that they will be stored and received @@ -97,9 +116,9 @@ func main() { // Read more about muttable and immutable go types: https://stackoverflow.com/a/8021081 app.Get("/set_immutable", func(ctx iris.Context) { business := []businessModel{{Name: "Edward"}, {Name: "value 2"}} - s := sess.Start(ctx) - s.SetImmutable("businessEdit", business) - businessGet := s.Get("businessEdit").([]businessModel) + session := sessions.Get(ctx) + session.SetImmutable("businessEdit", business) + businessGet := session.Get("businessEdit").([]businessModel) // try to change it, if we used `Set` instead of `SetImmutable` this // change will affect the underline array of the session's value "businessEdit", but now it will not. @@ -108,7 +127,7 @@ func main() { }) app.Get("/get_immutable", func(ctx iris.Context) { - valSlice := sess.Start(ctx).Get("businessEdit") + valSlice := sessions.Get(ctx).Get("businessEdit") if valSlice == nil { ctx.HTML("please navigate to the /set_immutable first") return diff --git a/context/context.go b/context/context.go index b05b16a6..0d8bd445 100644 --- a/context/context.go +++ b/context/context.go @@ -768,9 +768,9 @@ type Context interface { // Binary writes out the raw bytes as binary data. Binary(data []byte) (int, error) // Text writes out a string as plain text. - Text(text string) (int, error) + Text(format string, args ...interface{}) (int, error) // HTML writes out a string as text/html. - HTML(htmlContents string) (int, error) + HTML(format string, args ...interface{}) (int, error) // JSON marshals the given interface object and writes the JSON response. JSON(v interface{}, options ...JSON) (int, error) // JSONP marshals the given interface object and writes the JSON response. @@ -2876,15 +2876,15 @@ func (ctx *context) Binary(data []byte) (int, error) { } // Text writes out a string as plain text. -func (ctx *context) Text(text string) (int, error) { +func (ctx *context) Text(format string, args ...interface{}) (int, error) { ctx.ContentType(ContentTextHeaderValue) - return ctx.writer.WriteString(text) + return ctx.Writef(format, args...) } // HTML writes out a string as text/html. -func (ctx *context) HTML(htmlContents string) (int, error) { +func (ctx *context) HTML(format string, args ...interface{}) (int, error) { ctx.ContentType(ContentHTMLHeaderValue) - return ctx.writer.WriteString(htmlContents) + return ctx.Writef(format, args...) } // JSON contains the options for the JSON (Context's) Renderer. diff --git a/doc.go b/doc.go index 594b0a86..fca949ed 100644 --- a/doc.go +++ b/doc.go @@ -38,13 +38,13 @@ Source code and other details for the project are available at GitHub: Current Version -11.2.1 +11.2.2 Installation The only requirement is the Go Programming Language, at least version 1.12. - $ go get github.com/kataras/iris@v11.2.1 + $ go get github.com/kataras/iris@v11.2.2 Wiki: diff --git a/iris.go b/iris.go index 808c9f60..a5aae229 100644 --- a/iris.go +++ b/iris.go @@ -37,7 +37,7 @@ import ( var ( // Version is the current version number of the Iris Web Framework. - Version = "11.2.1" + Version = "11.2.2" ) // HTTP status codes as registered with IANA. diff --git a/sessions/session.go b/sessions/session.go index 80f9383d..61a269c2 100644 --- a/sessions/session.go +++ b/sessions/session.go @@ -411,6 +411,11 @@ func (s *Session) Visit(cb func(k string, v interface{})) { s.provider.db.Visit(s.sid, cb) } +// Len returns the total number of stored values in this session. +func (s *Session) Len() int { + return s.provider.db.Len(s.sid) +} + func (s *Session) set(key string, value interface{}, immutable bool) { s.provider.db.Set(s.sid, s.Lifetime, key, value, immutable) diff --git a/sessions/sessions.go b/sessions/sessions.go index b103cd15..79486824 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -77,7 +77,7 @@ func (s *Sessions) updateCookie(ctx context.Context, sid string, expires time.Du func (s *Sessions) Start(ctx context.Context, cookieOptions ...context.CookieOption) *Session { cookieValue := s.decodeCookieValue(GetCookie(ctx, s.config.Cookie)) - if cookieValue == "" { // cookie doesn't exists, let's generate a session and add set a cookie + if cookieValue == "" { // cookie doesn't exist, let's generate a session and set a cookie. sid := s.config.SessionIDGenerator(ctx) sess := s.provider.Init(sid, s.config.Expires) @@ -88,9 +88,35 @@ func (s *Sessions) Start(ctx context.Context, cookieOptions ...context.CookieOpt return sess } - sess := s.provider.Read(cookieValue, s.config.Expires) + return s.provider.Read(cookieValue, s.config.Expires) +} - return sess +const contextSessionKey = "_iris_session" + +// Handler returns a sessions middleware to register on application routes. +func (s *Sessions) Handler(cookieOptions ...context.CookieOption) context.Handler { + return func(ctx context.Context) { + session := s.Start(ctx, cookieOptions...) + ctx.Values().Set(contextSessionKey, session) + ctx.Next() + } +} + +// Get returns a *Session from the same request life cycle, +// can be used inside a chain of handlers of a route. +// +// The `Sessions.Start` should be called previously, +// e.g. register the `Sessions.Handler` as middleware. +// Then call `Get` package-level function as many times as you want. +// The `Sessions.Start` can be called more than one time in the same request life cycle as well. +func Get(ctx context.Context) *Session { + if v := ctx.Values().Get(contextSessionKey); v != nil { + if sess, ok := v.(*Session); ok { + return sess + } + } + + return nil } // StartWithPath same as `Start` but it explicitly accepts the cookie path option.