From af9a1f1241a182714a0e7aef410989db34f5a5cb Mon Sep 17 00:00:00 2001 From: kataras Date: Sun, 5 Nov 2017 04:12:18 +0200 Subject: [PATCH] Update to version 8.5.6 | Read HISTORY.md Former-commit-id: 3c1fb7ad47d54133f68ee0ee8ebe4c3835fe4ce0 --- .gitignore | 3 +- HISTORY.md | 12 ++ README.md | 4 +- VERSION | 2 +- _examples/README.md | 14 +- _examples/apidoc/yaag/main.go | 13 +- _examples/authentication/README.md | 2 +- _examples/experimental-handlers/README.md | 5 + .../casbin/middleware/casbinmodel.conf | 14 ++ .../casbin/middleware/casbinpolicy.csv | 5 + .../casbin/middleware/main.go | 43 ++++++ .../casbin/middleware/main_test.go | 49 +++++++ .../casbin/wrapper/casbinmodel.conf | 14 ++ .../casbin/wrapper/casbinpolicy.csv | 7 + .../casbin/wrapper/main.go | 43 ++++++ .../casbin/wrapper/main_test.go | 80 +++++++++++ .../cloudwatch/simple/main.go | 50 +++++++ .../experimental-handlers/cors/simple/main.go | 43 ++++++ _examples/experimental-handlers/jwt/main.go | 46 +++++++ .../newrelic/simple/main.go | 24 ++++ .../prometheus/simple/main.go | 40 ++++++ .../secure/simple/main.go | 38 ++++++ .../tollboothic/limit-handler/main.go | 31 +++++ .../quicktemplate/templates/base.qtpl.go | 128 ------------------ .../quicktemplate/templates/hello.qtpl.go | 72 ---------- .../quicktemplate/templates/index.qtpl.go | 62 --------- _examples/tutorial/dropzonejs/README.md | 4 +- _examples/tutorial/dropzonejs/README_PART2.md | 4 +- _examples/tutorial/dropzonejs/meta.yml | 8 ++ ...ding-templates-into-app.exe.REMOVED.git-id | 1 - core/maintenance/version.go | 2 +- core/router/api_builder.go | 29 +--- doc.go | 2 +- 33 files changed, 587 insertions(+), 307 deletions(-) create mode 100644 _examples/experimental-handlers/README.md create mode 100644 _examples/experimental-handlers/casbin/middleware/casbinmodel.conf create mode 100644 _examples/experimental-handlers/casbin/middleware/casbinpolicy.csv create mode 100644 _examples/experimental-handlers/casbin/middleware/main.go create mode 100644 _examples/experimental-handlers/casbin/middleware/main_test.go create mode 100644 _examples/experimental-handlers/casbin/wrapper/casbinmodel.conf create mode 100644 _examples/experimental-handlers/casbin/wrapper/casbinpolicy.csv create mode 100644 _examples/experimental-handlers/casbin/wrapper/main.go create mode 100644 _examples/experimental-handlers/casbin/wrapper/main_test.go create mode 100644 _examples/experimental-handlers/cloudwatch/simple/main.go create mode 100644 _examples/experimental-handlers/cors/simple/main.go create mode 100644 _examples/experimental-handlers/jwt/main.go create mode 100644 _examples/experimental-handlers/newrelic/simple/main.go create mode 100644 _examples/experimental-handlers/prometheus/simple/main.go create mode 100644 _examples/experimental-handlers/secure/simple/main.go create mode 100644 _examples/experimental-handlers/tollboothic/limit-handler/main.go delete mode 100644 _examples/http_responsewriter/quicktemplate/templates/base.qtpl.go delete mode 100644 _examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go delete mode 100644 _examples/http_responsewriter/quicktemplate/templates/index.qtpl.go create mode 100644 _examples/tutorial/dropzonejs/meta.yml delete mode 100644 _examples/view/embedding-templates-into-app/embedding-templates-into-app.exe.REMOVED.git-id diff --git a/.gitignore b/.gitignore index 600d2d33..73703f23 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.vscode \ No newline at end of file +.vscode +_authortools \ No newline at end of file diff --git a/HISTORY.md b/HISTORY.md index be0e583f..e3d14ac9 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -17,6 +17,18 @@ 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` or let the automatic updater do that for you. +# Su, 05 November 2017 | v8.5.6 + +- **DEPRECATE** the `app.StaticServe`, use `app.StaticWeb` which does the same thing but better or `iris/app.StaticHandler` which gives you more options to work on. +- add some debug messages for route registrations, to be aligned with the mvc debug messages. +- improve the https://iris-go.com/v8/recipe -- now you can see other files like assets as well -- lexical order of categories instead of "level". +- add [8 more examples](_examples/tree/master/experimental-handlers) to this repository, originally lived at https://github.com/iris-contrib/middleware and https://github.com/iris-contrib/examples/tree/master/experimental-handlers. + +_TODO;_ + +- [ ] give the ability to customize the mvc path-method-and path parameters mapping, +- [ ] make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here. + # Tu, 02 November 2017 | v8.5.5 - fix [audio/mpeg3 does not appear to be a valid registered mime type#798](https://github.com/kataras/iris/issues/798]) reported by @kryptodev, diff --git a/README.md b/README.md index 360c420b..86242417 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs ## Table Of Content * [Installation](#installation) -* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855) +* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#su-05-november-2017--v856) * [Getting started](#getting-started) * [Learn](_examples/) * [MVC (Model View Controller)](_examples/#mvc) **NEW** @@ -74,7 +74,7 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs * [Dockerize](https://github.com/iris-contrib/cloud-native-go) * [Contributing](CONTRIBUTING.md) * [FAQ](FAQ.md) -* [What's next?](#you-are-ready-to-move-to-the-next-step-and-get-closer-to-becoming-a-pro-gopher) +* [What's next?](#now-you-are-ready-to-move-to-the-next-step-and-get-closer-to-becoming-a-pro-gopher) * [People](#people) ## Installation diff --git a/VERSION b/VERSION index ffe8a09e..dda843d0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.5.5:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855 \ No newline at end of file +8.5.6:https://github.com/kataras/iris/blob/master/HISTORY.md#su-05-november-2017--v856 \ No newline at end of file diff --git a/_examples/README.md b/_examples/README.md index db87f037..c5578eea 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -263,7 +263,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files to - [Basic Authentication](authentication/basicauth/main.go) - [OAUth2](authentication/oauth2/main.go) -- [JWT](https://github.com/iris-contrib/middleware/blob/master/jwt/_example/main.go) +- [JWT](experimental-handlers/jwt/main.go) - [Sessions](#sessions) ### File Server @@ -307,6 +307,18 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files to - [Internal Application File Logger](miscellaneous/file-logger/main.go) - [Google reCAPTCHA](miscellaneous/recaptcha/main.go) +### Experimental Handlers + +* [Casbin wrapper](experimental-handlers/casbin/wrapper/main.go) +* [Casbin middleware](experimental-handlers/casbin/middleware/main.go) +* [Cloudwatch](experimental-handlers/cloudwatch/simple/main.go) +* [CORS](experimental-handlers/cors/simple/main.go) +* [JWT](experimental-handlers/jwt/main.go) +* [Newrelic](experimental-handlers/newrelic/simple/main.go) +* [Prometheus](experimental-handlers/prometheus/simple/main.go) +* [Secure](experimental-handlers/secure/simple/main.go) +* [Tollboothic](experimental-handlers/tollboothic/limit-handler/main.go) + #### More https://github.com/kataras/iris/tree/master/middleware#third-party-handlers diff --git a/_examples/apidoc/yaag/main.go b/_examples/apidoc/yaag/main.go index c664ccc3..ed931a53 100644 --- a/_examples/apidoc/yaag/main.go +++ b/_examples/apidoc/yaag/main.go @@ -2,7 +2,6 @@ package main import ( "github.com/kataras/iris" - "github.com/kataras/iris/context" "github.com/betacraft/yaag/irisyaag" "github.com/betacraft/yaag/yaag" @@ -27,21 +26,21 @@ func main() { }) app.Use(irisyaag.New()) // <- IMPORTANT, register the middleware. - app.Get("/json", func(ctx context.Context) { - ctx.JSON(context.Map{"result": "Hello World!"}) + app.Get("/json", func(ctx iris.Context) { + ctx.JSON(iris.Map{"result": "Hello World!"}) }) - app.Get("/plain", func(ctx context.Context) { + app.Get("/plain", func(ctx iris.Context) { ctx.Text("Hello World!") }) - app.Get("/xml", func(ctx context.Context) { + app.Get("/xml", func(ctx iris.Context) { ctx.XML(myXML{Result: "Hello World!"}) }) - app.Get("/complex", func(ctx context.Context) { + app.Get("/complex", func(ctx iris.Context) { value := ctx.URLParam("key") - ctx.JSON(context.Map{"value": value}) + ctx.JSON(iris.Map{"value": value}) }) // Run our HTTP Server. diff --git a/_examples/authentication/README.md b/_examples/authentication/README.md index 0181a263..c7c132ca 100644 --- a/_examples/authentication/README.md +++ b/_examples/authentication/README.md @@ -2,5 +2,5 @@ - [Basic Authentication](basicauth/main.go) - [OAUth2](oauth2/main.go) -- [JWT](https://github.com/iris-contrib/middleware/blob/master/jwt/_example/main.go) +- [JWT](https://github.com/kataras/iris/blob/master/_examples/experimental-handlers/jwt/main.go) - [Sessions](https://github.com/kataras/iris/tree/master/_examples/#sessions) \ No newline at end of file diff --git a/_examples/experimental-handlers/README.md b/_examples/experimental-handlers/README.md new file mode 100644 index 00000000..6e21b557 --- /dev/null +++ b/_examples/experimental-handlers/README.md @@ -0,0 +1,5 @@ +# Install iris-contrib/middleware + +```sh +$ go get -u github.com/iris-contrib/middleware/... +``` \ No newline at end of file diff --git a/_examples/experimental-handlers/casbin/middleware/casbinmodel.conf b/_examples/experimental-handlers/casbin/middleware/casbinmodel.conf new file mode 100644 index 00000000..d1b3dbd7 --- /dev/null +++ b/_examples/experimental-handlers/casbin/middleware/casbinmodel.conf @@ -0,0 +1,14 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") \ No newline at end of file diff --git a/_examples/experimental-handlers/casbin/middleware/casbinpolicy.csv b/_examples/experimental-handlers/casbin/middleware/casbinpolicy.csv new file mode 100644 index 00000000..52837375 --- /dev/null +++ b/_examples/experimental-handlers/casbin/middleware/casbinpolicy.csv @@ -0,0 +1,5 @@ +p, alice, /dataset1/*, GET +p, alice, /dataset1/resource1, POST +p, bob, /dataset2/resource1, * +p, bob, /dataset2/resource2, GET +p, bob, /dataset2/folder1/*, POST \ No newline at end of file diff --git a/_examples/experimental-handlers/casbin/middleware/main.go b/_examples/experimental-handlers/casbin/middleware/main.go new file mode 100644 index 00000000..03639675 --- /dev/null +++ b/_examples/experimental-handlers/casbin/middleware/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "github.com/kataras/iris" + + "github.com/casbin/casbin" + cm "github.com/iris-contrib/middleware/casbin" +) + +// $ go get github.com/casbin/casbin +// $ go run main.go + +// Enforcer maps the model and the policy for the casbin service, we use this variable on the main_test too. +var Enforcer = casbin.NewEnforcer("casbinmodel.conf", "casbinpolicy.csv") + +func newApp() *iris.Application { + casbinMiddleware := cm.New(Enforcer) + + app := iris.New() + app.Use(casbinMiddleware.ServeHTTP) + + app.Get("/", hi) + + app.Get("/dataset1/{p:path}", hi) // p, alice, /dataset1/*, GET + + app.Post("/dataset1/resource1", hi) + + app.Get("/dataset2/resource2", hi) + app.Post("/dataset2/folder1/{p:path}", hi) + + app.Any("/dataset2/resource1", hi) + + return app +} + +func main() { + app := newApp() + app.Run(iris.Addr(":8080")) +} + +func hi(ctx iris.Context) { + ctx.Writef("Hello %s", cm.Username(ctx.Request())) +} diff --git a/_examples/experimental-handlers/casbin/middleware/main_test.go b/_examples/experimental-handlers/casbin/middleware/main_test.go new file mode 100644 index 00000000..cf94014a --- /dev/null +++ b/_examples/experimental-handlers/casbin/middleware/main_test.go @@ -0,0 +1,49 @@ +package main + +import ( + "testing" + + "github.com/iris-contrib/httpexpect" + "github.com/kataras/iris/httptest" +) + +func TestCasbinMiddleware(t *testing.T) { + app := newApp() + e := httptest.New(t, app, httptest.Debug(true)) + + type ttcasbin struct { + username string + path string + method string + status int + } + + tt := []ttcasbin{ + {"alice", "/dataset1/resource1", "GET", 200}, + {"alice", "/dataset1/resource1", "POST", 200}, + {"alice", "/dataset1/resource2", "GET", 200}, + {"alice", "/dataset1/resource2", "POST", 404}, + + {"bob", "/dataset2/resource1", "GET", 200}, + {"bob", "/dataset2/resource1", "POST", 200}, + {"bob", "/dataset2/resource1", "DELETE", 200}, + {"bob", "/dataset2/resource2", "GET", 200}, + {"bob", "/dataset2/resource2", "POST", 404}, + {"bob", "/dataset2/resource2", "DELETE", 404}, + + {"bob", "/dataset2/folder1/item1", "GET", 404}, + {"bob", "/dataset2/folder1/item1", "POST", 200}, + {"bob", "/dataset2/folder1/item1", "DELETE", 404}, + {"bob", "/dataset2/folder1/item2", "GET", 404}, + {"bob", "/dataset2/folder1/item2", "POST", 200}, + {"bob", "/dataset2/folder1/item2", "DELETE", 404}, + } + + for _, tt := range tt { + check(e, tt.method, tt.path, tt.username, tt.status) + } +} + +func check(e *httpexpect.Expect, method, path, username string, status int) { + e.Request(method, path).WithBasicAuth(username, "password").Expect().Status(status) +} diff --git a/_examples/experimental-handlers/casbin/wrapper/casbinmodel.conf b/_examples/experimental-handlers/casbin/wrapper/casbinmodel.conf new file mode 100644 index 00000000..d1b3dbd7 --- /dev/null +++ b/_examples/experimental-handlers/casbin/wrapper/casbinmodel.conf @@ -0,0 +1,14 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") \ No newline at end of file diff --git a/_examples/experimental-handlers/casbin/wrapper/casbinpolicy.csv b/_examples/experimental-handlers/casbin/wrapper/casbinpolicy.csv new file mode 100644 index 00000000..532b7b4a --- /dev/null +++ b/_examples/experimental-handlers/casbin/wrapper/casbinpolicy.csv @@ -0,0 +1,7 @@ +p, alice, /dataset1/*, GET +p, alice, /dataset1/resource1, POST +p, bob, /dataset2/resource1, * +p, bob, /dataset2/resource2, GET +p, bob, /dataset2/folder1/*, POST +p, dataset1_admin, /dataset1/*, * +g, cathrin, dataset1_admin \ No newline at end of file diff --git a/_examples/experimental-handlers/casbin/wrapper/main.go b/_examples/experimental-handlers/casbin/wrapper/main.go new file mode 100644 index 00000000..ece88ab4 --- /dev/null +++ b/_examples/experimental-handlers/casbin/wrapper/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "github.com/kataras/iris" + + "github.com/casbin/casbin" + cm "github.com/iris-contrib/middleware/casbin" +) + +// $ go get github.com/casbin/casbin +// $ go run main.go + +// Enforcer maps the model and the policy for the casbin service, we use this variable on the main_test too. +var Enforcer = casbin.NewEnforcer("casbinmodel.conf", "casbinpolicy.csv") + +func newApp() *iris.Application { + casbinMiddleware := cm.New(Enforcer) + + app := iris.New() + app.WrapRouter(casbinMiddleware.Wrapper()) + + app.Get("/", hi) + + app.Any("/dataset1/{p:path}", hi) // p, dataset1_admin, /dataset1/*, * && p, alice, /dataset1/*, GET + + app.Post("/dataset1/resource1", hi) + + app.Get("/dataset2/resource2", hi) + app.Post("/dataset2/folder1/{p:path}", hi) + + app.Any("/dataset2/resource1", hi) + + return app +} + +func main() { + app := newApp() + app.Run(iris.Addr(":8080")) +} + +func hi(ctx iris.Context) { + ctx.Writef("Hello %s", cm.Username(ctx.Request())) +} diff --git a/_examples/experimental-handlers/casbin/wrapper/main_test.go b/_examples/experimental-handlers/casbin/wrapper/main_test.go new file mode 100644 index 00000000..b107bfda --- /dev/null +++ b/_examples/experimental-handlers/casbin/wrapper/main_test.go @@ -0,0 +1,80 @@ +package main + +import ( + "testing" + + "github.com/iris-contrib/httpexpect" + "github.com/kataras/iris/httptest" +) + +func TestCasbinWrapper(t *testing.T) { + app := newApp() + e := httptest.New(t, app, httptest.Debug(true)) + + type ttcasbin struct { + username string + path string + method string + status int + } + + tt := []ttcasbin{ + {"alice", "/dataset1/resource1", "GET", 200}, + {"alice", "/dataset1/resource1", "POST", 200}, + {"alice", "/dataset1/resource2", "GET", 200}, + {"alice", "/dataset1/resource2", "POST", 403}, + + {"bob", "/dataset2/resource1", "GET", 200}, + {"bob", "/dataset2/resource1", "POST", 200}, + {"bob", "/dataset2/resource1", "DELETE", 200}, + {"bob", "/dataset2/resource2", "GET", 200}, + {"bob", "/dataset2/resource2", "POST", 403}, + {"bob", "/dataset2/resource2", "DELETE", 403}, + + {"bob", "/dataset2/folder1/item1", "GET", 403}, + {"bob", "/dataset2/folder1/item1", "POST", 200}, + {"bob", "/dataset2/folder1/item1", "DELETE", 403}, + {"bob", "/dataset2/folder1/item2", "GET", 403}, + {"bob", "/dataset2/folder1/item2", "POST", 200}, + {"bob", "/dataset2/folder1/item2", "DELETE", 403}, + } + + for _, tt := range tt { + check(e, tt.method, tt.path, tt.username, tt.status) + } + + println("ADMIN ROLES") + ttAdmin := []ttcasbin{ + {"cathrin", "/dataset1/item", "GET", 200}, + {"cathrin", "/dataset1/item", "POST", 200}, + {"cathrin", "/dataset1/item", "DELETE", 200}, + {"cathrin", "/dataset2/item", "GET", 403}, + {"cathrin", "/dataset2/item", "POST", 403}, + {"cathrin", "/dataset2/item", "DELETE", 403}, + } + + for _, tt := range ttAdmin { + check(e, tt.method, tt.path, tt.username, tt.status) + } + + println("ADMIN ROLE FOR cathrin DELETED") + Enforcer.DeleteRolesForUser("cathrin") + + ttAdminDeleted := []ttcasbin{ + {"cathrin", "/dataset1/item", "GET", 403}, + {"cathrin", "/dataset1/item", "POST", 403}, + {"cathrin", "/dataset1/item", "DELETE", 403}, + {"cathrin", "/dataset2/item", "GET", 403}, + {"cathrin", "/dataset2/item", "POST", 403}, + {"cathrin", "/dataset2/item", "DELETE", 403}, + } + + for _, tt := range ttAdminDeleted { + check(e, tt.method, tt.path, tt.username, tt.status) + } + +} + +func check(e *httpexpect.Expect, method, path, username string, status int) { + e.Request(method, path).WithBasicAuth(username, "password").Expect().Status(status) +} diff --git a/_examples/experimental-handlers/cloudwatch/simple/main.go b/_examples/experimental-handlers/cloudwatch/simple/main.go new file mode 100644 index 00000000..dbe440be --- /dev/null +++ b/_examples/experimental-handlers/cloudwatch/simple/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "time" + + "github.com/kataras/iris" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudwatch" + cw "github.com/iris-contrib/middleware/cloudwatch" +) + +// $ go get github.com/aws/aws-sdk-go/... +// $ go run main.go + +func main() { + app := iris.New() + app.Use(cw.New("us-east-1", "test").ServeHTTP) + + app.Get("/", func(ctx iris.Context) { + put := cw.GetPutFunc(ctx) + + put([]*cloudwatch.MetricDatum{ + { + MetricName: aws.String("MyMetric"), + Dimensions: []*cloudwatch.Dimension{ + { + Name: aws.String("ThingOne"), + Value: aws.String("something"), + }, + { + Name: aws.String("ThingTwo"), + Value: aws.String("other"), + }, + }, + Timestamp: aws.Time(time.Now()), + Unit: aws.String("Count"), + Value: aws.Float64(42), + }, + }) + + ctx.StatusCode(iris.StatusOK) + ctx.Text("success!\n") + }) + + // http://localhost:8080 + // should give: NoCredentialProviders + // which is correct, you have to authorize your aws, we asumme that you know how to. + app.Run(iris.Addr(":8080")) +} diff --git a/_examples/experimental-handlers/cors/simple/main.go b/_examples/experimental-handlers/cors/simple/main.go new file mode 100644 index 00000000..8f9cb1bf --- /dev/null +++ b/_examples/experimental-handlers/cors/simple/main.go @@ -0,0 +1,43 @@ +package main + +// $ go get github.com/rs/cors +// $ go run main.go + +import ( + "github.com/kataras/iris" + + "github.com/iris-contrib/middleware/cors" +) + +func main() { + + app := iris.New() + crs := cors.New(cors.Options{ + AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts. + AllowCredentials: true, + }) + + v1 := app.Party("/api/v1") + v1.Use(crs) + { + v1.Get("/home", func(ctx iris.Context) { + ctx.WriteString("Hello from /home") + }) + v1.Get("/about", func(ctx iris.Context) { + ctx.WriteString("Hello from /about") + }) + v1.Post("/send", func(ctx iris.Context) { + ctx.WriteString("sent") + }) + } + + // or use that to wrap the entire router + // even before the path and method matching + // this should work better and with all cors' features. + // Use that instead, if suits you. + // app.WrapRouter(cors.WrapNext(cors.Options{ + // AllowedOrigins: []string{"*"}, + // AllowCredentials: true, + // })) + app.Run(iris.Addr("localhost:8080")) +} diff --git a/_examples/experimental-handlers/jwt/main.go b/_examples/experimental-handlers/jwt/main.go new file mode 100644 index 00000000..41e5dfee --- /dev/null +++ b/_examples/experimental-handlers/jwt/main.go @@ -0,0 +1,46 @@ +// iris provides some basic middleware, most for your learning courve. +// You can use any net/http compatible middleware with iris.FromStd wrapper. +// +// JWT net/http video tutorial for golang newcomers: https://www.youtube.com/watch?v=dgJFeqeXVKw +// +// This middleware is the only one cloned from external source: https://github.com/auth0/go-jwt-middleware +// (because it used "context" to define the user but we don't need that so a simple iris.FromStd wouldn't work as expected.) +package main + +// $ go get -u github.com/dgrijalva/jwt-go +// $ go run main.go + +import ( + "github.com/kataras/iris" + + "github.com/dgrijalva/jwt-go" + jwtmiddleware "github.com/iris-contrib/middleware/jwt" +) + +func myHandler(ctx iris.Context) { + user := ctx.Values().Get("jwt").(*jwt.Token) + + ctx.Writef("This is an authenticated request\n") + ctx.Writef("Claim content:\n") + + ctx.Writef("%s", user.Signature) +} + +func main() { + app := iris.New() + + jwtHandler := jwtmiddleware.New(jwtmiddleware.Config{ + ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { + return []byte("My Secret"), nil + }, + // When set, the middleware verifies that tokens are signed with the specific signing algorithm + // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks + // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ + SigningMethod: jwt.SigningMethodHS256, + }) + + app.Use(jwtHandler.Serve) + + app.Get("/ping", myHandler) + app.Run(iris.Addr("localhost:3001")) +} // don't forget to look ../jwt_test.go to seee how to set your own custom claims diff --git a/_examples/experimental-handlers/newrelic/simple/main.go b/_examples/experimental-handlers/newrelic/simple/main.go new file mode 100644 index 00000000..a4e762a3 --- /dev/null +++ b/_examples/experimental-handlers/newrelic/simple/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/kataras/iris" + + "github.com/iris-contrib/middleware/newrelic" +) + +func main() { + app := iris.New() + config := newrelic.Config("APP_SERVER_NAME", "NEWRELIC_LICENSE_KEY") + config.Enabled = true + m, err := newrelic.New(config) + if err != nil { + app.Logger().Fatal(err) + } + app.Use(m.ServeHTTP) + + app.Get("/", func(ctx iris.Context) { + ctx.Writef("success!\n") + }) + + app.Run(iris.Addr(":8080")) +} diff --git a/_examples/experimental-handlers/prometheus/simple/main.go b/_examples/experimental-handlers/prometheus/simple/main.go new file mode 100644 index 00000000..ff624b14 --- /dev/null +++ b/_examples/experimental-handlers/prometheus/simple/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "math/rand" + "time" + + "github.com/kataras/iris" + + prometheusMiddleware "github.com/iris-contrib/middleware/prometheus" + + "github.com/prometheus/client_golang/prometheus" +) + +func main() { + app := iris.New() + m := prometheusMiddleware.New("serviceName", 300, 1200, 5000) + + app.Use(m.ServeHTTP) + + app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { + // error code handlers are not sharing the same middleware as other routes, so we have + // to call them inside their body. + m.ServeHTTP(ctx) + + ctx.Writef("Not Found") + }) + + app.Get("/", func(ctx iris.Context) { + sleep := rand.Intn(4999) + 1 + time.Sleep(time.Duration(sleep) * time.Millisecond) + ctx.Writef("Slept for %d milliseconds", sleep) + }) + + app.Get("/metrics", iris.FromStd(prometheus.Handler())) + + // http://localhost:8080/ + // http://localhost:8080/anotfound + // http://localhost:8080/metrics + app.Run(iris.Addr(":8080")) +} diff --git a/_examples/experimental-handlers/secure/simple/main.go b/_examples/experimental-handlers/secure/simple/main.go new file mode 100644 index 00000000..8f021e79 --- /dev/null +++ b/_examples/experimental-handlers/secure/simple/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "github.com/kataras/iris" + + "github.com/iris-contrib/middleware/secure" +) + +func main() { + s := secure.New(secure.Options{ + AllowedHosts: []string{"ssl.example.com"}, // AllowedHosts is a list of fully qualified domain names that are allowed. Default is empty list, which allows any and all host names. + SSLRedirect: true, // If SSLRedirect is set to true, then only allow HTTPS requests. Default is false. + SSLTemporaryRedirect: false, // If SSLTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301). + SSLHost: "ssl.example.com", // SSLHost is the host name that is used to redirect HTTP requests to HTTPS. Default is "", which indicates to use the same host. + SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"}, // SSLProxyHeaders is set of header keys with associated values that would indicate a valid HTTPS request. Useful when using Nginx: `map[string]string{"X-Forwarded-Proto": "https"}`. Default is blank map. + STSSeconds: 315360000, // STSSeconds is the max-age of the Strict-Transport-Security header. Default is 0, which would NOT include the header. + STSIncludeSubdomains: true, // If STSIncludeSubdomains is set to true, the `includeSubdomains` will be appended to the Strict-Transport-Security header. Default is false. + STSPreload: true, // If STSPreload is set to true, the `preload` flag will be appended to the Strict-Transport-Security header. Default is false. + ForceSTSHeader: false, // STS header is only included when the connection is HTTPS. If you want to force it to always be added, set to true. `IsDevelopment` still overrides this. Default is false. + FrameDeny: true, // If FrameDeny is set to true, adds the X-Frame-Options header with the value of `DENY`. Default is false. + CustomFrameOptionsValue: "SAMEORIGIN", // CustomFrameOptionsValue allows the X-Frame-Options header value to be set with a custom value. This overrides the FrameDeny option. + ContentTypeNosniff: true, // If ContentTypeNosniff is true, adds the X-Content-Type-Options header with the value `nosniff`. Default is false. + BrowserXSSFilter: true, // If BrowserXssFilter is true, adds the X-XSS-Protection header with the value `1; mode=block`. Default is false. + ContentSecurityPolicy: "default-src 'self'", // ContentSecurityPolicy allows the Content-Security-Policy header value to be set with a custom value. Default is "". + PublicKey: `pin-sha256="base64+primary=="; pin-sha256="base64+backup=="; max-age=5184000; includeSubdomains; report-uri="https://www.example.com/hpkp-report"`, // PublicKey implements HPKP to prevent MITM attacks with forged certificates. Default is "". + + IsDevelopment: true, // This will cause the AllowedHosts, SSLRedirect, and STSSeconds/STSIncludeSubdomains options to be ignored during development. When deploying to production, be sure to set this to false. + }) + + app := iris.New() + app.Use(s.Serve) + + app.Get("/home", func(ctx iris.Context) { + ctx.Writef("Hello from /home") + }) + + app.Run(iris.Addr(":8080")) +} diff --git a/_examples/experimental-handlers/tollboothic/limit-handler/main.go b/_examples/experimental-handlers/tollboothic/limit-handler/main.go new file mode 100644 index 00000000..a7a255b4 --- /dev/null +++ b/_examples/experimental-handlers/tollboothic/limit-handler/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "github.com/kataras/iris" + + "github.com/didip/tollbooth" + "github.com/iris-contrib/middleware/tollboothic" +) + +// $ go get github.com/didip/tollbooth +// $ go run main.go + +func main() { + app := iris.New() + + limiter := tollbooth.NewLimiter(1, nil) + // + // or create a limiter with expirable token buckets + // This setting means: + // create a 1 request/second limiter and + // every token bucket in it will expire 1 hour after it was initially set. + // limiter := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour}) + + app.Get("/", tollboothic.LimitHandler(limiter), func(ctx iris.Context) { + ctx.HTML("Hello, world!") + }) + + app.Run(iris.Addr(":8080")) +} + +// Read more at: https://github.com/didip/tollbooth diff --git a/_examples/http_responsewriter/quicktemplate/templates/base.qtpl.go b/_examples/http_responsewriter/quicktemplate/templates/base.qtpl.go deleted file mode 100644 index 32a5e638..00000000 --- a/_examples/http_responsewriter/quicktemplate/templates/base.qtpl.go +++ /dev/null @@ -1,128 +0,0 @@ -// This file is automatically generated by qtc from "base.qtpl". -// See https://github.com/valyala/quicktemplate for details. - -// This is our templates' base implementation. -// - -//line base.qtpl:3 -package templates - -//line base.qtpl:3 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line base.qtpl:3 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line base.qtpl:4 -type Partial interface { - //line base.qtpl:4 - Body() string - //line base.qtpl:4 - StreamBody(qw422016 *qt422016.Writer) - //line base.qtpl:4 - WriteBody(qq422016 qtio422016.Writer) -//line base.qtpl:4 -} - -// Template writes a template implementing the Partial interface. - -//line base.qtpl:11 -func StreamTemplate(qw422016 *qt422016.Writer, p Partial) { - //line base.qtpl:11 - qw422016.N().S(` - - - Quicktemplate integration with Iris - - -
- Header contents here... -
- -
- `) - //line base.qtpl:22 - p.StreamBody(qw422016) - //line base.qtpl:22 - qw422016.N().S(` -
- - - - -`) -//line base.qtpl:30 -} - -//line base.qtpl:30 -func WriteTemplate(qq422016 qtio422016.Writer, p Partial) { - //line base.qtpl:30 - qw422016 := qt422016.AcquireWriter(qq422016) - //line base.qtpl:30 - StreamTemplate(qw422016, p) - //line base.qtpl:30 - qt422016.ReleaseWriter(qw422016) -//line base.qtpl:30 -} - -//line base.qtpl:30 -func Template(p Partial) string { - //line base.qtpl:30 - qb422016 := qt422016.AcquireByteBuffer() - //line base.qtpl:30 - WriteTemplate(qb422016, p) - //line base.qtpl:30 - qs422016 := string(qb422016.B) - //line base.qtpl:30 - qt422016.ReleaseByteBuffer(qb422016) - //line base.qtpl:30 - return qs422016 -//line base.qtpl:30 -} - -// Base template implementation. Other pages may inherit from it if they need -// overriding only certain Partial methods. - -//line base.qtpl:35 -type Base struct{} - -//line base.qtpl:36 -func (b *Base) StreamBody(qw422016 *qt422016.Writer) { -//line base.qtpl:36 -qw422016.N().S(`This is the base body`) } - -//line base.qtpl:36 -//line base.qtpl:36 -func (b *Base) WriteBody(qq422016 qtio422016.Writer) { - //line base.qtpl:36 - qw422016 := qt422016.AcquireWriter(qq422016) - //line base.qtpl:36 - b.StreamBody(qw422016) - //line base.qtpl:36 - qt422016.ReleaseWriter(qw422016) -//line base.qtpl:36 -} - -//line base.qtpl:36 -func (b *Base) Body() string { - //line base.qtpl:36 - qb422016 := qt422016.AcquireByteBuffer() - //line base.qtpl:36 - b.WriteBody(qb422016) - //line base.qtpl:36 - qs422016 := string(qb422016.B) - //line base.qtpl:36 - qt422016.ReleaseByteBuffer(qb422016) - //line base.qtpl:36 - return qs422016 -//line base.qtpl:36 -} diff --git a/_examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go b/_examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go deleted file mode 100644 index 5b812bfb..00000000 --- a/_examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go +++ /dev/null @@ -1,72 +0,0 @@ -// This file is automatically generated by qtc from "hello.qtpl". -// See https://github.com/valyala/quicktemplate for details. - -// Hello template, implements the Partial's methods. -// - -//line hello.qtpl:3 -package templates - -//line hello.qtpl:3 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line hello.qtpl:3 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line hello.qtpl:4 -type Hello struct { - Vars map[string]interface{} -} - -//line hello.qtpl:9 -func (h *Hello) StreamBody(qw422016 *qt422016.Writer) { - //line hello.qtpl:9 - qw422016.N().S(` -

`) - //line hello.qtpl:10 - qw422016.E().V(h.Vars["message"]) - //line hello.qtpl:10 - qw422016.N().S(`

-
- Hello `) - //line hello.qtpl:12 - qw422016.E().V(h.Vars["name"]) - //line hello.qtpl:12 - qw422016.N().S(`! -
-`) -//line hello.qtpl:14 -} - -//line hello.qtpl:14 -func (h *Hello) WriteBody(qq422016 qtio422016.Writer) { - //line hello.qtpl:14 - qw422016 := qt422016.AcquireWriter(qq422016) - //line hello.qtpl:14 - h.StreamBody(qw422016) - //line hello.qtpl:14 - qt422016.ReleaseWriter(qw422016) -//line hello.qtpl:14 -} - -//line hello.qtpl:14 -func (h *Hello) Body() string { - //line hello.qtpl:14 - qb422016 := qt422016.AcquireByteBuffer() - //line hello.qtpl:14 - h.WriteBody(qb422016) - //line hello.qtpl:14 - qs422016 := string(qb422016.B) - //line hello.qtpl:14 - qt422016.ReleaseByteBuffer(qb422016) - //line hello.qtpl:14 - return qs422016 -//line hello.qtpl:14 -} diff --git a/_examples/http_responsewriter/quicktemplate/templates/index.qtpl.go b/_examples/http_responsewriter/quicktemplate/templates/index.qtpl.go deleted file mode 100644 index e5297ac4..00000000 --- a/_examples/http_responsewriter/quicktemplate/templates/index.qtpl.go +++ /dev/null @@ -1,62 +0,0 @@ -// This file is automatically generated by qtc from "index.qtpl". -// See https://github.com/valyala/quicktemplate for details. - -// Index template, implements the Partial's methods. -// - -//line index.qtpl:3 -package templates - -//line index.qtpl:3 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line index.qtpl:3 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line index.qtpl:4 -type Index struct{} - -//line index.qtpl:7 -func (i *Index) StreamBody(qw422016 *qt422016.Writer) { - //line index.qtpl:7 - qw422016.N().S(` -

Index Page

-
- This is our index page's body. -
-`) -//line index.qtpl:12 -} - -//line index.qtpl:12 -func (i *Index) WriteBody(qq422016 qtio422016.Writer) { - //line index.qtpl:12 - qw422016 := qt422016.AcquireWriter(qq422016) - //line index.qtpl:12 - i.StreamBody(qw422016) - //line index.qtpl:12 - qt422016.ReleaseWriter(qw422016) -//line index.qtpl:12 -} - -//line index.qtpl:12 -func (i *Index) Body() string { - //line index.qtpl:12 - qb422016 := qt422016.AcquireByteBuffer() - //line index.qtpl:12 - i.WriteBody(qb422016) - //line index.qtpl:12 - qs422016 := string(qb422016.B) - //line index.qtpl:12 - qt422016.ReleaseByteBuffer(qb422016) - //line index.qtpl:12 - return qs422016 -//line index.qtpl:12 -} diff --git a/_examples/tutorial/dropzonejs/README.md b/_examples/tutorial/dropzonejs/README.md index cf490726..9c8bbab6 100644 --- a/_examples/tutorial/dropzonejs/README.md +++ b/_examples/tutorial/dropzonejs/README.md @@ -1,7 +1,7 @@ # Articles -- [How to build a file upload form using DropzoneJS and Go](https://dev.to/kataras/dropzonejs--go-series---part-1-474) -- [How to display existing files on server using DropzoneJS and Go](https://dev.to/kataras/dropzonejs--go-series---part-2-4n1) +* [How to build a file upload form using DropzoneJS and Go](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) +* [How to display existing files on server using DropzoneJS and Go](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) # Content diff --git a/_examples/tutorial/dropzonejs/README_PART2.md b/_examples/tutorial/dropzonejs/README_PART2.md index 052686f4..331e0f19 100644 --- a/_examples/tutorial/dropzonejs/README_PART2.md +++ b/_examples/tutorial/dropzonejs/README_PART2.md @@ -1,7 +1,7 @@ # Articles -- [How to build a file upload form using DropzoneJS and Go](https://dev.to/kataras/dropzonejs--go-series---part-1-474) -- [How to display existing files on server using DropzoneJS and Go](https://dev.to/kataras/dropzonejs--go-series---part-2-4n1) +* [How to build a file upload form using DropzoneJS and Go](https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991) +* [How to display existing files on server using DropzoneJS and Go](https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19) # Content diff --git a/_examples/tutorial/dropzonejs/meta.yml b/_examples/tutorial/dropzonejs/meta.yml new file mode 100644 index 00000000..f0815494 --- /dev/null +++ b/_examples/tutorial/dropzonejs/meta.yml @@ -0,0 +1,8 @@ +Name: DropzoneJS +Articles: + - Title: How to build a file upload form using DropzoneJS and Go + Source: https://hackernoon.com/how-to-build-a-file-upload-form-using-dropzonejs-and-go-8fb9f258a991 + Author: https://twitter.com/@kataras + - Title: How to display existing files on server using DropzoneJS and Go + Source: https://hackernoon.com/how-to-display-existing-files-on-server-using-dropzonejs-and-go-53e24b57ba19 + Author: https://twitter.com/@kataras \ No newline at end of file diff --git a/_examples/view/embedding-templates-into-app/embedding-templates-into-app.exe.REMOVED.git-id b/_examples/view/embedding-templates-into-app/embedding-templates-into-app.exe.REMOVED.git-id deleted file mode 100644 index 0298edc2..00000000 --- a/_examples/view/embedding-templates-into-app/embedding-templates-into-app.exe.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -3c9dbd9acb1d553cc63940c72f212a880e8a8073 \ No newline at end of file diff --git a/core/maintenance/version.go b/core/maintenance/version.go index f62d29a6..01faf308 100644 --- a/core/maintenance/version.go +++ b/core/maintenance/version.go @@ -13,7 +13,7 @@ import ( const ( // Version is the string representation of the current local Iris Web Framework version. - Version = "8.5.5" + Version = "8.5.6" ) // CheckForUpdates checks for any available updates diff --git a/core/router/api_builder.go b/core/router/api_builder.go index 04ab60a6..5858df2d 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -599,15 +599,9 @@ func (api *APIBuilder) StaticHandler(systemPath string, showList bool, gzip bool return StaticHandler(systemPath, showList, gzip) } -// StaticServe serves a directory as web resource -// it's the simpliest form of the Static* functions -// Almost same usage as StaticWeb -// accepts only one required parameter which is the systemPath, -// the same path will be used to register the GET and HEAD method routes. -// If second parameter is empty, otherwise the requestPath is the second parameter -// it uses gzip compression (compression on each request, no file cache). -// -// Returns the GET *Route. +// StaticServe serves a directory as web resource. +// Same as `StaticWeb`. +// DEPRECATED; use `StaticWeb` or `StaticHandler` (for more options) instead. func (api *APIBuilder) StaticServe(systemPath string, requestPath ...string) *Route { var reqPath string @@ -619,22 +613,7 @@ func (api *APIBuilder) StaticServe(systemPath string, requestPath ...string) *Ro reqPath = requestPath[0] } - return api.Get(joinPath(reqPath, WildcardParam("file")), func(ctx context.Context) { - filepath := ctx.Params().Get("file") - - spath := strings.Replace(filepath, "/", string(os.PathSeparator), -1) - spath = path.Join(systemPath, spath) - - if !DirectoryExists(spath) { - ctx.NotFound() - return - } - - if err := ctx.ServeFile(spath, true); err != nil { - ctx.Application().Logger().Warnf("while trying to serve static file: '%v' on IP: '%s'", err, ctx.RemoteAddr()) - ctx.StatusCode(http.StatusInternalServerError) - } - }) + return api.StaticWeb(reqPath, systemPath) } // StaticContent registers a GET and HEAD method routes to the requestPath diff --git a/doc.go b/doc.go index e6023f5f..799d8373 100644 --- a/doc.go +++ b/doc.go @@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub: Current Version -8.5.5 +8.5.6 Installation