mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
improvements on cookie options
Former-commit-id: f1d5cfc88a33077a9359eaa25b6a20265f5632b5
This commit is contained in:
parent
50b18c7515
commit
221f026491
|
@ -372,6 +372,8 @@ Other Improvements:
|
||||||
![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0)
|
![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0)
|
||||||
|
|
||||||
- Enhanced cookie security and management through new `Context.AddCookieOptions` method and new cookie options (look on New Package-level functions section below), [securecookie](https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie) example has been updated.
|
- Enhanced cookie security and management through new `Context.AddCookieOptions` method and new cookie options (look on New Package-level functions section below), [securecookie](https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie) example has been updated.
|
||||||
|
- `Context.RemoveCookie` removes also the Request's cookies of the same request lifecycle when `iris.CookieAllowReclaim` is set to cookie options, [example](https://github.com/kataras/iris/tree/master/_examples/cookies/options).
|
||||||
|
|
||||||
- `iris.TLS` can now accept certificates as raw contents too.
|
- `iris.TLS` can now accept certificates as raw contents too.
|
||||||
- `iris.TLS` registers a secondary http server which redirects "http://" to their "https://" equivalent requests, unless the new `iris.TLSNoRedirect` host Configurator is provided on `iris.TLS` (or `iris.AutoTLS`), e.g. `app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key", iris.TLSNoRedirect))`.
|
- `iris.TLS` registers a secondary http server which redirects "http://" to their "https://" equivalent requests, unless the new `iris.TLSNoRedirect` host Configurator is provided on `iris.TLS` (or `iris.AutoTLS`), e.g. `app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key", iris.TLSNoRedirect))`.
|
||||||
|
|
||||||
|
@ -405,6 +407,7 @@ New Package-level Variables:
|
||||||
|
|
||||||
New Context Methods:
|
New Context Methods:
|
||||||
|
|
||||||
|
- `Context.GetDomain() string` returns the domain.
|
||||||
- `Context.AddCookieOptions(...CookieOption)` adds options for `SetCookie`, `SetCookieKV, UpsertCookie` and `RemoveCookie` methods for the current request.
|
- `Context.AddCookieOptions(...CookieOption)` adds options for `SetCookie`, `SetCookieKV, UpsertCookie` and `RemoveCookie` methods for the current request.
|
||||||
- `Context.ClearCookieOptions()` clears any cookie options registered through `AddCookieOptions`.
|
- `Context.ClearCookieOptions()` clears any cookie options registered through `AddCookieOptions`.
|
||||||
- `Context.SetVersion(constraint string)` force-sets an [API Version](https://github.com/kataras/iris/wiki/API-versioning)
|
- `Context.SetVersion(constraint string)` force-sets an [API Version](https://github.com/kataras/iris/wiki/API-versioning)
|
||||||
|
@ -423,7 +426,6 @@ New Context Methods:
|
||||||
- `Context.ReadProtobuf(ptr)` binds request body to a proto message
|
- `Context.ReadProtobuf(ptr)` binds request body to a proto message
|
||||||
- `Context.ReadMsgPack(ptr)` binds request body of a msgpack format to a struct
|
- `Context.ReadMsgPack(ptr)` binds request body of a msgpack format to a struct
|
||||||
- `Context.ReadBody(ptr)` binds the request body to the "ptr" depending on the request's Method and Content-Type
|
- `Context.ReadBody(ptr)` binds the request body to the "ptr" depending on the request's Method and Content-Type
|
||||||
- `Context.SetSameSite(http.SameSite)` to set cookie "SameSite" option (respectful by sessions too)
|
|
||||||
- `Context.Defer(Handler)` works like `Party.Done` but for the request life-cycle instead
|
- `Context.Defer(Handler)` works like `Party.Done` but for the request life-cycle instead
|
||||||
- `Context.ReflectValue() []reflect.Value` stores and returns the `[]reflect.ValueOf(ctx)`
|
- `Context.ReflectValue() []reflect.Value` stores and returns the `[]reflect.ValueOf(ctx)`
|
||||||
- `Context.Controller() reflect.Value` returns the current MVC Controller value.
|
- `Context.Controller() reflect.Value` returns the current MVC Controller value.
|
||||||
|
|
|
@ -137,6 +137,7 @@
|
||||||
* [Manage Permissions](permissions/main.go)
|
* [Manage Permissions](permissions/main.go)
|
||||||
* Cookies
|
* Cookies
|
||||||
* [Basic](cookies/basic/main.go)
|
* [Basic](cookies/basic/main.go)
|
||||||
|
* [Options](cookies/options/main.go)
|
||||||
* [Encode/Decode (with `securecookie`)](cookies/securecookie/main.go)
|
* [Encode/Decode (with `securecookie`)](cookies/securecookie/main.go)
|
||||||
* Sessions
|
* Sessions
|
||||||
* [Overview: Config](sessions/overview/main.go)
|
* [Overview: Config](sessions/overview/main.go)
|
||||||
|
|
76
_examples/cookies/options/main.go
Normal file
76
_examples/cookies/options/main.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris/v12"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := newApp()
|
||||||
|
|
||||||
|
// http://localhost:8080/set/name1/value1
|
||||||
|
// http://localhost:8080/get/name1
|
||||||
|
// http://localhost:8080/remove/name1
|
||||||
|
app.Listen(":8080", iris.WithLogLevel("debug"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApp() *iris.Application {
|
||||||
|
app := iris.New()
|
||||||
|
app.Use(withCookieOptions)
|
||||||
|
|
||||||
|
app.Get("/set/{name}/{value}", setCookie)
|
||||||
|
app.Get("/get/{name}", getCookie)
|
||||||
|
app.Get("/remove/{name}", removeCookie)
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
func withCookieOptions(ctx iris.Context) {
|
||||||
|
// Register cookie options for request-lifecycle.
|
||||||
|
// To register per cookie, just add the CookieOption
|
||||||
|
// on the last variadic input argument of
|
||||||
|
// SetCookie, SetCookieKV, UpsertCookie, RemoveCookie
|
||||||
|
// and GetCookie Context methods.
|
||||||
|
//
|
||||||
|
// * CookieAllowReclaim
|
||||||
|
// * CookieAllowSubdomains
|
||||||
|
// * CookieSecure
|
||||||
|
// * CookieHTTPOnly
|
||||||
|
// * CookieSameSite
|
||||||
|
// * CookiePath
|
||||||
|
// * CookieCleanPath
|
||||||
|
// * CookieExpires
|
||||||
|
// * CookieEncoding
|
||||||
|
ctx.AddCookieOptions(iris.CookieAllowReclaim())
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCookie(ctx iris.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
value := ctx.Params().Get("value")
|
||||||
|
|
||||||
|
ctx.SetCookieKV(name, value)
|
||||||
|
|
||||||
|
// By-default net/http does not remove or set the Cookie on the Request object.
|
||||||
|
//
|
||||||
|
// With the `CookieAllowReclaim` option, whenever you set or remove a cookie
|
||||||
|
// it will be also reflected in the Request object immediately (of the same request lifecycle)
|
||||||
|
// therefore, any of the next handlers in the chain are not holding the old value.
|
||||||
|
valueIsAvailableInRequestObject := ctx.GetCookie(name)
|
||||||
|
ctx.Writef("cookie %s=%s", name, valueIsAvailableInRequestObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCookie(ctx iris.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
|
||||||
|
value := ctx.GetCookie(name)
|
||||||
|
ctx.WriteString(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeCookie(ctx iris.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
|
||||||
|
ctx.RemoveCookie(name)
|
||||||
|
|
||||||
|
removedFromRequestObject := ctx.GetCookie(name) // CookieAllowReclaim feature.
|
||||||
|
ctx.Writef("cookie %s removed, value should be empty=%s", name, removedFromRequestObject)
|
||||||
|
}
|
32
_examples/cookies/options/main_test.go
Normal file
32
_examples/cookies/options/main_test.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/v12/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCookieOptions(t *testing.T) {
|
||||||
|
app := newApp()
|
||||||
|
e := httptest.New(t, app, httptest.URL("http://example.com"))
|
||||||
|
|
||||||
|
cookieName, cookieValue := "my_cookie_name", "my_cookie_value"
|
||||||
|
|
||||||
|
// Test set a Cookie.
|
||||||
|
t1 := e.GET(fmt.Sprintf("/set/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK)
|
||||||
|
t1.Cookie(cookieName).Value().Equal(cookieValue)
|
||||||
|
t1.Body().Contains(fmt.Sprintf("%s=%s", cookieName, cookieValue))
|
||||||
|
|
||||||
|
// Test retrieve a Cookie.
|
||||||
|
t2 := e.GET(fmt.Sprintf("/get/%s", cookieName)).Expect().Status(httptest.StatusOK)
|
||||||
|
t2.Body().Equal(cookieValue)
|
||||||
|
|
||||||
|
// Test remove a Cookie.
|
||||||
|
t3 := e.GET(fmt.Sprintf("/remove/%s", cookieName)).Expect().Status(httptest.StatusOK)
|
||||||
|
t3.Body().Contains(fmt.Sprintf("cookie %s removed, value should be empty=%s", cookieName, ""))
|
||||||
|
|
||||||
|
t4 := e.GET(fmt.Sprintf("/get/%s", cookieName)).Expect().Status(httptest.StatusOK)
|
||||||
|
t4.Cookies().Empty()
|
||||||
|
t4.Body().Empty()
|
||||||
|
}
|
|
@ -378,6 +378,8 @@ type Context interface {
|
||||||
RemoteAddr() string
|
RemoteAddr() string
|
||||||
// GetHeader returns the request header's value based on its name.
|
// GetHeader returns the request header's value based on its name.
|
||||||
GetHeader(name string) string
|
GetHeader(name string) string
|
||||||
|
// GetDomain resolves and returns the server's domain.
|
||||||
|
GetDomain() string
|
||||||
// IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
|
// IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
|
||||||
//
|
//
|
||||||
// There is no a 100% way of knowing that a request was made via Ajax.
|
// There is no a 100% way of knowing that a request was made via Ajax.
|
||||||
|
@ -992,12 +994,15 @@ type Context interface {
|
||||||
// See `ClearCookieOptions` too.
|
// See `ClearCookieOptions` too.
|
||||||
//
|
//
|
||||||
// Available builtin Cookie options are:
|
// Available builtin Cookie options are:
|
||||||
// * CookieSameSite
|
// * CookieAllowReclaim
|
||||||
// * CookiePath
|
// * CookieAllowSubdomains
|
||||||
// * CookieCleanPath
|
// * CookieSecure
|
||||||
// * CookieExpires
|
// * CookieHTTPOnly
|
||||||
// * CookieHTTPOnly
|
// * CookieSameSite
|
||||||
// * CookieEncoding
|
// * CookiePath
|
||||||
|
// * CookieCleanPath
|
||||||
|
// * CookieExpires
|
||||||
|
// * CookieEncoding
|
||||||
//
|
//
|
||||||
// Example at: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
// Example at: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
AddCookieOptions(options ...CookieOption)
|
AddCookieOptions(options ...CookieOption)
|
||||||
|
@ -1878,6 +1883,20 @@ func (ctx *context) GetHeader(name string) string {
|
||||||
return ctx.request.Header.Get(name)
|
return ctx.request.Header.Get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDomain resolves and returns the server's domain.
|
||||||
|
func (ctx *context) GetDomain() string {
|
||||||
|
host := ctx.Host()
|
||||||
|
if portIdx := strings.IndexByte(host, ':'); portIdx > 0 {
|
||||||
|
host = host[0:portIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
if domain, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil {
|
||||||
|
host = domain
|
||||||
|
}
|
||||||
|
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
// IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
|
// IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
|
||||||
//
|
//
|
||||||
// There is no a 100% way of knowing that a request was made via Ajax.
|
// There is no a 100% way of knowing that a request was made via Ajax.
|
||||||
|
@ -4755,18 +4774,16 @@ const (
|
||||||
|
|
||||||
// CookieOption is the type of function that is accepted on
|
// CookieOption is the type of function that is accepted on
|
||||||
// context's methods like `SetCookieKV`, `RemoveCookie` and `SetCookie`
|
// context's methods like `SetCookieKV`, `RemoveCookie` and `SetCookie`
|
||||||
// as their (last) variadic input argument to amend the end cookie's form.
|
// as their (last) variadic input argument to amend the to-be-sent cookie.
|
||||||
//
|
//
|
||||||
// Any custom or builtin `CookieOption` is valid,
|
|
||||||
// see `CookiePath`, `CookieCleanPath`, `CookieExpires` and `CookieHTTPOnly` for more.
|
|
||||||
// The "op" is the operation code, 0 is GET, 1 is SET and 2 is REMOVE.
|
// The "op" is the operation code, 0 is GET, 1 is SET and 2 is REMOVE.
|
||||||
type CookieOption func(c *http.Cookie, op uint8)
|
type CookieOption func(ctx Context, c *http.Cookie, op uint8)
|
||||||
|
|
||||||
// findCookieAgainst reports whether the "cookie.Name" is in the list of "cookieNames".
|
// CookieIncluded reports whether the "cookie.Name" is in the list of "cookieNames".
|
||||||
// Notes:
|
// Notes:
|
||||||
// If "cookieNames" slice is empty then it returns true,
|
// If "cookieNames" slice is empty then it returns true,
|
||||||
// If "cookie.Name" is empty then it returns false.
|
// If "cookie.Name" is empty then it returns false.
|
||||||
func findCookieAgainst(cookie *http.Cookie, cookieNames []string) bool {
|
func CookieIncluded(cookie *http.Cookie, cookieNames []string) bool {
|
||||||
if cookie.Name == "" {
|
if cookie.Name == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -4784,25 +4801,53 @@ func findCookieAgainst(cookie *http.Cookie, cookieNames []string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
|
||||||
|
|
||||||
|
func sanitizeCookieName(n string) string {
|
||||||
|
return cookieNameSanitizer.Replace(n)
|
||||||
|
}
|
||||||
|
|
||||||
// CookieAllowReclaim accepts the Context itself.
|
// CookieAllowReclaim accepts the Context itself.
|
||||||
// If set it will add the cookie to (on `CookieSet`, `CookieSetKV`, `CookieUpsert`)
|
// If set it will add the cookie to (on `CookieSet`, `CookieSetKV`, `CookieUpsert`)
|
||||||
// or remove the cookie from (on `CookieRemove`) the Request object too.
|
// or remove the cookie from (on `CookieRemove`) the Request object too.
|
||||||
func CookieAllowReclaim(ctx Context, cookieNames ...string) CookieOption {
|
func CookieAllowReclaim(cookieNames ...string) CookieOption {
|
||||||
return func(c *http.Cookie, op uint8) {
|
return func(ctx Context, c *http.Cookie, op uint8) {
|
||||||
if op == OpCookieGet {
|
if op == OpCookieGet {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !findCookieAgainst(c, cookieNames) {
|
if !CookieIncluded(c, cookieNames) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case OpCookieSet:
|
case OpCookieSet:
|
||||||
|
// perform upsert on request cookies or is it too much and not worth the cost?
|
||||||
ctx.Request().AddCookie(c)
|
ctx.Request().AddCookie(c)
|
||||||
case OpCookieDel:
|
case OpCookieDel:
|
||||||
// TODO: delete only this c.Name.
|
header := ctx.Request().Header
|
||||||
ctx.Request().Header.Set("Cookie", "")
|
|
||||||
|
if cookiesLine := header.Get("Cookie"); cookiesLine != "" {
|
||||||
|
if cookies := strings.Split(cookiesLine, "; "); len(cookies) > 1 {
|
||||||
|
// more than one cookie here.
|
||||||
|
// select that one and remove it.
|
||||||
|
name := sanitizeCookieName(c.Name)
|
||||||
|
|
||||||
|
for _, nameValue := range cookies {
|
||||||
|
if strings.HasPrefix(nameValue, name) {
|
||||||
|
cookiesLine = strings.Replace(cookiesLine, "; "+nameValue, "", 1)
|
||||||
|
// current cookiesLine: myapp_session_id=5ccf4e89-8d0e-4ed6-9f4c-6746d7c5e2ee; key1=value1
|
||||||
|
// found nameValue: key1=value1
|
||||||
|
// new cookiesLine: myapp_session_id=5ccf4e89-8d0e-4ed6-9f4c-6746d7c5e2ee
|
||||||
|
header.Set("Cookie", cookiesLine)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Del("Cookie")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4812,28 +4857,17 @@ func CookieAllowReclaim(ctx Context, cookieNames ...string) CookieOption {
|
||||||
// in order to allow subdomains to have access to the cookies.
|
// in order to allow subdomains to have access to the cookies.
|
||||||
// It sets the cookie's Domain field (if was empty) and
|
// It sets the cookie's Domain field (if was empty) and
|
||||||
// it also sets the cookie's SameSite to lax mode too.
|
// it also sets the cookie's SameSite to lax mode too.
|
||||||
func CookieAllowSubdomains(ctx Context, cookieNames ...string) CookieOption {
|
func CookieAllowSubdomains(cookieNames ...string) CookieOption {
|
||||||
host := ctx.Host()
|
return func(ctx Context, c *http.Cookie, _ uint8) {
|
||||||
if portIdx := strings.IndexByte(host, ':'); portIdx > 0 {
|
|
||||||
host = host[0:portIdx]
|
|
||||||
}
|
|
||||||
|
|
||||||
cookieDomain := "." + host
|
|
||||||
|
|
||||||
if domain, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil {
|
|
||||||
cookieDomain = "." + domain
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(c *http.Cookie, _ uint8) {
|
|
||||||
if c.Domain != "" {
|
if c.Domain != "" {
|
||||||
return // already set.
|
return // already set.
|
||||||
}
|
}
|
||||||
|
|
||||||
if !findCookieAgainst(c, cookieNames) {
|
if !CookieIncluded(c, cookieNames) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Domain = cookieDomain
|
c.Domain = ctx.GetDomain()
|
||||||
c.SameSite = http.SameSiteLaxMode // allow subdomain sharing.
|
c.SameSite = http.SameSiteLaxMode // allow subdomain sharing.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4846,7 +4880,7 @@ func CookieAllowSubdomains(ctx Context, cookieNames ...string) CookieOption {
|
||||||
//
|
//
|
||||||
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
|
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
|
||||||
func CookieSameSite(sameSite http.SameSite) CookieOption {
|
func CookieSameSite(sameSite http.SameSite) CookieOption {
|
||||||
return func(c *http.Cookie, op uint8) {
|
return func(_ Context, c *http.Cookie, op uint8) {
|
||||||
if op == OpCookieSet {
|
if op == OpCookieSet {
|
||||||
c.SameSite = sameSite
|
c.SameSite = sameSite
|
||||||
}
|
}
|
||||||
|
@ -4855,12 +4889,10 @@ func CookieSameSite(sameSite http.SameSite) CookieOption {
|
||||||
|
|
||||||
// CookieSecure sets the cookie's Secure option if the current request's
|
// CookieSecure sets the cookie's Secure option if the current request's
|
||||||
// connection is using TLS. See `CookieHTTPOnly` too.
|
// connection is using TLS. See `CookieHTTPOnly` too.
|
||||||
func CookieSecure(ctx Context) CookieOption {
|
func CookieSecure(ctx Context, c *http.Cookie, op uint8) {
|
||||||
return func(c *http.Cookie, op uint8) {
|
if op == OpCookieSet {
|
||||||
if op == OpCookieSet {
|
if ctx.Request().TLS != nil {
|
||||||
if ctx.Request().TLS != nil {
|
c.Secure = true
|
||||||
c.Secure = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4870,7 +4902,7 @@ func CookieSecure(ctx Context) CookieOption {
|
||||||
// HttpOnly field defaults to true for `RemoveCookie` and `SetCookieKV`.
|
// HttpOnly field defaults to true for `RemoveCookie` and `SetCookieKV`.
|
||||||
// See `CookieSecure` too.
|
// See `CookieSecure` too.
|
||||||
func CookieHTTPOnly(httpOnly bool) CookieOption {
|
func CookieHTTPOnly(httpOnly bool) CookieOption {
|
||||||
return func(c *http.Cookie, op uint8) {
|
return func(_ Context, c *http.Cookie, op uint8) {
|
||||||
if op == OpCookieSet {
|
if op == OpCookieSet {
|
||||||
c.HttpOnly = httpOnly
|
c.HttpOnly = httpOnly
|
||||||
}
|
}
|
||||||
|
@ -4880,7 +4912,7 @@ func CookieHTTPOnly(httpOnly bool) CookieOption {
|
||||||
// CookiePath is a `CookieOption`.
|
// CookiePath is a `CookieOption`.
|
||||||
// Use it to change the cookie's Path field.
|
// Use it to change the cookie's Path field.
|
||||||
func CookiePath(path string) CookieOption {
|
func CookiePath(path string) CookieOption {
|
||||||
return func(c *http.Cookie, op uint8) {
|
return func(_ Context, c *http.Cookie, op uint8) {
|
||||||
if op > OpCookieGet { // on set and remove.
|
if op > OpCookieGet { // on set and remove.
|
||||||
c.Path = path
|
c.Path = path
|
||||||
}
|
}
|
||||||
|
@ -4889,7 +4921,7 @@ func CookiePath(path string) CookieOption {
|
||||||
|
|
||||||
// CookieCleanPath is a `CookieOption`.
|
// CookieCleanPath is a `CookieOption`.
|
||||||
// Use it to clear the cookie's Path field, exactly the same as `CookiePath("")`.
|
// Use it to clear the cookie's Path field, exactly the same as `CookiePath("")`.
|
||||||
func CookieCleanPath(c *http.Cookie, op uint8) {
|
func CookieCleanPath(_ Context, c *http.Cookie, op uint8) {
|
||||||
if op > OpCookieGet {
|
if op > OpCookieGet {
|
||||||
c.Path = ""
|
c.Path = ""
|
||||||
}
|
}
|
||||||
|
@ -4898,7 +4930,7 @@ func CookieCleanPath(c *http.Cookie, op uint8) {
|
||||||
// CookieExpires is a `CookieOption`.
|
// CookieExpires is a `CookieOption`.
|
||||||
// Use it to change the cookie's Expires and MaxAge fields by passing the lifetime of the cookie.
|
// Use it to change the cookie's Expires and MaxAge fields by passing the lifetime of the cookie.
|
||||||
func CookieExpires(durFromNow time.Duration) CookieOption {
|
func CookieExpires(durFromNow time.Duration) CookieOption {
|
||||||
return func(c *http.Cookie, op uint8) {
|
return func(_ Context, c *http.Cookie, op uint8) {
|
||||||
if op == OpCookieSet {
|
if op == OpCookieSet {
|
||||||
c.Expires = time.Now().Add(durFromNow)
|
c.Expires = time.Now().Add(durFromNow)
|
||||||
c.MaxAge = int(durFromNow.Seconds())
|
c.MaxAge = int(durFromNow.Seconds())
|
||||||
|
@ -4945,12 +4977,12 @@ type SecureCookie interface {
|
||||||
//
|
//
|
||||||
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
func CookieEncoding(encoding SecureCookie, cookieNames ...string) CookieOption {
|
func CookieEncoding(encoding SecureCookie, cookieNames ...string) CookieOption {
|
||||||
return func(c *http.Cookie, op uint8) {
|
return func(_ Context, c *http.Cookie, op uint8) {
|
||||||
if op == OpCookieDel {
|
if op == OpCookieDel {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !findCookieAgainst(c, cookieNames) {
|
if !CookieIncluded(c, cookieNames) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5010,7 +5042,7 @@ func (ctx *context) applyCookieOptions(c *http.Cookie, op uint8, override []Cook
|
||||||
if v := ctx.Values().Get(cookieOptionsContextKey); v != nil {
|
if v := ctx.Values().Get(cookieOptionsContextKey); v != nil {
|
||||||
if options, ok := v.([]CookieOption); ok {
|
if options, ok := v.([]CookieOption); ok {
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
opt(c, op)
|
opt(ctx, c, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5018,7 +5050,7 @@ func (ctx *context) applyCookieOptions(c *http.Cookie, op uint8, override []Cook
|
||||||
// The function's ones should be called last, so they can override
|
// The function's ones should be called last, so they can override
|
||||||
// the stored ones (i.e by a prior middleware).
|
// the stored ones (i.e by a prior middleware).
|
||||||
for _, opt := range override {
|
for _, opt := range override {
|
||||||
opt(c, op)
|
opt(ctx, c, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,20 +104,21 @@ const sessionContextKey = "iris.session"
|
||||||
func (s *Sessions) Handler(cookieOptions ...context.CookieOption) context.Handler {
|
func (s *Sessions) Handler(cookieOptions ...context.CookieOption) context.Handler {
|
||||||
s.handlerCookieOpts = cookieOptions
|
s.handlerCookieOpts = cookieOptions
|
||||||
|
|
||||||
|
var requestOptions []context.CookieOption
|
||||||
|
if s.config.AllowReclaim {
|
||||||
|
requestOptions = append(requestOptions, context.CookieAllowReclaim(s.config.Cookie))
|
||||||
|
}
|
||||||
|
if !s.config.DisableSubdomainPersistence {
|
||||||
|
requestOptions = append(requestOptions, context.CookieAllowSubdomains(s.config.Cookie))
|
||||||
|
}
|
||||||
|
if s.config.CookieSecureTLS {
|
||||||
|
requestOptions = append(requestOptions, context.CookieSecure)
|
||||||
|
}
|
||||||
|
if s.config.Encoding != nil {
|
||||||
|
requestOptions = append(requestOptions, context.CookieEncoding(s.config.Encoding, s.config.Cookie))
|
||||||
|
}
|
||||||
|
|
||||||
return func(ctx context.Context) {
|
return func(ctx context.Context) {
|
||||||
var requestOptions []context.CookieOption
|
|
||||||
if s.config.AllowReclaim {
|
|
||||||
requestOptions = append(requestOptions, context.CookieAllowReclaim(ctx, s.config.Cookie))
|
|
||||||
}
|
|
||||||
if !s.config.DisableSubdomainPersistence {
|
|
||||||
requestOptions = append(requestOptions, context.CookieAllowSubdomains(ctx, s.config.Cookie))
|
|
||||||
}
|
|
||||||
if s.config.CookieSecureTLS {
|
|
||||||
requestOptions = append(requestOptions, context.CookieSecure(ctx))
|
|
||||||
}
|
|
||||||
if s.config.Encoding != nil {
|
|
||||||
requestOptions = append(requestOptions, context.CookieEncoding(s.config.Encoding, s.config.Cookie))
|
|
||||||
}
|
|
||||||
ctx.AddCookieOptions(requestOptions...) // request life-cycle options.
|
ctx.AddCookieOptions(requestOptions...) // request life-cycle options.
|
||||||
|
|
||||||
session := s.Start(ctx, cookieOptions...) // this cookie's end-developer's custom options.
|
session := s.Start(ctx, cookieOptions...) // this cookie's end-developer's custom options.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user