mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
Update to version 8.5.6 | Read HISTORY.md
Former-commit-id: 3c1fb7ad47d54133f68ee0ee8ebe4c3835fe4ce0
This commit is contained in:
parent
ef41e07d4e
commit
af9a1f1241
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
.vscode
|
||||
.vscode
|
||||
_authortools
|
12
HISTORY.md
12
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,
|
||||
|
|
|
@ -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
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
8.5.5:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855
|
||||
8.5.6:https://github.com/kataras/iris/blob/master/HISTORY.md#su-05-november-2017--v856
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
5
_examples/experimental-handlers/README.md
Normal file
5
_examples/experimental-handlers/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Install iris-contrib/middleware
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/iris-contrib/middleware/...
|
||||
```
|
|
@ -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 == "*")
|
|
@ -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
|
|
43
_examples/experimental-handlers/casbin/middleware/main.go
Normal file
43
_examples/experimental-handlers/casbin/middleware/main.go
Normal file
|
@ -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()))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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 == "*")
|
|
@ -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
|
|
43
_examples/experimental-handlers/casbin/wrapper/main.go
Normal file
43
_examples/experimental-handlers/casbin/wrapper/main.go
Normal file
|
@ -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()))
|
||||
}
|
80
_examples/experimental-handlers/casbin/wrapper/main_test.go
Normal file
80
_examples/experimental-handlers/casbin/wrapper/main_test.go
Normal file
|
@ -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)
|
||||
}
|
50
_examples/experimental-handlers/cloudwatch/simple/main.go
Normal file
50
_examples/experimental-handlers/cloudwatch/simple/main.go
Normal file
|
@ -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"))
|
||||
}
|
43
_examples/experimental-handlers/cors/simple/main.go
Normal file
43
_examples/experimental-handlers/cors/simple/main.go
Normal file
|
@ -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"))
|
||||
}
|
46
_examples/experimental-handlers/jwt/main.go
Normal file
46
_examples/experimental-handlers/jwt/main.go
Normal file
|
@ -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
|
24
_examples/experimental-handlers/newrelic/simple/main.go
Normal file
24
_examples/experimental-handlers/newrelic/simple/main.go
Normal file
|
@ -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"))
|
||||
}
|
40
_examples/experimental-handlers/prometheus/simple/main.go
Normal file
40
_examples/experimental-handlers/prometheus/simple/main.go
Normal file
|
@ -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"))
|
||||
}
|
38
_examples/experimental-handlers/secure/simple/main.go
Normal file
38
_examples/experimental-handlers/secure/simple/main.go
Normal file
|
@ -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"))
|
||||
}
|
|
@ -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("<b>Hello, world!</b>")
|
||||
})
|
||||
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
// Read more at: https://github.com/didip/tollbooth
|
|
@ -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(`
|
||||
<html>
|
||||
<head>
|
||||
<title>Quicktemplate integration with Iris</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Header contents here...
|
||||
</div>
|
||||
|
||||
<div style="margin:10px;">
|
||||
`)
|
||||
//line base.qtpl:22
|
||||
p.StreamBody(qw422016)
|
||||
//line base.qtpl:22
|
||||
qw422016.N().S(`
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<footer>
|
||||
Footer contents here...
|
||||
</footer>
|
||||
</html>
|
||||
`)
|
||||
//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
|
||||
}
|
|
@ -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(`
|
||||
<h1>`)
|
||||
//line hello.qtpl:10
|
||||
qw422016.E().V(h.Vars["message"])
|
||||
//line hello.qtpl:10
|
||||
qw422016.N().S(`</h1>
|
||||
<div>
|
||||
Hello <b>`)
|
||||
//line hello.qtpl:12
|
||||
qw422016.E().V(h.Vars["name"])
|
||||
//line hello.qtpl:12
|
||||
qw422016.N().S(`!</b>
|
||||
</div>
|
||||
`)
|
||||
//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
|
||||
}
|
|
@ -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(`
|
||||
<h1>Index Page</h1>
|
||||
<div>
|
||||
This is our index page's body.
|
||||
</div>
|
||||
`)
|
||||
//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
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
8
_examples/tutorial/dropzonejs/meta.yml
Normal file
8
_examples/tutorial/dropzonejs/meta.yml
Normal file
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
3c9dbd9acb1d553cc63940c72f212a880e8a8073
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user