From ef41e07d4e02361be19c1778678e23f5d53b9fb0 Mon Sep 17 00:00:00 2001 From: kataras Date: Sat, 4 Nov 2017 02:59:21 +0200 Subject: [PATCH] Add a better example for the recaptcha middleware as requested at: https://github.com/kataras/iris/issues/799 Former-commit-id: 85c3286a9d6be5cf47631e7608f70f3790934e64 --- .../recaptcha/custom_form/main.go | 44 +++++++++++++++++ _examples/miscellaneous/recaptcha/main.go | 48 +++++++++---------- _examples/routing/main.go | 1 + context/context.go | 3 +- context/handler.go | 14 ++++++ core/maintenance/client/client.go | 2 +- core/maintenance/version.go | 38 +++++++-------- core/router/api_builder.go | 9 +++- core/router/handler.go | 3 ++ core/router/route.go | 45 +++++++++++++---- iris.go | 5 +- 11 files changed, 153 insertions(+), 59 deletions(-) create mode 100644 _examples/miscellaneous/recaptcha/custom_form/main.go diff --git a/_examples/miscellaneous/recaptcha/custom_form/main.go b/_examples/miscellaneous/recaptcha/custom_form/main.go new file mode 100644 index 00000000..e5215261 --- /dev/null +++ b/_examples/miscellaneous/recaptcha/custom_form/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + + "github.com/kataras/iris" + + "github.com/kataras/iris/middleware/recaptcha" +) + +// keys should be obtained by https://www.google.com/recaptcha +const ( + recaptchaPublic = "6Lf3WywUAAAAAKNfAm5DP2J5ahqedtZdHTYaKkJ6" + recaptchaSecret = "6Lf3WywUAAAAAJpArb8nW_LCL_PuPuokmEABFfgw" +) + +func main() { + app := iris.New() + + r := recaptcha.New(recaptchaSecret) + + app.Get("/comment", showRecaptchaForm) + + // pass the middleware before the main handler or use the `recaptcha.SiteVerify`. + app.Post("/comment", r, postComment) + + app.Run(iris.Addr(":8080")) +} + +var htmlForm = `
+ +
+ +
` + +func showRecaptchaForm(ctx iris.Context) { + contents := fmt.Sprintf(htmlForm, recaptchaPublic) + ctx.HTML(contents) +} + +func postComment(ctx iris.Context) { + // [...] + ctx.JSON(iris.Map{"success": true}) +} diff --git a/_examples/miscellaneous/recaptcha/main.go b/_examples/miscellaneous/recaptcha/main.go index e4b8c97f..3ecd161a 100644 --- a/_examples/miscellaneous/recaptcha/main.go +++ b/_examples/miscellaneous/recaptcha/main.go @@ -1,44 +1,40 @@ package main import ( - "fmt" - "github.com/kataras/iris" - "github.com/kataras/iris/middleware/recaptcha" ) -// publicDataSiteKey and secretKey and should be obtained by https://www.google.com/recaptcha. +// keys should be obtained by https://www.google.com/recaptcha const ( - publicDataSiteKey = "" - secretKey = "" + recaptchaPublic = "" + recaptchaSecret = "" ) +func showRecaptchaForm(ctx iris.Context, path string) { + ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, path)) +} + func main() { app := iris.New() - r := recaptcha.New(secretKey) + // On both Get and Post on this example, so you can easly + // use a single route to show a form and the main subject if recaptcha's validation result succeed. + app.HandleMany("GET POST", "/", func(ctx iris.Context) { + if ctx.Method() == iris.MethodGet { + showRecaptchaForm(ctx, "/") + return + } - app.Get("/comment", showRecaptchaForm) + result := recaptcha.SiteFerify(ctx, recaptchaSecret) + if !result.Success { + /* redirect here if u want or do nothing */ + ctx.HTML(" failed please try again ") + return + } - // pass the middleware before the main handler or use the `recaptcha.SiteVerify`. - app.Post("/comment", r, postComment) + ctx.Writef("succeed.") + }) app.Run(iris.Addr(":8080")) } - -var htmlForm = `
- -
- -
` - -func showRecaptchaForm(ctx iris.Context) { - contents := fmt.Sprintf(htmlForm, publicDataSiteKey) - ctx.HTML(contents) -} - -func postComment(ctx iris.Context) { - // [...] - ctx.JSON(iris.Map{"success": true}) -} diff --git a/_examples/routing/main.go b/_examples/routing/main.go index 738b1ca3..5d4ddc50 100644 --- a/_examples/routing/main.go +++ b/_examples/routing/main.go @@ -141,6 +141,7 @@ func h(ctx iris.Context) { func main() { app := newApp() + app.Logger().SetLevel("debug") /* // GET diff --git a/context/context.go b/context/context.go index fdda0c06..ee336936 100644 --- a/context/context.go +++ b/context/context.go @@ -17,7 +17,6 @@ import ( "path/filepath" "reflect" "regexp" - "runtime" "strconv" "strings" "time" @@ -1056,7 +1055,7 @@ func (ctx *context) Proceed(h Handler) bool { // HandlerName returns the current handler's name, helpful for debugging. func (ctx *context) HandlerName() string { - return runtime.FuncForPC(reflect.ValueOf(ctx.handlers[ctx.currentHandlerIndex]).Pointer()).Name() + return HandlerName(ctx.handlers[ctx.currentHandlerIndex]) } // Do sets the handler index to zero, executes the first handler diff --git a/context/handler.go b/context/handler.go index d86431b0..6d980513 100644 --- a/context/handler.go +++ b/context/handler.go @@ -1,5 +1,10 @@ package context +import ( + "reflect" + "runtime" +) + // A Handler responds to an HTTP request. // It writes reply headers and data to the Context.ResponseWriter() and then return. // Returning signals that the request is finished; @@ -20,3 +25,12 @@ type Handler func(Context) // // See `Handler` for more. type Handlers []Handler + +// HandlerName returns the name, the handler function informations. +// Same as `context.HandlerName`. +func HandlerName(h Handler) string { + pc := reflect.ValueOf(h).Pointer() + // l, n := runtime.FuncForPC(pc).FileLine(pc) + // return fmt.Sprintf("%s:%d", l, n) + return runtime.FuncForPC(pc).Name() +} diff --git a/core/maintenance/client/client.go b/core/maintenance/client/client.go index cac65fa6..d10431ef 100644 --- a/core/maintenance/client/client.go +++ b/core/maintenance/client/client.go @@ -10,7 +10,7 @@ import ( "github.com/kataras/iris/core/netutil" ) -const host = "http://live.iris-go.com" +const host = "https://live.iris-go.com" // PostForm performs the PostForm with a secure client. func PostForm(p string, data url.Values) (*http.Response, error) { diff --git a/core/maintenance/version.go b/core/maintenance/version.go index 643560bf..f62d29a6 100644 --- a/core/maintenance/version.go +++ b/core/maintenance/version.go @@ -23,15 +23,17 @@ func CheckForUpdates() { updateAvailale := v.Compare(Version) == version.Smaller if updateAvailale { - has, ft := hasInternetConnection() - canUpdate := (has && ft && ask()) || !has || !ft - if canUpdate { - installVersion(v) + if confirmUpdate(v) { + has, ft := hasInternetConnection() + canUpdate := (has && ft && ask()) || !has || !ft + if canUpdate { + installVersion() + } } } } -func installVersion(v version.Version) { +func confirmUpdate(v version.Version) bool { // on help? when asking for installing the new update // and when answering "No". ignoreUpdatesMsg := "Would you like to ignore future updates? Disable the version checker via:\napp.Run(..., iris.WithoutVersionChecker)" @@ -47,25 +49,23 @@ func installVersion(v version.Version) { Message: shouldUpdateNowMsg, Help: ignoreUpdatesMsg, }, &confirmUpdate, nil) + return confirmUpdate // it's true only when update was available and user typed "yes". +} - // run the updater last, so the user can star the repo and at the same time - // the app will update her/his local iris. - if confirmUpdate { // it's true only when update was available and user typed "yes". - repo := "github.com/kataras/iris/..." - cmd := exec.Command("go", "get", "-u", "-v", repo) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stdout +func installVersion() { + golog.Infof("Downloading...\n") + repo := "github.com/kataras/iris/..." + cmd := exec.Command("go", "get", "-u", "-v", repo) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stdout - if err := cmd.Run(); err != nil { - golog.Warnf("unexpected message while trying to go get,\nif you edited the original source code then you've to remove the whole $GOPATH/src/github.com/kataras folder and execute `go get -u github.com/kataras/iris/...` manually\n%v", err) - return - } - - golog.Infof("Update process finished.\nManual rebuild and restart is required to apply the changes...\n") + if err := cmd.Run(); err != nil { + golog.Warnf("unexpected message while trying to go get,\nif you edited the original source code then you've to remove the whole $GOPATH/src/github.com/kataras folder and execute `go get -u github.com/kataras/iris/...` manually\n%v", err) return } - // if update was available but chosen not to update then just continue... + golog.Infof("Update process finished.\nManual rebuild and restart is required to apply the changes...\n") + return } /* Author's note: diff --git a/core/router/api_builder.go b/core/router/api_builder.go index 921f70fa..04ab60a6 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -146,6 +146,13 @@ func (api *APIBuilder) Handle(method string, relativePath string, handlers ...co } fullpath := api.relativePath + relativePath // for now, keep the last "/" if any, "/xyz/" + if len(handlers) == 0 { + api.reporter.Add("missing handlers for route %s: %s", method, fullpath) + return nil + } + + // before join the middleware + handlers + done handlers. + possibleMainHandlerName := context.HandlerName(handlers[0]) // global begin handlers -> middleware that are registered before route registration // -> handlers that are passed to this Handle function. @@ -158,7 +165,7 @@ func (api *APIBuilder) Handle(method string, relativePath string, handlers ...co // here we separate the subdomain and relative path subdomain, path := splitSubdomainAndPath(fullpath) - r, err := NewRoute(method, subdomain, path, routeHandlers, api.macros) + r, err := NewRoute(method, subdomain, path, possibleMainHandlerName, routeHandlers, api.macros) if err != nil { // template path parser errors: api.reporter.Add("%v -> %s:%s:%s", err, method, subdomain, path) return nil diff --git a/core/router/handler.go b/core/router/handler.go index 89060681..0114f9da 100644 --- a/core/router/handler.go +++ b/core/router/handler.go @@ -1,6 +1,7 @@ package router import ( + "github.com/kataras/golog" "html" "net/http" "sort" @@ -136,7 +137,9 @@ func (h *routerHandler) Build(provider RoutesProvider) error { if err := h.addRoute(r); err != nil { // node errors: rp.Add("%v -> %s", err, r.String()) + continue } + golog.Debugf(r.Trace()) } return rp.Return() diff --git a/core/router/route.go b/core/router/route.go index 6a2f8def..755e66a6 100644 --- a/core/router/route.go +++ b/core/router/route.go @@ -22,7 +22,8 @@ type Route struct { beginHandlers context.Handlers // Handlers are the main route's handlers, executed by order. // Cannot be empty. - Handlers context.Handlers + Handlers context.Handlers + mainHandlerName string // temp storage, they're appended to the Handlers on build. // Execution happens after Begin and main Handler(s), can be empty. doneHandlers context.Handlers @@ -36,7 +37,7 @@ type Route struct { // handlers and the macro container which all routes should share. // It parses the path based on the "macros", // handlers are being changed to validate the macros at serve time, if needed. -func NewRoute(method, subdomain, unparsedPath string, +func NewRoute(method, subdomain, unparsedPath, mainHandlerName string, handlers context.Handlers, macros *macro.Map) (*Route, error) { tmpl, err := macro.Parse(unparsedPath, macros) @@ -54,13 +55,14 @@ func NewRoute(method, subdomain, unparsedPath string, formattedPath := formatPath(path) route := &Route{ - Name: defaultName, - Method: method, - Subdomain: subdomain, - tmpl: tmpl, - Path: path, - Handlers: handlers, - FormattedPath: formattedPath, + Name: defaultName, + Method: method, + Subdomain: subdomain, + tmpl: tmpl, + Path: path, + Handlers: handlers, + mainHandlerName: mainHandlerName, + FormattedPath: formattedPath, } return route, nil } @@ -203,6 +205,27 @@ func (r Route) ResolvePath(args ...string) string { return formattedPath } +// Trace returns some debug infos as a string sentence. +// Should be called after Build. +func (r Route) Trace() string { + printfmt := fmt.Sprintf("%s:", r.Method) + if r.Subdomain != "" { + printfmt += fmt.Sprintf(" %s", r.Subdomain) + } + printfmt += fmt.Sprintf(" %s ", r.Tmpl().Src) + if l := len(r.Handlers); l > 1 { + printfmt += fmt.Sprintf("-> %s() and %d more", r.mainHandlerName, l-1) + } else { + printfmt += fmt.Sprintf("-> %s()", r.mainHandlerName) + } + + // printfmt := fmt.Sprintf("%s: %s >> %s", r.Method, r.Subdomain+r.Tmpl().Src, r.mainHandlerName) + // if l := len(r.Handlers); l > 0 { + // printfmt += fmt.Sprintf(" and %d more", l) + // } + return printfmt // without new line. +} + type routeReadOnlyWrapper struct { *Route } @@ -222,3 +245,7 @@ func (rd routeReadOnlyWrapper) Subdomain() string { func (rd routeReadOnlyWrapper) Path() string { return rd.Route.tmpl.Src } + +func (rd routeReadOnlyWrapper) Trace() string { + return rd.Route.Trace() +} diff --git a/iris.go b/iris.go index 63eda6a6..7569f61c 100644 --- a/iris.go +++ b/iris.go @@ -425,7 +425,10 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor { } su.IgnoredErrors = append(su.IgnoredErrors, app.config.IgnoreServerErrors...) - app.logger.Debugf("Host: server will ignore the following errors: %s", su.IgnoredErrors) + if len(su.IgnoredErrors) > 0 { + app.logger.Debugf("Host: server will ignore the following errors: %s", su.IgnoredErrors) + } + su.Configure(app.hostConfigurators...) app.Hosts = append(app.Hosts, su)