1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-10 21:45:57 +00:00

SetImmutable for sessions and context's values. https://github.com/iris-contrib/community-board/issues/5

New package "memstore" created, read it to see how I made it.


Former-commit-id: 9edc344b938786b2ef68defec03c44259a2d539c
This commit is contained in:
kataras
2017-06-08 03:39:15 +03:00
parent 5e00c50c37
commit 14e7751d21
14 changed files with 455 additions and 268 deletions

View File

@@ -31,6 +31,7 @@ import (
"github.com/russross/blackfriday"
"github.com/kataras/iris/core/errors"
"github.com/kataras/iris/core/memstore"
"github.com/kataras/iris/sessions"
)
@@ -73,6 +74,64 @@ func (u UnmarshalerFunc) Unmarshal(data []byte, v interface{}) error {
return u(data, v)
}
// RequestParams is a key string - value string storage which context's request params should implement.
// RequestValues is for communication between middleware, RequestParams cannot be changed, are setted at the routing
// time, stores the dynamic named parameters, can be empty if the route is static.
type RequestParams struct {
store memstore.Store
}
// Set shouldn't be used as a local storage, context's values store
// is the local storage, not params.
func (r *RequestParams) Set(key, value string) {
r.store.Set(key, value)
}
// Visit accepts a visitor which will be filled
// by the key-value params.
func (r *RequestParams) Visit(visitor func(key string, value interface{})) {
r.store.Visit(visitor)
}
// Get returns a path parameter's value based on its route's dynamic path key.
func (r RequestParams) Get(key string) string {
return r.store.GetString(key)
}
// GetInt returns the param's value as int, based on its key.
func (r RequestParams) GetInt(key string) (int, error) {
return r.store.GetInt(key)
}
// GetInt64 returns the user's value as int64, based on its key.
func (r RequestParams) GetInt64(key string) (int64, error) {
return r.store.GetInt64(key)
}
// GetDecoded returns the url-query-decoded user's value based on its key.
func (r RequestParams) GetDecoded(key string) string {
return DecodeQuery(DecodeQuery(r.Get(key)))
}
// GetIntUnslashed same as Get but it removes the first slash if found.
// Usage: Get an id from a wildcard path.
//
// Returns -1 with an error if the parameter couldn't be found.
func (r RequestParams) GetIntUnslashed(key string) (int, error) {
v := r.Get(key)
if v != "" {
if len(v) > 1 {
if v[0] == '/' {
v = v[1:]
}
}
return strconv.Atoi(v)
}
return -1, memstore.ErrIntParse.Format(v)
}
// Context is the midle-man server's "object" for the clients.
//
// A New context is being acquired from a sync.Pool on each connection.
@@ -163,9 +222,7 @@ type Context interface {
// Params returns the current url's named parameters key-value storage.
// Named path parameters are being saved here.
// This storage, as the whole Context, is per-request lifetime.
Params() RequestParams
// SetParams sets/or/overrides the request's url named parameters key-value storage.
SetParams(RequestParams)
Params() *RequestParams
// Values returns the current "user" storage.
// Named path parameters and any optional data can be saved here.
@@ -173,7 +230,7 @@ type Context interface {
//
// You can use this function to Set and Get local values
// that can be used to share information between handlers and middleware.
Values() *RequestValues
Values() *memstore.Store
// Translate is the i18n (localization) middleware's function,
// it calls the Get("translate") to return the translated value.
//
@@ -684,8 +741,8 @@ type context struct {
// the original http.Request
request *http.Request
// the local key-value storage
params RequestParams // url named parameters
values RequestValues // generic storage, middleware communication
params RequestParams // url named parameters
values memstore.Store // generic storage, middleware communication
// the underline application framework
framework Application
@@ -720,7 +777,7 @@ func (ctx *context) BeginRequest(w http.ResponseWriter, r *http.Request) {
ctx.handlers = nil // will be filled by router.Serve/HTTP
ctx.session = nil // >> >> by sessions.Session()
ctx.values = ctx.values[0:0] // >> >> by context.Values().Set
ctx.params = ctx.params[0:0]
ctx.params.store = ctx.params.store[0:0]
ctx.request = r
ctx.currentHandlerIndex = 0
ctx.writer = AcquireResponseWriter()
@@ -861,13 +918,8 @@ func (ctx *context) IsStopped() bool {
// Params returns the current url's named parameters key-value storage.
// Named path parameters are being saved here.
// This storage, as the whole context, is per-request lifetime.
func (ctx *context) Params() RequestParams {
return ctx.params
}
// SetParams sets/or/overrides the request's url named parameters key-value storage.
func (ctx *context) SetParams(params RequestParams) {
ctx.params = params
func (ctx *context) Params() *RequestParams {
return &ctx.params
}
// Values returns the current "user" storage.
@@ -876,7 +928,7 @@ func (ctx *context) SetParams(params RequestParams) {
//
// You can use this function to Set and Get local values
// that can be used to share information between handlers and middleware.
func (ctx *context) Values() *RequestValues {
func (ctx *context) Values() *memstore.Store {
return &ctx.values
}

View File

@@ -1,193 +0,0 @@
package context
import (
"strconv"
"github.com/kataras/iris/core/errors"
)
type (
// RequestValue is the entry of the context storage RequestValues - .Values()
RequestValue struct {
key string
value interface{}
}
// RequestValues is just a key-value storage which context's request values should implement.
RequestValues []RequestValue
)
// RequestValuesReadOnly the request values with read-only access.
type RequestValuesReadOnly struct {
RequestValues
}
// Set does nothing.
func (r RequestValuesReadOnly) Set(string, interface{}) {}
// Set sets a value to the key-value context storage, can be familiar as "User Values".
func (r *RequestValues) Set(key string, value interface{}) {
args := *r
n := len(args)
for i := 0; i < n; i++ {
kv := &args[i]
if kv.key == key {
kv.value = value
return
}
}
c := cap(args)
if c > n {
args = args[:n+1]
kv := &args[n]
kv.key = key
kv.value = value
*r = args
return
}
kv := RequestValue{}
kv.key = key
kv.value = value
*r = append(args, kv)
}
// Get returns the user's value based on its key.
func (r *RequestValues) Get(key string) interface{} {
args := *r
n := len(args)
for i := 0; i < n; i++ {
kv := &args[i]
if kv.key == key {
return kv.value
}
}
return nil
}
// Visit accepts a visitor which will be filled
// by the key-value objects, the caller should not try to change the underline values.
func (r *RequestValues) Visit(visitor func(key string, value interface{})) {
args := *r
for i, n := 0, len(args); i < n; i++ {
visitor(args[i].key, args[i].value)
}
}
// GetString returns the user's value as string, based on its key.
func (r *RequestValues) GetString(key string) string {
if v, ok := r.Get(key).(string); ok {
return v
}
return ""
}
var errIntParse = errors.New("unable to find or parse the integer, found: %#v")
// GetInt returns the user's value as int, based on its key.
func (r *RequestValues) GetInt(key string) (int, error) {
v := r.Get(key)
if vint, ok := v.(int); ok {
return vint, nil
} else if vstring, sok := v.(string); sok {
return strconv.Atoi(vstring)
}
return -1, errIntParse.Format(v)
}
// GetInt64 returns the user's value as int64, based on its key.
func (r *RequestValues) GetInt64(key string) (int64, error) {
return strconv.ParseInt(r.GetString(key), 10, 64)
}
// Reset clears all the request values.
func (r *RequestValues) Reset() {
*r = (*r)[0:0]
}
// ReadOnly returns a new request values with read-only access.
func (r *RequestValues) ReadOnly() RequestValuesReadOnly {
args := *r
values := make(RequestValues, len(args))
copy(values, args)
return RequestValuesReadOnly{values}
}
// Len returns the full length of the values.
func (r *RequestValues) Len() int {
args := *r
return len(args)
}
// RequestParam is the entry of RequestParams, request's url named parameters are storaged here.
type RequestParam struct {
Key string
Value string
}
// RequestParams is a key string - value string storage which context's request params should implement.
// RequestValues is for communication between middleware, RequestParams cannot be changed, are setted at the routing
// time, stores the dynamic named parameters, can be empty if the route is static.
type RequestParams []RequestParam
// Get returns the param's value based on its key.
func (r RequestParams) Get(key string) string {
for _, p := range r {
if p.Key == key {
return p.Value
}
}
return ""
}
// Visit accepts a visitor which will be filled
// by the key and value.
// The caller should not try to change the underline values.
func (r RequestParams) Visit(visitor func(key string, value string)) {
for i, n := 0, len(r); i < n; i++ {
visitor(r[i].Key, r[i].Value)
}
}
// GetInt returns the user's value as int, based on its key.
func (r RequestParams) GetInt(key string) (int, error) {
v := r.Get(key)
return strconv.Atoi(v)
}
// GetInt64 returns the user's value as int64, based on its key.
func (r RequestParams) GetInt64(key string) (int64, error) {
return strconv.ParseInt(r.Get(key), 10, 64)
}
// GetDecoded returns the url-query-decoded user's value based on its key.
func (r RequestParams) GetDecoded(key string) string {
return DecodeQuery(DecodeQuery(r.Get(key)))
}
// GetIntUnslashed same as Get but it removes the first slash if found.
// Usage: Get an id from a wildcard path.
//
// Returns -1 with an error if the parameter couldn't be found.
func (r RequestParams) GetIntUnslashed(key string) (int, error) {
v := r.Get(key)
if v != "" {
if len(v) > 1 {
if v[0] == '/' {
v = v[1:]
}
}
return strconv.Atoi(v)
}
return -1, errIntParse.Format(v)
}
// Len returns the full length of the params.
func (r RequestParams) Len() int {
return len(r)
}