diff --git a/_examples/README.md b/_examples/README.md index 8d3d9fb7..ea8c8a7d 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -253,6 +253,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her ### ORM - [Using xorm(Mysql, MyMysql, Postgres, Tidb, **SQLite**, MsSql, MsSql, Oracle)](orm/xorm/main.go) +- [Using gorm](orm/gorm/main.go) ### Miscellaneous 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..fd2e9d36 --- /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/v2" + cm "github.com/iris-contrib/middleware/casbin" +) + +// $ go get github.com/casbin/casbin/v2 +// $ 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..d806af1c --- /dev/null +++ b/_examples/experimental-handlers/casbin/middleware/main_test.go @@ -0,0 +1,48 @@ +package main + +import ( + "testing" + + "github.com/kataras/iris/httptest" +) + +func TestCasbinMiddleware(t *testing.T) { + app := newApp() + e := httptest.New(t, app, httptest.Debug(false)) + + 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 *httptest.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..e544cf3c --- /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/v2" + 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..48a4a0b7 --- /dev/null +++ b/_examples/experimental-handlers/casbin/wrapper/main_test.go @@ -0,0 +1,79 @@ +package main + +import ( + "testing" + + "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 *httptest.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/client/main.go b/_examples/experimental-handlers/cors/simple/client/main.go new file mode 100644 index 00000000..9163f29a --- /dev/null +++ b/_examples/experimental-handlers/cors/simple/client/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "github.com/kataras/iris" +) + +// NOTE: THIS IS OPTIONALLY. +// It is just an example of communication between cors/simple/main.go and your app +// based on issues that beginners had with it. +// You should use your own favourite library for HTTP requests (any programming language ofc). +// +// Replace the '8fc93b1c.ngrok.io' with a domain which +// exposes the cors/simple/main.go server side. +const url = "http://8fc93b1c.ngrok.io/api/v1/mailer" + +var clientSide = []byte(``) + +func main() { + app := iris.New() + app.Get("/", func(ctx iris.Context) { + ctx.Write(clientSide) + }) + + // Start and navigate to http://localhost:8080 + // and go to the previous terminal of your running cors/simple/main.go server + // and see the logs. + 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..5003329b --- /dev/null +++ b/_examples/experimental-handlers/cors/simple/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "github.com/kataras/iris" +) + +func main() { + app := iris.New() + + crs := func(ctx iris.Context) { + ctx.Header("Access-Control-Allow-Origin", "*") + ctx.Header("Access-Control-Allow-Credentials", "true") + ctx.Header("Access-Control-Allow-Headers", "Access-Control-Allow-Origin,Content-Type") + ctx.Next() + } // or "github.com/iris-contrib/middleware/cors" + + v1 := app.Party("/api/v1", crs).AllowMethods(iris.MethodOptions) // <- important for the preflight. + { + v1.Post("/mailer", func(ctx iris.Context) { + var any iris.Map + err := ctx.ReadJSON(&any) + if err != nil { + ctx.WriteString(err.Error()) + ctx.StatusCode(iris.StatusBadRequest) + return + } + ctx.Application().Logger().Infof("received %#+v", any) + }) + + 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") + }) + v1.Put("/send", func(ctx iris.Context) { + ctx.WriteString("updated") + }) + v1.Delete("/send", func(ctx iris.Context) { + ctx.WriteString("deleted") + }) + } + + // iris.WithoutPathCorrectionRedirection | iris#Configuration.DisablePathCorrectionRedirection: + // CORS needs the allow origin headers in the redirect response as well, we have a solution for this: + // If you use iris >= v11.0.4 then add the `app.Run(..., iris.WithoutPathCorrectionRedirection)` + // on the server side if you wish + // to directly fire the handler instead of redirection (which is the default behavior) + // on request paths like "/v1/mailer/" when "/v1/mailer" route handler is registered. + app.Run(iris.Addr(":80"), iris.WithoutPathCorrectionRedirection) +} diff --git a/_examples/experimental-handlers/csrf/main.go b/_examples/experimental-handlers/csrf/main.go new file mode 100644 index 00000000..20964ac0 --- /dev/null +++ b/_examples/experimental-handlers/csrf/main.go @@ -0,0 +1,55 @@ +// This middleware provides Cross-Site Request Forgery +// protection. +// +// It securely generates a masked (unique-per-request) token that +// can be embedded in the HTTP response (e.g. form field or HTTP header). +// The original (unmasked) token is stored in the session, which is inaccessible +// by an attacker (provided you are using HTTPS). Subsequent requests are +// expected to include this token, which is compared against the session token. +// Requests that do not provide a matching token are served with a HTTP 403 +// 'Forbidden' error response. +package main + +// $ go get -u github.com/iris-contrib/middleware/... + +import ( + "github.com/kataras/iris" + + "github.com/iris-contrib/middleware/csrf" +) + +func main() { + app := iris.New() + app.RegisterView(iris.HTML("./views", ".html")) + // Note that the authentication key provided should be 32 bytes + // long and persist across application restarts. + protect := csrf.Protect([]byte("9AB0F421E53A477C084477AEA06096F5"), + csrf.Secure(false)) // Defaults to true, but pass `false` while no https (devmode). + + users := app.Party("/user", protect) + { + users.Get("/signup", getSignupForm) + // // POST requests without a valid token will return a HTTP 403 Forbidden. + users.Post("/signup", postSignupForm) + } + + // GET: http://localhost:8080/user/signup + // POST: http://localhost:8080/user/signup + app.Run(iris.Addr(":8080")) +} + +func getSignupForm(ctx iris.Context) { + // views/user/signup.html just needs a {{ .csrfField }} template tag for + // csrf.TemplateField to inject the CSRF token into. Easy! + ctx.ViewData(csrf.TemplateTag, csrf.TemplateField(ctx)) + ctx.View("user/signup.html") + + // We could also retrieve the token directly from csrf.Token(ctx) and + // set it in the request header - ctx.GetHeader("X-CSRF-Token", token) + // This is useful if you're sending JSON to clients or a front-end JavaScript + // framework. +} + +func postSignupForm(ctx iris.Context) { + ctx.Writef("You're welcome mate!") +} diff --git a/_examples/experimental-handlers/csrf/views/user/signup.html b/_examples/experimental-handlers/csrf/views/user/signup.html new file mode 100644 index 00000000..eea693d6 --- /dev/null +++ b/_examples/experimental-handlers/csrf/views/user/signup.html @@ -0,0 +1,4 @@ +
diff --git a/_examples/experimental-handlers/jwt/main.go b/_examples/experimental-handlers/jwt/main.go new file mode 100644 index 00000000..c0109268 --- /dev/null +++ b/_examples/experimental-handlers/jwt/main.go @@ -0,0 +1,46 @@ +// iris provides some basic middleware, most for your learning curve. +// 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 see 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..33758819 --- /dev/null +++ b/_examples/experimental-handlers/prometheus/simple/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "math/rand" + "time" + + "github.com/kataras/iris" + + prometheusMiddleware "github.com/iris-contrib/middleware/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func main() { + app := iris.New() + m := prometheusMiddleware.New("serviceName", 0.3, 1.2, 5.0) + + 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(promhttp.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/httptest/httptest_go19.go b/httptest/httptest_go19.go index 0bcd5ad3..6be2b47b 100644 --- a/httptest/httptest_go19.go +++ b/httptest/httptest_go19.go @@ -4,5 +4,9 @@ package httptest import "github.com/gavv/httpexpect" -// Request type alias. -type Request = httpexpect.Request +type ( + // Request type alias. + Request = httpexpect.Request + // Expect type alias. + Expect = httpexpect.Expect +)