mirror of
https://github.com/kataras/iris.git
synced 2025-02-09 02:34:55 +01:00
Cookies: Ability to set custom cookie encoders to encode the cookie's value before sent by ctx.SetCookie
and ctx.SetCookieKV
and cookie decoders to decode the cookie's value when retrieving from ctx.GetCookie
. That was the second and final part relative to a community's question at: https://github.com/kataras/iris/issues/1018
Former-commit-id: 53b6810076c8db8646df335d57a30c78b23cd9b8
This commit is contained in:
parent
fcff62d5b4
commit
b4856d542d
|
@ -398,6 +398,7 @@ iris cache library lives on its own [package](https://github.com/kataras/iris/tr
|
||||||
### Cookies
|
### Cookies
|
||||||
|
|
||||||
- [Basic](cookies/basic/main.go)
|
- [Basic](cookies/basic/main.go)
|
||||||
|
- [Encode/Decode (securecookie)](cookies/securecookie/main.go)
|
||||||
|
|
||||||
### Sessions
|
### Sessions
|
||||||
|
|
||||||
|
|
|
@ -397,6 +397,7 @@ Iris 独立缓存包 [package](https://github.com/kataras/iris/tree/master/cache
|
||||||
### Cookies
|
### Cookies
|
||||||
|
|
||||||
- [Basic](cookies/basic/main.go)
|
- [Basic](cookies/basic/main.go)
|
||||||
|
- [Encode/Decode (securecookie)](cookies/securecookie/main.go)
|
||||||
|
|
||||||
### Sessions
|
### Sessions
|
||||||
|
|
||||||
|
|
59
_examples/cookies/securecookie/main.go
Normal file
59
_examples/cookies/securecookie/main.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// developers can use any library to add a custom cookie encoder/decoder.
|
||||||
|
// At this example we use the gorilla's securecookie package:
|
||||||
|
// $ go get github.com/gorilla/securecookie
|
||||||
|
// $ go run main.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
|
||||||
|
"github.com/gorilla/securecookie"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// AES only supports key sizes of 16, 24 or 32 bytes.
|
||||||
|
// You either need to provide exactly that amount or you derive the key from what you type in.
|
||||||
|
hashKey = []byte("the-big-and-secret-fash-key-here")
|
||||||
|
blockKey = []byte("lot-secret-of-characters-big-too")
|
||||||
|
sc = securecookie.New(hashKey, blockKey)
|
||||||
|
)
|
||||||
|
|
||||||
|
func newApp() *iris.Application {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
// Set A Cookie.
|
||||||
|
app.Get("/cookies/{name}/{value}", func(ctx iris.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
value := ctx.Params().Get("value")
|
||||||
|
|
||||||
|
ctx.SetCookieKV(name, value, iris.CookieEncode(sc.Encode)) // <--
|
||||||
|
|
||||||
|
ctx.Writef("cookie added: %s = %s", name, value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Retrieve A Cookie.
|
||||||
|
app.Get("/cookies/{name}", func(ctx iris.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
|
||||||
|
value := ctx.GetCookie(name, iris.CookieDecode(sc.Decode)) // <--
|
||||||
|
|
||||||
|
ctx.WriteString(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Delete A Cookie.
|
||||||
|
app.Delete("/cookies/{name}", func(ctx iris.Context) {
|
||||||
|
name := ctx.Params().Get("name")
|
||||||
|
|
||||||
|
ctx.RemoveCookie(name) // <--
|
||||||
|
|
||||||
|
ctx.Writef("cookie %s removed", name)
|
||||||
|
})
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := newApp()
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
34
_examples/cookies/securecookie/main_test.go
Normal file
34
_examples/cookies/securecookie/main_test.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCookiesBasic(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("/cookies/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK)
|
||||||
|
// note that this will not work because it doesn't always returns the same value:
|
||||||
|
// cookieValueEncoded, _ := sc.Encode(cookieName, cookieValue)
|
||||||
|
t1.Cookie(cookieName).Value().NotEqual(cookieValue) // validate cookie's existence and value is not on its raw form.
|
||||||
|
t1.Body().Contains(cookieValue)
|
||||||
|
|
||||||
|
// Test Retrieve A Cookie.
|
||||||
|
t2 := e.GET(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK)
|
||||||
|
t2.Body().Equal(cookieValue)
|
||||||
|
|
||||||
|
// Test Remove A Cookie.
|
||||||
|
t3 := e.DELETE(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK)
|
||||||
|
t3.Body().Contains(cookieName)
|
||||||
|
|
||||||
|
t4 := e.GET(fmt.Sprintf("/cookies/%s", cookieName)).Expect().Status(httptest.StatusOK)
|
||||||
|
t4.Cookies().Empty()
|
||||||
|
t4.Body().Empty()
|
||||||
|
}
|
|
@ -676,6 +676,14 @@ type Context interface {
|
||||||
// was being registered to this request's path.
|
// was being registered to this request's path.
|
||||||
GetCurrentRoute() RouteReadOnly
|
GetCurrentRoute() RouteReadOnly
|
||||||
|
|
||||||
|
// Do calls the SetHandlers(handlers)
|
||||||
|
// and executes the first handler,
|
||||||
|
// handlers should not be empty.
|
||||||
|
//
|
||||||
|
// It's used by the router, developers may use that
|
||||||
|
// to replace and execute handlers immediately.
|
||||||
|
Do(Handlers)
|
||||||
|
|
||||||
// AddHandler can add handler(s)
|
// AddHandler can add handler(s)
|
||||||
// to the current request in serve-time,
|
// to the current request in serve-time,
|
||||||
// these handlers are not persistenced to the router.
|
// these handlers are not persistenced to the router.
|
||||||
|
@ -697,6 +705,43 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// Look Handlers(), Next() and StopExecution() too.
|
// Look Handlers(), Next() and StopExecution() too.
|
||||||
HandlerIndex(n int) (currentIndex int)
|
HandlerIndex(n int) (currentIndex int)
|
||||||
|
// Proceed is an alternative way to check if a particular handler
|
||||||
|
// has been executed and called the `ctx.Next` function inside it.
|
||||||
|
// This is useful only when you run a handler inside
|
||||||
|
// another handler. It justs checks for before index and the after index.
|
||||||
|
//
|
||||||
|
// A usecase example is when you want to execute a middleware
|
||||||
|
// inside controller's `BeginRequest` that calls the `ctx.Next` inside it.
|
||||||
|
// The Controller looks the whole flow (BeginRequest, method handler, EndRequest)
|
||||||
|
// as one handler, so `ctx.Next` will not be reflected to the method handler
|
||||||
|
// if called from the `BeginRequest`.
|
||||||
|
//
|
||||||
|
// Although `BeginRequest` should NOT be used to call other handlers,
|
||||||
|
// the `BeginRequest` has been introduced to be able to set
|
||||||
|
// common data to all method handlers before their execution.
|
||||||
|
// Controllers can accept middleware(s) from the MVC's Application's Router as normally.
|
||||||
|
//
|
||||||
|
// That said let's see an example of `ctx.Proceed`:
|
||||||
|
//
|
||||||
|
// var authMiddleware = basicauth.New(basicauth.Config{
|
||||||
|
// Users: map[string]string{
|
||||||
|
// "admin": "password",
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
||||||
|
// if !ctx.Proceed(authMiddleware) {
|
||||||
|
// ctx.StopExecution()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// This Get() will be executed in the same handler as `BeginRequest`,
|
||||||
|
// internally controller checks for `ctx.StopExecution`.
|
||||||
|
// So it will not be fired if BeginRequest called the `StopExecution`.
|
||||||
|
// func(c *UsersController) Get() []models.User {
|
||||||
|
// return c.Service.GetAll()
|
||||||
|
//}
|
||||||
|
// Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
|
||||||
|
Proceed(Handler) bool
|
||||||
// HandlerName returns the current handler's name, helpful for debugging.
|
// HandlerName returns the current handler's name, helpful for debugging.
|
||||||
HandlerName() string
|
HandlerName() string
|
||||||
// Next calls all the next handler from the handlers chain,
|
// Next calls all the next handler from the handlers chain,
|
||||||
|
@ -704,14 +749,29 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
|
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
|
||||||
Next()
|
Next()
|
||||||
// NextHandler returns(but it is NOT executes) the next handler from the handlers chain.
|
// NextOr checks if chain has a next handler, if so then it executes it
|
||||||
|
// otherwise it sets a new chain assigned to this Context based on the given handler(s)
|
||||||
|
// and executes its first handler.
|
||||||
|
//
|
||||||
|
// Returns true if next handler exists and executed, otherwise false.
|
||||||
|
//
|
||||||
|
// Note that if no next handler found and handlers are missing then
|
||||||
|
// it sends a Status Not Found (404) to the client and it stops the execution.
|
||||||
|
NextOr(handlers ...Handler) bool
|
||||||
|
// NextOrNotFound checks if chain has a next handler, if so then it executes it
|
||||||
|
// otherwise it sends a Status Not Found (404) to the client and stops the execution.
|
||||||
|
//
|
||||||
|
// Returns true if next handler exists and executed, otherwise false.
|
||||||
|
NextOrNotFound() bool
|
||||||
|
// NextHandler returns (it doesn't execute) the next handler from the handlers chain.
|
||||||
//
|
//
|
||||||
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||||
NextHandler() Handler
|
NextHandler() Handler
|
||||||
// Skip skips/ignores the next handler from the handlers chain,
|
// Skip skips/ignores the next handler from the handlers chain,
|
||||||
// it should be used inside a middleware.
|
// it should be used inside a middleware.
|
||||||
Skip()
|
Skip()
|
||||||
// StopExecution if called then the following .Next calls are ignored.
|
// StopExecution if called then the following .Next calls are ignored,
|
||||||
|
// as a result the next handlers in the chain will not be fire.
|
||||||
StopExecution()
|
StopExecution()
|
||||||
// IsStopped checks and returns true if the current position of the Context is 255,
|
// IsStopped checks and returns true if the current position of the Context is 255,
|
||||||
// means that the StopExecution() was called.
|
// means that the StopExecution() was called.
|
||||||
|
@ -759,6 +819,8 @@ type Context interface {
|
||||||
// Subdomain returns the subdomain of this request, if any.
|
// Subdomain returns the subdomain of this request, if any.
|
||||||
// Note that this is a fast method which does not cover all cases.
|
// Note that this is a fast method which does not cover all cases.
|
||||||
Subdomain() (subdomain string)
|
Subdomain() (subdomain string)
|
||||||
|
// IsWWW returns true if the current subdomain (if any) is www.
|
||||||
|
IsWWW() bool
|
||||||
// RemoteAddr tries to parse and return the real client's request IP.
|
// RemoteAddr tries to parse and return the real client's request IP.
|
||||||
//
|
//
|
||||||
// Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
|
// Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
|
||||||
|
@ -787,7 +849,12 @@ type Context interface {
|
||||||
// Read more at: https://developer.mozilla.org/en-US/docs/AJAX
|
// Read more at: https://developer.mozilla.org/en-US/docs/AJAX
|
||||||
// and https://xhr.spec.whatwg.org/
|
// and https://xhr.spec.whatwg.org/
|
||||||
IsAjax() bool
|
IsAjax() bool
|
||||||
|
// IsMobile checks if client is using a mobile device(phone or tablet) to communicate with this server.
|
||||||
|
// If the return value is true that means that the http client using a mobile
|
||||||
|
// device to communicate with the server, otherwise false.
|
||||||
|
//
|
||||||
|
// Keep note that this checks the "User-Agent" request header.
|
||||||
|
IsMobile() bool
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Response Headers helpers |
|
// | Response Headers helpers |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
@ -801,6 +868,10 @@ type Context interface {
|
||||||
// which may, setted before with the 'ContentType'.
|
// which may, setted before with the 'ContentType'.
|
||||||
GetContentType() string
|
GetContentType() string
|
||||||
|
|
||||||
|
// GetContentLength returns the request's header value of "Content-Length".
|
||||||
|
// Returns 0 if header was unable to be found or its value was not a valid number.
|
||||||
|
GetContentLength() int64
|
||||||
|
|
||||||
// StatusCode sets the status code header to the response.
|
// StatusCode sets the status code header to the response.
|
||||||
// Look .GetStatusCode too.
|
// Look .GetStatusCode too.
|
||||||
StatusCode(statusCode int)
|
StatusCode(statusCode int)
|
||||||
|
@ -808,44 +879,160 @@ type Context interface {
|
||||||
// Look StatusCode too.
|
// Look StatusCode too.
|
||||||
GetStatusCode() int
|
GetStatusCode() int
|
||||||
|
|
||||||
// Redirect redirect sends a redirect response the client
|
// Redirect sends a redirect response to the client
|
||||||
|
// to a specific url or relative path.
|
||||||
// accepts 2 parameters string and an optional int
|
// accepts 2 parameters string and an optional int
|
||||||
// first parameter is the url to redirect
|
// first parameter is the url to redirect
|
||||||
// second parameter is the http status should send, default is 302 (StatusFound),
|
// second parameter is the http status should send,
|
||||||
// you can set it to 301 (Permant redirect), if that's nessecery
|
// default is 302 (StatusFound),
|
||||||
|
// you can set it to 301 (Permant redirect)
|
||||||
|
// or 303 (StatusSeeOther) if POST method,
|
||||||
|
// or StatusTemporaryRedirect(307) if that's nessecery.
|
||||||
Redirect(urlToRedirect string, statusHeader ...int)
|
Redirect(urlToRedirect string, statusHeader ...int)
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Various Request and Post Data |
|
// | Various Request and Post Data |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
|
||||||
// URLParam returns the get parameter from a request , if any.
|
// URLParam returns true if the url parameter exists, otherwise false.
|
||||||
|
URLParamExists(name string) bool
|
||||||
|
// URLParamDefault returns the get parameter from a request,
|
||||||
|
// if not found then "def" is returned.
|
||||||
|
URLParamDefault(name string, def string) string
|
||||||
|
// URLParam returns the get parameter from a request, if any.
|
||||||
URLParam(name string) string
|
URLParam(name string) string
|
||||||
|
// URLParamTrim returns the url query parameter with trailing white spaces removed from a request.
|
||||||
|
URLParamTrim(name string) string
|
||||||
|
// URLParamTrim returns the escaped url query parameter from a request.
|
||||||
|
URLParamEscape(name string) string
|
||||||
// URLParamInt returns the url query parameter as int value from a request,
|
// URLParamInt returns the url query parameter as int value from a request,
|
||||||
// returns an error if parse failed.
|
// returns -1 and an error if parse failed.
|
||||||
URLParamInt(name string) (int, error)
|
URLParamInt(name string) (int, error)
|
||||||
|
// URLParamIntDefault returns the url query parameter as int value from a request,
|
||||||
|
// if not found or parse failed then "def" is returned.
|
||||||
|
URLParamIntDefault(name string, def int) int
|
||||||
// URLParamInt64 returns the url query parameter as int64 value from a request,
|
// URLParamInt64 returns the url query parameter as int64 value from a request,
|
||||||
// returns an error if parse failed.
|
// returns -1 and an error if parse failed.
|
||||||
URLParamInt64(name string) (int64, error)
|
URLParamInt64(name string) (int64, error)
|
||||||
|
// URLParamInt64Default returns the url query parameter as int64 value from a request,
|
||||||
|
// if not found or parse failed then "def" is returned.
|
||||||
|
URLParamInt64Default(name string, def int64) int64
|
||||||
|
// URLParamFloat64 returns the url query parameter as float64 value from a request,
|
||||||
|
// returns -1 and an error if parse failed.
|
||||||
|
URLParamFloat64(name string) (float64, error)
|
||||||
|
// URLParamFloat64Default returns the url query parameter as float64 value from a request,
|
||||||
|
// if not found or parse failed then "def" is returned.
|
||||||
|
URLParamFloat64Default(name string, def float64) float64
|
||||||
|
// URLParamBool returns the url query parameter as boolean value from a request,
|
||||||
|
// returns an error if parse failed or not found.
|
||||||
|
URLParamBool(name string) (bool, error)
|
||||||
// URLParams returns a map of GET query parameters separated by comma if more than one
|
// URLParams returns a map of GET query parameters separated by comma if more than one
|
||||||
// it returns an empty map if nothing found.
|
// it returns an empty map if nothing found.
|
||||||
URLParams() map[string]string
|
URLParams() map[string]string
|
||||||
|
|
||||||
// FormValue returns a single form value by its name/key
|
// FormValueDefault returns a single parsed form value by its "name",
|
||||||
|
// including both the URL field's query parameters and the POST or PUT form data.
|
||||||
|
//
|
||||||
|
// Returns the "def" if not found.
|
||||||
|
FormValueDefault(name string, def string) string
|
||||||
|
// FormValue returns a single parsed form value by its "name",
|
||||||
|
// including both the URL field's query parameters and the POST or PUT form data.
|
||||||
FormValue(name string) string
|
FormValue(name string) string
|
||||||
// FormValues returns all post data values with their keys
|
// FormValues returns the parsed form data, including both the URL
|
||||||
// form data, get, post & put query arguments
|
// field's query parameters and the POST or PUT form data.
|
||||||
|
//
|
||||||
|
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||||
|
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||||
//
|
//
|
||||||
// NOTE: A check for nil is necessary.
|
// NOTE: A check for nil is necessary.
|
||||||
FormValues() map[string][]string
|
FormValues() map[string][]string
|
||||||
// PostValue returns a form's only-post value by its name,
|
|
||||||
// same as Request.PostFormValue.
|
// PostValueDefault returns the parsed form data from POST, PATCH,
|
||||||
PostValue(name string) string
|
// or PUT body parameters based on a "name".
|
||||||
// FormFile returns the first file for the provided form key.
|
|
||||||
// FormFile calls ctx.Request.ParseMultipartForm and ParseForm if necessary.
|
|
||||||
//
|
//
|
||||||
// same as Request.FormFile.
|
// If not found then "def" is returned instead.
|
||||||
|
PostValueDefault(name string, def string) string
|
||||||
|
// PostValue returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name"
|
||||||
|
PostValue(name string) string
|
||||||
|
// PostValueTrim returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", without trailing spaces.
|
||||||
|
PostValueTrim(name string) string
|
||||||
|
// PostValueInt returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as int.
|
||||||
|
//
|
||||||
|
// If not found returns -1 and a non-nil error.
|
||||||
|
PostValueInt(name string) (int, error)
|
||||||
|
// PostValueIntDefault returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as int.
|
||||||
|
//
|
||||||
|
// If not found returns or parse errors the "def".
|
||||||
|
PostValueIntDefault(name string, def int) int
|
||||||
|
// PostValueInt64 returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as float64.
|
||||||
|
//
|
||||||
|
// If not found returns -1 and a no-nil error.
|
||||||
|
PostValueInt64(name string) (int64, error)
|
||||||
|
// PostValueInt64Default returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as int64.
|
||||||
|
//
|
||||||
|
// If not found or parse errors returns the "def".
|
||||||
|
PostValueInt64Default(name string, def int64) int64
|
||||||
|
// PostValueInt64Default returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as float64.
|
||||||
|
//
|
||||||
|
// If not found returns -1 and a non-nil error.
|
||||||
|
PostValueFloat64(name string) (float64, error)
|
||||||
|
// PostValueInt64Default returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as float64.
|
||||||
|
//
|
||||||
|
// If not found or parse errors returns the "def".
|
||||||
|
PostValueFloat64Default(name string, def float64) float64
|
||||||
|
// PostValueInt64Default returns the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name", as bool.
|
||||||
|
//
|
||||||
|
// If not found or value is false, then it returns false, otherwise true.
|
||||||
|
PostValueBool(name string) (bool, error)
|
||||||
|
// PostValues returns all the parsed form data from POST, PATCH,
|
||||||
|
// or PUT body parameters based on a "name" as a string slice.
|
||||||
|
//
|
||||||
|
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||||
|
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||||
|
PostValues(name string) []string
|
||||||
|
// FormFile returns the first uploaded file that received from the client.
|
||||||
|
//
|
||||||
|
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||||
|
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-file
|
||||||
FormFile(key string) (multipart.File, *multipart.FileHeader, error)
|
FormFile(key string) (multipart.File, *multipart.FileHeader, error)
|
||||||
|
// UploadFormFiles uploads any received file(s) from the client
|
||||||
|
// to the system physical location "destDirectory".
|
||||||
|
//
|
||||||
|
// The second optional argument "before" gives caller the chance to
|
||||||
|
// modify the *miltipart.FileHeader before saving to the disk,
|
||||||
|
// it can be used to change a file's name based on the current request,
|
||||||
|
// all FileHeader's options can be changed. You can ignore it if
|
||||||
|
// you don't need to use this capability before saving a file to the disk.
|
||||||
|
//
|
||||||
|
// Note that it doesn't check if request body streamed.
|
||||||
|
//
|
||||||
|
// Returns the copied length as int64 and
|
||||||
|
// a not nil error if at least one new file
|
||||||
|
// can't be created due to the operating system's permissions or
|
||||||
|
// http.ErrMissingFile if no file received.
|
||||||
|
//
|
||||||
|
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
|
||||||
|
// instead and create a copy function that suits your needs, the below is for generic usage.
|
||||||
|
//
|
||||||
|
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||||
|
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||||
|
//
|
||||||
|
// See `FormFile` to a more controlled to receive a file.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-files
|
||||||
|
UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error)
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Custom HTTP Errors |
|
// | Custom HTTP Errors |
|
||||||
|
@ -867,16 +1054,24 @@ type Context interface {
|
||||||
// should be called before reading the request body from the client.
|
// should be called before reading the request body from the client.
|
||||||
SetMaxRequestBodySize(limitOverBytes int64)
|
SetMaxRequestBodySize(limitOverBytes int64)
|
||||||
|
|
||||||
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type
|
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type.
|
||||||
// Examples of usage: context.ReadJSON, context.ReadXML.
|
// Examples of usage: context.ReadJSON, context.ReadXML.
|
||||||
UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error
|
//
|
||||||
// ReadJSON reads JSON from request's body and binds it to a value of any json-valid type.
|
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
|
||||||
ReadJSON(jsonObject interface{}) error
|
UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error
|
||||||
// ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
|
// ReadJSON reads JSON from request's body and binds it to a pointer of a value of any json-valid type.
|
||||||
ReadXML(xmlObject interface{}) error
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-json/main.go
|
||||||
|
ReadJSON(jsonObjectPtr interface{}) error
|
||||||
|
// ReadXML reads XML from request's body and binds it to a pointer of a value of any xml-valid type.
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-xml/main.go
|
||||||
|
ReadXML(xmlObjectPtr interface{}) error
|
||||||
// ReadForm binds the formObject with the form data
|
// ReadForm binds the formObject with the form data
|
||||||
// it supports any kind of struct.
|
// it supports any kind of struct.
|
||||||
ReadForm(formObject interface{}) error
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-form/main.go
|
||||||
|
ReadForm(formObjectPtr interface{}) error
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Body (raw) Writers |
|
// | Body (raw) Writers |
|
||||||
|
@ -910,6 +1105,39 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// Returns the number of bytes written and any write error encountered.
|
// Returns the number of bytes written and any write error encountered.
|
||||||
WriteString(body string) (int, error)
|
WriteString(body string) (int, error)
|
||||||
|
|
||||||
|
// SetLastModified sets the "Last-Modified" based on the "modtime" input.
|
||||||
|
// If "modtime" is zero then it does nothing.
|
||||||
|
//
|
||||||
|
// It's mostly internally on core/router and context packages.
|
||||||
|
//
|
||||||
|
// Note that modtime.UTC() is being used instead of just modtime, so
|
||||||
|
// you don't have to know the internals in order to make that works.
|
||||||
|
SetLastModified(modtime time.Time)
|
||||||
|
// CheckIfModifiedSince checks if the response is modified since the "modtime".
|
||||||
|
// Note that it has nothing to do with server-side caching.
|
||||||
|
// It does those checks by checking if the "If-Modified-Since" request header
|
||||||
|
// sent by client or a previous server response header
|
||||||
|
// (e.g with WriteWithExpiration or StaticEmbedded or Favicon etc.)
|
||||||
|
// is a valid one and it's before the "modtime".
|
||||||
|
//
|
||||||
|
// A check for !modtime && err == nil is necessary to make sure that
|
||||||
|
// it's not modified since, because it may return false but without even
|
||||||
|
// had the chance to check the client-side (request) header due to some errors,
|
||||||
|
// like the HTTP Method is not "GET" or "HEAD" or if the "modtime" is zero
|
||||||
|
// or if parsing time from the header failed.
|
||||||
|
//
|
||||||
|
// It's mostly used internally, e.g. `context#WriteWithExpiration`.
|
||||||
|
//
|
||||||
|
// Note that modtime.UTC() is being used instead of just modtime, so
|
||||||
|
// you don't have to know the internals in order to make that works.
|
||||||
|
CheckIfModifiedSince(modtime time.Time) (bool, error)
|
||||||
|
// WriteNotModified sends a 304 "Not Modified" status code to the client,
|
||||||
|
// it makes sure that the content type, the content length headers
|
||||||
|
// and any "ETag" are removed before the response sent.
|
||||||
|
//
|
||||||
|
// It's mostly used internally on core/router/fs.go and context methods.
|
||||||
|
WriteNotModified()
|
||||||
// WriteWithExpiration like Write but it sends with an expiration datetime
|
// WriteWithExpiration like Write but it sends with an expiration datetime
|
||||||
// which is refreshed every package-level `StaticCacheDuration` field.
|
// which is refreshed every package-level `StaticCacheDuration` field.
|
||||||
WriteWithExpiration(body []byte, modtime time.Time) (int, error)
|
WriteWithExpiration(body []byte, modtime time.Time) (int, error)
|
||||||
|
@ -936,13 +1164,11 @@ type Context interface {
|
||||||
ClientSupportsGzip() bool
|
ClientSupportsGzip() bool
|
||||||
// WriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
|
// WriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
|
||||||
// returns the number of bytes written and an error ( if the client doesn' supports gzip compression)
|
// returns the number of bytes written and an error ( if the client doesn' supports gzip compression)
|
||||||
//
|
// You may re-use this function in the same handler
|
||||||
// This function writes temporary gzip contents, the ResponseWriter is untouched.
|
// to write more data many times without any troubles.
|
||||||
WriteGzip(b []byte) (int, error)
|
WriteGzip(b []byte) (int, error)
|
||||||
// TryWriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
|
// TryWriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
|
||||||
// If client does not supprots gzip then the contents are written as they are, uncompressed.
|
// If client does not supprots gzip then the contents are written as they are, uncompressed.
|
||||||
//
|
|
||||||
// This function writes temporary gzip contents, the ResponseWriter is untouched.
|
|
||||||
TryWriteGzip(b []byte) (int, error)
|
TryWriteGzip(b []byte) (int, error)
|
||||||
// GzipResponseWriter converts the current response writer into a response writer
|
// GzipResponseWriter converts the current response writer into a response writer
|
||||||
// which when its .Write called it compress the data to gzip and writes them to the client.
|
// which when its .Write called it compress the data to gzip and writes them to the client.
|
||||||
|
@ -970,7 +1196,6 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
|
// Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
|
||||||
ViewLayout(layoutTmplFile string)
|
ViewLayout(layoutTmplFile string)
|
||||||
|
|
||||||
// ViewData saves one or more key-value pair in order to be passed if and when .View
|
// ViewData saves one or more key-value pair in order to be passed if and when .View
|
||||||
// is being called afterwards, in the same request.
|
// is being called afterwards, in the same request.
|
||||||
// Useful when need to set or/and change template data from previous hanadlers in the chain.
|
// Useful when need to set or/and change template data from previous hanadlers in the chain.
|
||||||
|
@ -990,7 +1215,6 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
|
// Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
|
||||||
ViewData(key string, value interface{})
|
ViewData(key string, value interface{})
|
||||||
|
|
||||||
// GetViewData returns the values registered by `context#ViewData`.
|
// GetViewData returns the values registered by `context#ViewData`.
|
||||||
// The return value is `map[string]interface{}`, this means that
|
// The return value is `map[string]interface{}`, this means that
|
||||||
// if a custom struct registered to ViewData then this function
|
// if a custom struct registered to ViewData then this function
|
||||||
|
@ -1001,16 +1225,20 @@ type Context interface {
|
||||||
// Similarly to `viewData := ctx.Values().Get("iris.viewData")` or
|
// Similarly to `viewData := ctx.Values().Get("iris.viewData")` or
|
||||||
// `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`.
|
// `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`.
|
||||||
GetViewData() map[string]interface{}
|
GetViewData() map[string]interface{}
|
||||||
|
// View renders a template based on the registered view engine(s).
|
||||||
// View renders templates based on the adapted view engines.
|
// First argument accepts the filename, relative to the view engine's Directory and Extension,
|
||||||
// First argument accepts the filename, relative to the view engine's Directory,
|
|
||||||
// i.e: if directory is "./templates" and want to render the "./templates/users/index.html"
|
// i.e: if directory is "./templates" and want to render the "./templates/users/index.html"
|
||||||
// then you pass the "users/index.html" as the filename argument.
|
// then you pass the "users/index.html" as the filename argument.
|
||||||
//
|
//
|
||||||
// Look: .ViewData and .ViewLayout too.
|
// The second optional argument can receive a single "view model"
|
||||||
|
// that will be binded to the view template if it's not nil,
|
||||||
|
// otherwise it will check for previous view data stored by the `ViewData`
|
||||||
|
// even if stored at any previous handler(middleware) for the same request.
|
||||||
//
|
//
|
||||||
// Examples: https://github.com/kataras/iris/tree/master/_examples/view/
|
// Look .ViewData` and .ViewLayout too.
|
||||||
View(filename string) error
|
//
|
||||||
|
// Examples: https://github.com/kataras/iris/tree/master/_examples/view
|
||||||
|
View(filename string, optionalViewModel ...interface{}) error
|
||||||
|
|
||||||
// Binary writes out the raw bytes as binary data.
|
// Binary writes out the raw bytes as binary data.
|
||||||
Binary(data []byte) (int, error)
|
Binary(data []byte) (int, error)
|
||||||
|
@ -1024,9 +1252,10 @@ type Context interface {
|
||||||
JSONP(v interface{}, options ...JSONP) (int, error)
|
JSONP(v interface{}, options ...JSONP) (int, error)
|
||||||
// XML marshals the given interface object and writes the XML response.
|
// XML marshals the given interface object and writes the XML response.
|
||||||
XML(v interface{}, options ...XML) (int, error)
|
XML(v interface{}, options ...XML) (int, error)
|
||||||
// Markdown parses the markdown to html and renders to client.
|
// Markdown parses the markdown to html and renders its result to the client.
|
||||||
Markdown(markdownB []byte, options ...Markdown) (int, error)
|
Markdown(markdownB []byte, options ...Markdown) (int, error)
|
||||||
|
// YAML parses the "v" using the yaml parser and renders its result to the client.
|
||||||
|
YAML(v interface{}) (int, error)
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Serve files |
|
// | Serve files |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
@ -1034,18 +1263,23 @@ type Context interface {
|
||||||
// ServeContent serves content, headers are autoset
|
// ServeContent serves content, headers are autoset
|
||||||
// receives three parameters, it's low-level function, instead you can use .ServeFile(string,bool)/SendFile(string,string)
|
// receives three parameters, it's low-level function, instead you can use .ServeFile(string,bool)/SendFile(string,string)
|
||||||
//
|
//
|
||||||
// You can define your own "Content-Type" header also, after this function call
|
//
|
||||||
// Doesn't implements resuming (by range), use ctx.SendFile instead
|
// You can define your own "Content-Type" with `context#ContentType`, before this function call.
|
||||||
|
//
|
||||||
|
// This function doesn't support resuming (by range),
|
||||||
|
// use ctx.SendFile or router's `StaticWeb` instead.
|
||||||
ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error
|
ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error
|
||||||
// ServeFile serves a view file, to send a file ( zip for example) to the client you should use the SendFile(serverfilename,clientfilename)
|
// ServeFile serves a file (to send a file, a zip for example to the client you should use the `SendFile` instead)
|
||||||
// receives two parameters
|
// receives two parameters
|
||||||
// filename/path (string)
|
// filename/path (string)
|
||||||
// gzipCompression (bool)
|
// gzipCompression (bool)
|
||||||
//
|
//
|
||||||
// You can define your own "Content-Type" header also, after this function call
|
// You can define your own "Content-Type" with `context#ContentType`, before this function call.
|
||||||
// This function doesn't implement resuming (by range), use ctx.SendFile instead
|
|
||||||
//
|
//
|
||||||
// Use it when you want to serve css/js/... files to the client, for bigger files and 'force-download' use the SendFile.
|
// This function doesn't support resuming (by range),
|
||||||
|
// use ctx.SendFile or router's `StaticWeb` instead.
|
||||||
|
//
|
||||||
|
// Use it when you want to serve dynamic files to the client.
|
||||||
ServeFile(filename string, gzipCompression bool) error
|
ServeFile(filename string, gzipCompression bool) error
|
||||||
// SendFile sends file for force-download to the client
|
// SendFile sends file for force-download to the client
|
||||||
//
|
//
|
||||||
|
@ -1056,18 +1290,41 @@ type Context interface {
|
||||||
// | Cookies |
|
// | Cookies |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
|
||||||
// SetCookie adds a cookie
|
// SetCookie adds a cookie.
|
||||||
SetCookie(cookie *http.Cookie)
|
// Use of the "options" is not required, they can be used to amend the "cookie".
|
||||||
// SetCookieKV adds a cookie, receives just a name(string) and a value(string)
|
|
||||||
//
|
//
|
||||||
// If you use this method, it expires at 2 hours
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
|
||||||
// use ctx.SetCookie or http.SetCookie if you want to change more fields.
|
SetCookie(cookie *http.Cookie, options ...CookieOption)
|
||||||
SetCookieKV(name, value string)
|
// SetCookieKV adds a cookie, requires the name(string) and the value(string).
|
||||||
|
//
|
||||||
|
// By default it expires at 2 hours and it's added to the root path,
|
||||||
|
// use the `CookieExpires` and `CookiePath` to modify them.
|
||||||
|
// Alternatively: ctx.SetCookie(&http.Cookie{...})
|
||||||
|
//
|
||||||
|
// If you want to set custom the path:
|
||||||
|
// ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))
|
||||||
|
//
|
||||||
|
// If you want to be visible only to current request path:
|
||||||
|
// ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
|
||||||
|
// More:
|
||||||
|
// iris.CookieExpires(time.Duration)
|
||||||
|
// iris.CookieHTTPOnly(false)
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
|
||||||
|
SetCookieKV(name, value string, options ...CookieOption)
|
||||||
// GetCookie returns cookie's value by it's name
|
// GetCookie returns cookie's value by it's name
|
||||||
// returns empty string if nothing was found.
|
// returns empty string if nothing was found.
|
||||||
GetCookie(name string) string
|
//
|
||||||
// RemoveCookie deletes a cookie by it's name.
|
// If you want more than the value then:
|
||||||
RemoveCookie(name string)
|
// cookie, err := ctx.Request().Cookie("name")
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
|
||||||
|
GetCookie(name string, options ...CookieOption) string
|
||||||
|
// RemoveCookie deletes a cookie by it's name and path = "/".
|
||||||
|
// Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath)
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
|
||||||
|
RemoveCookie(name string, options ...CookieOption)
|
||||||
// VisitAllCookies takes a visitor which loops
|
// VisitAllCookies takes a visitor which loops
|
||||||
// on each (request's) cookies' name and value.
|
// on each (request's) cookies' name and value.
|
||||||
VisitAllCookies(visitor func(name string, value string))
|
VisitAllCookies(visitor func(name string, value string))
|
||||||
|
@ -1112,7 +1369,7 @@ type Context interface {
|
||||||
// TransactionsSkipped returns true if the transactions skipped or canceled at all.
|
// TransactionsSkipped returns true if the transactions skipped or canceled at all.
|
||||||
TransactionsSkipped() bool
|
TransactionsSkipped() bool
|
||||||
|
|
||||||
// Exec calls the framewrok's ServeCtx
|
// Exec calls the `context/Application#ServeCtx`
|
||||||
// based on this context but with a changed method and path
|
// based on this context but with a changed method and path
|
||||||
// like it was requested by the user, but it is not.
|
// like it was requested by the user, but it is not.
|
||||||
//
|
//
|
||||||
|
@ -1135,7 +1392,11 @@ type Context interface {
|
||||||
// Context's Values and the Session are kept in order to be able to communicate via the result route.
|
// Context's Values and the Session are kept in order to be able to communicate via the result route.
|
||||||
//
|
//
|
||||||
// It's for extreme use cases, 99% of the times will never be useful for you.
|
// It's for extreme use cases, 99% of the times will never be useful for you.
|
||||||
Exec(method string, path string)
|
Exec(method, path string)
|
||||||
|
|
||||||
|
// RouteExists reports whether a particular route exists
|
||||||
|
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||||
|
RouteExists(method, path string) bool
|
||||||
|
|
||||||
// Application returns the iris app instance which belongs to this context.
|
// Application returns the iris app instance which belongs to this context.
|
||||||
// Worth to notice that this function returns an interface
|
// Worth to notice that this function returns an interface
|
||||||
|
@ -1143,5 +1404,14 @@ type Context interface {
|
||||||
// to be executed at serve-time. The full app's fields
|
// to be executed at serve-time. The full app's fields
|
||||||
// and methods are not available here for the developer's safety.
|
// and methods are not available here for the developer's safety.
|
||||||
Application() Application
|
Application() Application
|
||||||
|
|
||||||
|
// String returns the string representation of this request.
|
||||||
|
// Each context has a unique string representation.
|
||||||
|
// It can be used for simple debugging scenarios, i.e print context as string.
|
||||||
|
//
|
||||||
|
// What it returns? A number which declares the length of the
|
||||||
|
// total `String` calls per executable application, followed
|
||||||
|
// by the remote IP (the client) and finally the method:url.
|
||||||
|
String() string
|
||||||
}
|
}
|
||||||
```
|
```
|
|
@ -3058,6 +3058,64 @@ func CookieHTTPOnly(httpOnly bool) CookieOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// CookieEncoder should encode the cookie value.
|
||||||
|
// Should accept as first argument the cookie name
|
||||||
|
// and as second argument the cookie value ptr.
|
||||||
|
// Should return an encoded value or an empty one if encode operation failed.
|
||||||
|
// Should return an error if encode operation failed.
|
||||||
|
//
|
||||||
|
// Note: Errors are not printed, so you have to know what you're doing,
|
||||||
|
// and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
|
||||||
|
// You either need to provide exactly that amount or you derive the key from what you type in.
|
||||||
|
//
|
||||||
|
// See `CookieDecoder` too.
|
||||||
|
CookieEncoder func(cookieName string, value interface{}) (string, error)
|
||||||
|
// CookieDecoder should decode the cookie value.
|
||||||
|
// Should accept as first argument the cookie name,
|
||||||
|
// as second argument the encoded cookie value and as third argument the decoded value ptr.
|
||||||
|
// Should return a decoded value or an empty one if decode operation failed.
|
||||||
|
// Should return an error if decode operation failed.
|
||||||
|
//
|
||||||
|
// Note: Errors are not printed, so you have to know what you're doing,
|
||||||
|
// and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
|
||||||
|
// You either need to provide exactly that amount or you derive the key from what you type in.
|
||||||
|
//
|
||||||
|
// See `CookieEncoder` too.
|
||||||
|
CookieDecoder func(cookieName string, cookieValue string, v interface{}) error
|
||||||
|
)
|
||||||
|
|
||||||
|
// CookieEncode is a `CookieOption`.
|
||||||
|
// Provides encoding functionality when adding a cookie.
|
||||||
|
// Accepts a `CookieEncoder` and sets the cookie's value to the encoded value.
|
||||||
|
// Users of that is the `SetCookie` and `SetCookieKV`.
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
|
func CookieEncode(encode CookieEncoder) CookieOption {
|
||||||
|
return func(c *http.Cookie) {
|
||||||
|
newVal, err := encode(c.Name, c.Value)
|
||||||
|
if err != nil {
|
||||||
|
c.Value = ""
|
||||||
|
} else {
|
||||||
|
c.Value = newVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CookieDecode is a `CookieOption`.
|
||||||
|
// Provides decoding functionality when retrieving a cookie.
|
||||||
|
// Accepts a `CookieDecoder` and sets the cookie's value to the decoded value before return by the `GetCookie`.
|
||||||
|
// User of that is the `GetCookie`.
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
|
func CookieDecode(decode CookieDecoder) CookieOption {
|
||||||
|
return func(c *http.Cookie) {
|
||||||
|
if err := decode(c.Name, c.Value, &c.Value); err != nil {
|
||||||
|
c.Value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetCookie adds a cookie.
|
// SetCookie adds a cookie.
|
||||||
// Use of the "options" is not required, they can be used to amend the "cookie".
|
// Use of the "options" is not required, they can be used to amend the "cookie".
|
||||||
//
|
//
|
||||||
|
@ -3111,19 +3169,6 @@ func (ctx *context) GetCookie(name string, options ...CookieOption) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// Q: Why named as `CookieOption` and not like `CookieInterceptor`?
|
|
||||||
// A: Because an interceptor would be able to modify the cookie AND stop the 'x' operation, but we don't want to cancel anything.
|
|
||||||
//
|
|
||||||
// Q: Why "Cookie Options" here?
|
|
||||||
// A: Because of the future suport of cookie encoding like I did with sessions.
|
|
||||||
// Two impl ideas:
|
|
||||||
// - Do it so each caller of `GetCookie/SetCookieKV/SetCookie` can have each own encoding or share one, no limit.
|
|
||||||
// - Do it so every of the above three methods will use the same encoding, therefore to the Application's level, limit per Iris app.
|
|
||||||
// We'll see...
|
|
||||||
//
|
|
||||||
// Finally, I should not forget to add links for the new translated READMEs(2) and push a new version with the minor changes so far,
|
|
||||||
// API is stable, so relax and do it on the next commit tomorrow, need sleep.
|
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
opt(cookie)
|
opt(cookie)
|
||||||
}
|
}
|
||||||
|
|
18
iris.go
18
iris.go
|
@ -444,6 +444,24 @@ var (
|
||||||
//
|
//
|
||||||
// A shortcut for the `context#CookieHTTPOnly`.
|
// A shortcut for the `context#CookieHTTPOnly`.
|
||||||
CookieHTTPOnly = context.CookieHTTPOnly
|
CookieHTTPOnly = context.CookieHTTPOnly
|
||||||
|
// CookieEncode is a `CookieOption`.
|
||||||
|
// Provides encoding functionality when adding a cookie.
|
||||||
|
// Accepts a `context#CookieEncoder` and sets the cookie's value to the encoded value.
|
||||||
|
// Users of that is the `context#SetCookie` and `context#SetCookieKV`.
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
|
//
|
||||||
|
// A shortcut for the `context#CookieEncode`.
|
||||||
|
CookieEncode = context.CookieEncode
|
||||||
|
// CookieDecode is a `CookieOption`.
|
||||||
|
// Provides decoding functionality when retrieving a cookie.
|
||||||
|
// Accepts a `context#CookieDecoder` and sets the cookie's value to the decoded value before return by the `GetCookie`.
|
||||||
|
// User of that is the `context#GetCookie`.
|
||||||
|
//
|
||||||
|
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
|
//
|
||||||
|
// A shortcut for the `context#CookieDecode`.
|
||||||
|
CookieDecode = context.CookieDecode
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPA accepts an "assetHandler" which can be the result of an
|
// SPA accepts an "assetHandler" which can be the result of an
|
||||||
|
|
Loading…
Reference in New Issue
Block a user