mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
Update to 8.3.2 | Read HISTORY.md file
Former-commit-id: e6ab761989d596cb004c39e65e04e8968d9461ab
This commit is contained in:
parent
33e651866e
commit
e12513a534
40
HISTORY.md
40
HISTORY.md
|
@ -18,6 +18,46 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
|||
|
||||
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris`.
|
||||
|
||||
|
||||
# Tu, 22 August 2017 | v8.3.2
|
||||
|
||||
|
||||
### MVC
|
||||
|
||||
When one or more values of handler type (`func(ctx context.Context)`) are passed
|
||||
right to the controller initialization then they will be recognised and act as middleware(s)
|
||||
that ran even before the controller activation, there is no reason to load
|
||||
the whole controller if the main handler or its `BeginRequest` are not "allowed" to be executed.
|
||||
|
||||
Example Code
|
||||
|
||||
```go
|
||||
func checkLogin(ctx context.Context) {
|
||||
if !myCustomAuthMethodPassed {
|
||||
// [set a status or redirect, you know what to do]
|
||||
ctx.StatusCode(iris.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
// [continue to the next handler, at this example is our controller itself]
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
// [...]
|
||||
app.Controller(new(ProfileController), checkLogin)
|
||||
// [...]
|
||||
```
|
||||
|
||||
Usage of these kind of MVC features could be found at the [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go#L174) source file.
|
||||
|
||||
### Other minor enhancements
|
||||
|
||||
- fix https://github.com/kataras/iris/issues/726[*](https://github.com/kataras/iris/commit/5e435fc54fe3dbf95308327c2180d1b444ef7e0d)
|
||||
- fix redis sessiondb expiration[*](https://github.com/kataras/iris/commit/85cfc91544c981e87e09c5aa86bad4b85d0b96d3)
|
||||
- update recursively when new version is available[*](https://github.com/kataras/iris/commit/cd3c223536c6a33653a7fcf1f0648123f2b968fd)
|
||||
- some minor session enhancements[*](https://github.com/kataras/iris/commit/2830f3b50ee9c526ac792c3ce1ec1c08c24ea024)
|
||||
|
||||
|
||||
# Sa, 19 August 2017 | v8.3.1
|
||||
|
||||
First of all I want to thank you for the 100% green feedback you gratefully sent me you about
|
||||
|
|
|
@ -38,7 +38,7 @@ Iris may have reached version 8, but we're not stopping there. We have many feat
|
|||
### 📑 Table of contents
|
||||
|
||||
* [Installation](#-installation)
|
||||
* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#sa-19-august-2017--v831)
|
||||
* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-22-august-2017--v832)
|
||||
* [Learn](#-learn)
|
||||
* [HTTP Listening](_examples/#http-listening)
|
||||
* [Configuration](_examples/#configuration)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
8.3.1:https://github.com/kataras/iris/blob/master/HISTORY.md#sa-19-august-2017--v831
|
||||
8.3.2:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-22-august-2017--v832
|
|
@ -220,7 +220,7 @@ Iris Application written using **14 code of lines** ran for **8 seconds** servin
|
|||
|
||||
## Sessions
|
||||
|
||||
Spawn `5000000 requests` with 125 different "threads" targeting a static request path, sets and gets a session based on the name `"key"` and string value `"value"` and write tat session value to the response stream.
|
||||
Spawn `5000000 requests` with 125 different "threads" targeting a static request path, sets and gets a session based on the name `"key"` and string value `"value"` and write that session value to the response stream.
|
||||
|
||||
### .NET Core (Kestrel) with Sessions
|
||||
|
||||
|
|
|
@ -492,15 +492,16 @@ func (api *APIBuilder) Any(relativePath string, handlers ...context.Handler) (ro
|
|||
// }
|
||||
//
|
||||
// Usage: app.Controller("/user/{id:int}", new(UserController), db, time.Now())
|
||||
// Note: Binded values of context.Handler type are being recognised as middlewares by the router.
|
||||
//
|
||||
// Read more at `/mvc#Controller`.
|
||||
func (api *APIBuilder) Controller(relativePath string, controller activator.BaseController,
|
||||
bindValues ...interface{}) (routes []*Route) {
|
||||
registerFunc := func(method string, handler context.Handler) {
|
||||
registerFunc := func(method string, handlers ...context.Handler) {
|
||||
if method == "ANY" || method == "ALL" {
|
||||
routes = api.Any(relativePath, handler)
|
||||
routes = api.Any(relativePath, handlers...)
|
||||
} else {
|
||||
routes = append(routes, api.HandleMany(method, relativePath, handler)...)
|
||||
routes = append(routes, api.HandleMany(method, relativePath, handlers...)...)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -169,6 +169,7 @@ type Party interface {
|
|||
// }
|
||||
//
|
||||
// Usage: app.Controller("/user/{id:int}", new(UserController), db, time.Now())
|
||||
// Note: Binded values of context.Handler type are being recognised as middlewares by the router.
|
||||
//
|
||||
// Read more at `/mvc#Controller`.
|
||||
Controller(relativePath string, controller activator.BaseController, bindValues ...interface{}) []*Route
|
||||
|
|
2
doc.go
2
doc.go
|
@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
Current Version
|
||||
|
||||
8.3.1
|
||||
8.3.2
|
||||
|
||||
Installation
|
||||
|
||||
|
|
2
iris.go
2
iris.go
|
@ -32,7 +32,7 @@ import (
|
|||
|
||||
const (
|
||||
// Version is the current version number of the Iris Web Framework.
|
||||
Version = "8.3.1"
|
||||
Version = "8.3.2"
|
||||
)
|
||||
|
||||
// HTTP status codes as registered with IANA.
|
||||
|
|
|
@ -277,7 +277,7 @@ func buildMethodHandler(t TController, methodFuncIndex int) context.Handler {
|
|||
}
|
||||
|
||||
// RegisterFunc used by the caller to register the result routes.
|
||||
type RegisterFunc func(httpMethod string, handler context.Handler)
|
||||
type RegisterFunc func(httpMethod string, handler ...context.Handler)
|
||||
|
||||
// RegisterMethodHandlers receives a `TController`, description of the
|
||||
// user's controller, and calls the "registerFunc" for each of its
|
||||
|
@ -292,8 +292,19 @@ func RegisterMethodHandlers(t TController, registerFunc RegisterFunc) {
|
|||
// http methods using the registerFunc, which is
|
||||
// responsible to convert these into routes
|
||||
// and add them to router via the APIBuilder.
|
||||
|
||||
var handlers context.Handlers
|
||||
|
||||
if t.binder != nil {
|
||||
if m := t.binder.middleware; len(m) > 0 {
|
||||
handlers = append(handlers, t.binder.middleware...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range t.Methods {
|
||||
registerFunc(m.HTTPMethod, buildMethodHandler(t, m.Index))
|
||||
methodHandler := buildMethodHandler(t, m.Index)
|
||||
registeredHandlers := append(handlers, methodHandler)
|
||||
registerFunc(m.HTTPMethod, registeredHandlers...)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,17 @@ package activator
|
|||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
type binder struct {
|
||||
values []interface{}
|
||||
fields []field
|
||||
|
||||
// saves any middleware that may need to be passed to the router,
|
||||
// statically, to gain performance.
|
||||
middleware context.Handlers
|
||||
}
|
||||
|
||||
// binder accepts a value of something
|
||||
|
@ -26,19 +32,42 @@ func newBinder(elemType reflect.Type, values []interface{}) *binder {
|
|||
|
||||
// if nothing valid found return nil, so the caller
|
||||
// can omit the binder.
|
||||
if len(b.fields) == 0 {
|
||||
if len(b.fields) == 0 && len(b.middleware) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *binder) storeValueIfMiddleware(value reflect.Value) bool {
|
||||
if value.CanInterface() {
|
||||
if m, ok := value.Interface().(context.Handler); ok {
|
||||
b.middleware = append(b.middleware, m)
|
||||
return true
|
||||
}
|
||||
if m, ok := value.Interface().(func(context.Context)); ok {
|
||||
b.middleware = append(b.middleware, m)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *binder) lookup(elem reflect.Type) (fields []field) {
|
||||
for _, v := range b.values {
|
||||
value := reflect.ValueOf(v)
|
||||
// handlers will be recognised as middleware, not struct fields.
|
||||
// End-Developer has the option to call any handler inside
|
||||
// the controller's `BeginRequest` and `EndRequest`, the
|
||||
// state is respected from the method handler already.
|
||||
if b.storeValueIfMiddleware(value) {
|
||||
// stored as middleware, continue to the next field, we don't have
|
||||
// to bind anything here.
|
||||
continue
|
||||
}
|
||||
|
||||
for i, n := 0, elem.NumField(); i < n; i++ {
|
||||
elemField := elem.Field(i)
|
||||
|
||||
if elemField.Type == value.Type() {
|
||||
// we area inside the correct type
|
||||
// println("[0] prepare bind filed for " + elemField.Name)
|
||||
|
@ -111,6 +140,13 @@ func lookupStruct(elem reflect.Type, value reflect.Value) *field {
|
|||
}
|
||||
|
||||
func (b *binder) handle(c reflect.Value) {
|
||||
// we could make check for middlewares here but
|
||||
// these could easly be used outside of the controller
|
||||
// so we don't have to initialize a controller to call them
|
||||
// so they don't belong actually here, we will register them to the
|
||||
// router itself, before the controller's handler to gain performance,
|
||||
// look `activator.go#RegisterMethodHandlers` for more.
|
||||
|
||||
elem := c.Elem() // controller should always be a pointer at this state
|
||||
for _, f := range b.fields {
|
||||
f.sendTo(elem)
|
||||
|
|
|
@ -58,6 +58,7 @@ import (
|
|||
// }
|
||||
//
|
||||
// Usage: app.Controller("/user/{id:int}", new(UserController), db, time.Now())
|
||||
// Note: Binded values of context.Handler type are being recognised as middlewares by the router.
|
||||
//
|
||||
// Look `core/router/APIBuilder#Controller` method too.
|
||||
type Controller struct {
|
||||
|
@ -140,7 +141,7 @@ func (c *Controller) RelPath() string {
|
|||
reqPath := c.Ctx.Path()
|
||||
if len(reqPath) == 0 {
|
||||
// it never come here
|
||||
// but to protect ourselves jsut return an empty slash.
|
||||
// but to protect ourselves just return an empty slash.
|
||||
return slashStr
|
||||
}
|
||||
// [1:]to ellimuate the prefixes like "//"
|
||||
|
|
|
@ -171,6 +171,53 @@ func TestControllerBeginAndEndRequestFunc(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestControllerBeginAndEndRequestFuncBindMiddleware(t *testing.T) {
|
||||
app := iris.New()
|
||||
usernames := map[string]bool{
|
||||
"kataras": true,
|
||||
"makis": false,
|
||||
"efi": true,
|
||||
"rg": false,
|
||||
"bill": true,
|
||||
"whoisyourdaddy": false,
|
||||
}
|
||||
middlewareCheck := func(ctx context.Context) {
|
||||
for username, allow := range usernames {
|
||||
if ctx.Params().Get("username") == username && allow {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.StatusCode(httptest.StatusForbidden)
|
||||
ctx.Writef("forbidden")
|
||||
}
|
||||
|
||||
app.Controller("/profile/{username}", new(testControllerBeginAndEndRequestFunc), middlewareCheck)
|
||||
|
||||
e := httptest.New(t, app)
|
||||
|
||||
doneResponse := "done"
|
||||
|
||||
for username, allow := range usernames {
|
||||
getEx := e.GET("/profile/" + username).Expect()
|
||||
if allow {
|
||||
getEx.Status(httptest.StatusOK).
|
||||
Body().Equal(username + doneResponse)
|
||||
} else {
|
||||
getEx.Status(httptest.StatusForbidden).Body().Equal("forbidden")
|
||||
}
|
||||
|
||||
postEx := e.POST("/profile/" + username).Expect()
|
||||
if allow {
|
||||
postEx.Status(httptest.StatusOK).
|
||||
Body().Equal(username + doneResponse)
|
||||
} else {
|
||||
postEx.Status(httptest.StatusForbidden).Body().Equal("forbidden")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
Username string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user