func echoServer() { e := echo.New() e.Use(middleware.Logger()) e.Post("/rsvp", echo.HandlerFunc(requestAddRsvp)) admin := e.Group("/rsvp") admin.Use(middleware.BasicAuth(checkAuth)) admin.Get("/list", echo.HandlerFunc(requestListRsvp)) admin.Get("/backup", echo.HandlerFunc(requestBoltBackup)) e.Static("/", *rootDir) fmt.Println("Starting Server:", *httpServ) e.Run(standard.New(*httpServ)) }
func main() { // 支持根据参数打印版本信息 global.PrintVersion(os.Stdout) savePid() logger.Init(ROOT+"/log", ConfigFile.MustValue("global", "log_level", "DEBUG")) go ServeBackGround() e := echo.New() serveStatic(e) e.Use(thirdmw.EchoLogger()) e.Use(mw.Recover()) e.Use(pwm.Installed(filterPrefixs)) e.Use(pwm.HTTPError()) e.Use(pwm.AutoLogin()) frontG := e.Group("", thirdmw.EchoCache()) controller.RegisterRoutes(frontG) frontG.GET("/admin", echo.HandlerFunc(admin.AdminIndex), pwm.NeedLogin(), pwm.AdminAuth()) adminG := e.Group("/admin", pwm.NeedLogin(), pwm.AdminAuth()) admin.RegisterRoutes(adminG) std := standard.New(getAddr()) std.SetHandler(e) gracefulRun(std) }
// BasicAuthFromConfig returns an HTTP basic auth middleware from config. // See `BasicAuth()`. func BasicAuthFromConfig(config BasicAuthConfig) echo.MiddlewareFunc { return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) error { auth := c.Request().Header().Get(echo.Authorization) l := len(basic) if len(auth) > l+1 && auth[:l] == basic { b, err := base64.StdEncoding.DecodeString(auth[l+1:]) if err == nil { cred := string(b) for i := 0; i < len(cred); i++ { if cred[i] == ':' { // Verify credentials if config.AuthFunc(cred[:i], cred[i+1:]) { return next.Handle(c) } } } } } c.Response().Header().Set(echo.WWWAuthenticate, basic+" realm=Restricted") return echo.ErrUnauthorized }) } }
// authorization is the authorization middleware for users. // It checks the access_token in the Authorization header or the access_token query parameter // On success sets "me" = *User (current logged user) and "accessData" = current access data // into the context. Sets even the scopes variable, the sorted slice of scopes in accessData func authorization() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var accessToken string auth := c.Request().Header.Get("Authorization") if auth == "" { // Check if there's the parameter access_token in the URL // this makes the bearer authentication with websockets compatible with OAuth2 accessToken = c.QueryParam("access_token") if accessToken == "" { return c.String(http.StatusUnauthorized, "access_token required") } } else { if !strings.HasPrefix(auth, "Bearer ") { return echo.ErrUnauthorized } ss := strings.Split(auth, " ") if len(ss) != 2 { return echo.ErrUnauthorized } accessToken = ss[1] } accessData, err := (&nerdz.OAuth2Storage{}).LoadAccess(accessToken) if err != nil { return c.String(http.StatusUnauthorized, err.Error()) } // fetch current logged user and store it into the context me, err := nerdz.NewUser(accessData.UserData.(uint64)) if err != nil { return c.String(http.StatusInternalServerError, err.Error()) } c.Set("me", me) // store the Access Data into the context c.Set("accessData", accessData) scopes := strings.Split(accessData.Scope, " ") sort.Strings(scopes) // store the sorted Scopes using the full format // eg: if accepted scope is profile:read,write // save 2 entries: profile:read and profile:write // each saved scope is always in the format <name>:<read|,write> var fullScopes []string for _, s := range scopes { //parts[0] = <scope>, parts[1] = <rw> parts := strings.Split(s, ":") rw := strings.Split(parts[1], ",") for _, perm := range rw { fullScopes = append(fullScopes, parts[0]+":"+perm) } } c.Set("scopes", fullScopes) // let next handler handle the context return next(c) }) } }
// GzipFromConfig return gzip middleware from config. // See `Gzip()`. func GzipFromConfig(config GzipConfig) echo.MiddlewareFunc { pool := gzipPool(config) scheme := "gzip" return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) error { c.Response().Header().Add(echo.Vary, echo.AcceptEncoding) if strings.Contains(c.Request().Header().Get(echo.AcceptEncoding), scheme) { rw := c.Response().Writer() gw := pool.Get().(*gzip.Writer) gw.Reset(rw) defer func() { if c.Response().Size() == 0 { // We have to reset response to it's pristine state when // nothing is written to body or error is returned. // See issue #424, #407. c.Response().SetWriter(rw) c.Response().Header().Del(echo.ContentEncoding) gw.Reset(ioutil.Discard) } gw.Close() pool.Put(gw) }() g := gzipResponseWriter{Response: c.Response(), Writer: gw} c.Response().Header().Set(echo.ContentEncoding, scheme) c.Response().SetWriter(g) } return next.Handle(c) }) } }
// SetPost is the middleware that checks if the required post, on the project board, exists. // If it exists, set the "post" = *ProjectPost in the current context func SetPost() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var e error var pid uint64 if pid, e = strconv.ParseUint(c.Param("pid"), 10, 64); e != nil { c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: "Invalid post identifier specified", Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } projectID := c.Get("project").(*nerdz.Project).ID() var post *nerdz.ProjectPost if post, e = nerdz.NewProjectPostWhere(&nerdz.ProjectPost{nerdz.Post{To: projectID, Pid: pid}}); e != nil { c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: "Required post does not exists", Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } c.Set("post", post) return next(c) }) } }
// SetOther is the middleware that sets the context variable "other" to "me" // therfore we can use the package user methods in the me package func SetOther() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { c.Set("other", c.Get("me")) return next(c) }) } }
// SetPm is the middleware that check if the required pm exists. // If it exists, set the "pm" = *Pm in the current context func SetPm() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { // other is the owner of the pm list other := c.Get("other").(*nerdz.User) // otherID is the ID of the second actor in the conversation var otherID, pmID uint64 var e error if otherID, e = strconv.ParseUint(c.Param("other"), 10, 64); e != nil { errstr := "Invalid user identifier specified" c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: errstr, Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } if pmID, e = strconv.ParseUint(c.Param("pmid"), 10, 64); e != nil { errstr := "Invalid PM identifier specified" c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: errstr, Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } var pm *nerdz.Pm if pm, e = nerdz.NewPm(pmID); e != nil { c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: e.Error(), Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } if (pm.From == otherID && pm.To == other.ID()) || (pm.From == other.ID() && pm.To == otherID) { c.Set("pm", pm) return next(c) } errstr := "You're not autorized to see the requested PM" c.JSON(http.StatusUnauthorized, &rest.Response{ HumanMessage: errstr, Message: errstr, Status: http.StatusUnauthorized, Success: false, }) return errors.New(errstr) }) } }
// Mgo returns a middleware which connect to mongo and set the session in the context func Mgo(mgodb *mgo.Database) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { sc := mgodb.Session.Clone() defer sc.Close() c.Set("mgok", sc.DB(mgodb.Name)) return next(c) }) } }
// WrapMiddleware wraps `fasthttp.RequestHandler` into `echo.MiddlewareFunc` func WrapMiddleware(h fasthttp.RequestHandler) echo.MiddlewareFunc { return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) error { rq := c.Request().(*Request) rs := c.Response().(*Response) ctx := rq.RequestCtx h(ctx) rs.status = ctx.Response.StatusCode() rs.size = int64(ctx.Response.Header.ContentLength()) return next.Handle(c) }) } }
func TestRecover(t *testing.T) { e := echo.New() buf := new(bytes.Buffer) e.SetLogOutput(buf) rq := test.NewRequest(echo.GET, "/", nil) rc := test.NewResponseRecorder() c := e.NewContext(rq, rc) h := Recover()(echo.HandlerFunc(func(c echo.Context) error { panic("test") })) h(c) assert.Equal(t, http.StatusInternalServerError, rc.Status()) assert.Contains(t, buf.String(), "PANIC RECOVER") }
func TestRecover(t *testing.T) { e := echo.New() buf := new(bytes.Buffer) e.Logger.SetOutput(buf) req, _ := http.NewRequest(echo.GET, "/", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) h := Recover()(echo.HandlerFunc(func(c echo.Context) error { panic("test") })) h(c) assert.Equal(t, http.StatusInternalServerError, rec.Code) assert.Contains(t, buf.String(), "PANIC RECOVER") }
// SetProject is the middleware that checks if the current logged user can see the required project // and if the required project exists. On success sets the "project" = *Project variable in the context func SetProject() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var project *nerdz.Project var err error if project, err = rest.Project("id", c); err != nil { return err } // store the project Project into the context c.Set("project", project) // pass context to the next handler return next(c) }) } }
// SetOther is the middleware that checks if the current logged user can see the required profile // and if the required profile exists. On success sets the "other" = *User variable in the context func SetOther() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var other *nerdz.User var err error if other, err = rest.User("id", c); err != nil { return err } // store the other User into the context c.Set("other", other) // pass context to the next handler return next(c) }) } }
// WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc` func WrapMiddleware(m func(http.Handler) http.Handler) echo.MiddlewareFunc { return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) (err error) { rq := c.Request().(*Request) rs := c.Response().(*Response) w := &responseAdapter{ ResponseWriter: rs.ResponseWriter, Response: rs, } m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err = next.Handle(c) })).ServeHTTP(w, rq.Request) return }) } }
// SetComment is the middleware that check if the required comment, on the user board, exists. // If it exists, set the "comment" = *UserPostComment in the current context func SetComment() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var cid uint64 var e error if cid, e = strconv.ParseUint(c.Param("cid"), 10, 64); e != nil { errstr := "Invalid comment identifier specified" c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: errstr, Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } var comment *nerdz.UserPostComment if comment, e = nerdz.NewUserPostComment(cid); e != nil { errstr := "Invalid comment identifier specified" c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: errstr, Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return e } post := c.Get("post").(*nerdz.UserPost) if comment.Hpid != post.Hpid { errstr := "Mismatch between comment ID and post ID. Comment not related to the post" c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: errstr, Message: errstr, Status: http.StatusBadRequest, Success: false, }) return e } c.Set("comment", comment) return next(c) }) } }
// setPmsOptions is the middleware that sets the "pmsOptions" = *nerdz.PmsOptions into the current context // handle GET parameters: func setPmsOptions() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { old := c.QueryParam("older") new := c.QueryParam("newer") older, _ := strconv.ParseUint(old, 10, 64) newer, _ := strconv.ParseUint(new, 10, 64) n, _ := strconv.ParseUint(c.QueryParam("n"), 10, 8) c.Set("pmsOptions", &nerdz.PmsOptions{ N: nerdz.AtMostComments(n), Older: older, Newer: newer, }) return next(c) }) } }
func TransactionHandler(db *dbr.Session) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { tx, _ := db.Begin() c.Set(TxKey, tx) if err := next(c); err != nil { tx.Rollback() logrus.Debug("Transction Rollback: ", err) return err } logrus.Debug("Transction Commit") tx.Commit() return nil }) } }
// StoreHeaders get header values and set to context func StoreHeaders(options ...*StoreHeaderOptions) echo.MiddlewareFunc { return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) error { request := c.Request() header := request.Header() url := request.URL() //application/vnd.get3w.v3+json version := VersionV1 accept := header.Get("Accept") if accept == "" || accept == "application/vnd.get3w.v1+json" { version = VersionV1 } c.Set("Version", version) auth := header.Get("Authorization") l := len(Bearer) accessToken := "" if len(auth) > l+1 && auth[:l] == Bearer { accessToken = auth[l+1:] } else if len(header.Get(TokenNameOfHeader)) > 0 { accessToken = header.Get(TokenNameOfHeader) } else if len(url.QueryValue(TokenNameOfQuery)) > 0 { accessToken = url.QueryValue(TokenNameOfQuery) } c.Set("AccessToken", accessToken) config, _ := home.LoadConfig() c.Set("Config", config) if err := next.Handle(c); err != nil { c.Error(err) } return nil }) } }
// Modify 编辑规则 func (self RuleController) Modify(ctx echo.Context) error { var data = make(map[string]interface{}) if ctx.FormValue("submit") == "1" { user := ctx.Get("user").(*model.Me) errMsg, err := logic.DefaultRule.Save(ctx, ctx.FormParams(), user.Username) if err != nil { return fail(ctx, 1, errMsg) } return success(ctx, nil) } rule := logic.DefaultRule.FindById(ctx, ctx.QueryParam("id")) if rule == nil { return ctx.Redirect(http.StatusSeeOther, ctx.Echo().URI(echo.HandlerFunc(self.RuleList))) } data["rule"] = rule return render(ctx, "rule/modify.html", data) }
// Modify func (self ArticleController) Modify(ctx echo.Context) error { var data = make(map[string]interface{}) if ctx.FormValue("submit") == "1" { user := ctx.Get("user").(*model.Me) errMsg, err := logic.DefaultArticle.Modify(ctx, user, ctx.FormParams()) if err != nil { return fail(ctx, 1, errMsg) } return success(ctx, nil) } article, err := logic.DefaultArticle.FindById(ctx, ctx.QueryParam("id")) if err != nil { return ctx.Redirect(http.StatusSeeOther, ctx.Echo().URI(echo.HandlerFunc(self.ArticleList))) } data["article"] = article data["statusSlice"] = model.ArticleStatusSlice data["langSlice"] = model.LangSlice return render(ctx, "article/modify.html", data) }
// RecoverFromConfig returns a recover middleware from config. // See `Recover()`. func RecoverFromConfig(config RecoverConfig) echo.MiddlewareFunc { return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) error { defer func() { if r := recover(); r != nil { var err error switch r := r.(type) { case error: err = r default: err = fmt.Errorf("%v", r) } stack := make([]byte, config.StackSize) length := runtime.Stack(stack, config.StackAll) if config.PrintStack { c.Logger().Printf("[%s] %s %s", color.Red("PANIC RECOVER"), err, stack[:length]) } c.Error(err) } }() return next.Handle(c) }) } }
// StaticFromConfig returns a static middleware from config. // See `Static()`. func StaticFromConfig(config StaticConfig) echo.MiddlewareFunc { return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) error { fs := http.Dir(config.Root) file := path.Clean(c.Request().URL().Path()) f, err := fs.Open(file) if err != nil { return next.Handle(c) } defer f.Close() fi, err := f.Stat() if err != nil { return err } if fi.IsDir() { /* NOTE: Not checking the Last-Modified header as it caches the response `304` when changing different directories for the same path. */ d := f // Index file file = path.Join(file, config.Index) f, err = fs.Open(file) if err != nil { if config.Browse { dirs, err := d.Readdir(-1) if err != nil { return err } // Create a directory index rs := c.Response() rs.Header().Set(echo.ContentType, echo.TextHTMLCharsetUTF8) if _, err = fmt.Fprintf(rs, "<pre>\n"); err != nil { return err } for _, d := range dirs { name := d.Name() color := "#212121" if d.IsDir() { color = "#e91e63" name += "/" } if _, err = fmt.Fprintf(rs, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil { return err } } _, err = fmt.Fprintf(rs, "</pre>\n") return err } return next.Handle(c) } fi, _ = f.Stat() // Index file stat } return c.ServeContent(f, fi.Name(), fi.ModTime()) }) } }
// setPostlist is the middleware that sets "postlistOptions" = *nerdz.PostlistOptions into the current Context // handle GET parameters: // following: if setted, requires posts from following users // followers: if setted, requires posts from followers users // lang: if setted to a supported language (nerdz.Configuration.Languages), requires // posts in that language // older: if setted to an existing hpid, requires posts older than the "older" value // olderType: if setted can be only "user" or "project". Represents a reference to the older hpid type // used when fetching from a view, where hpid can be from posts or groups_posts // newer: if setted to an existing hpid, requires posts newer than the "newer" value7 // newerType: if setted can be only "user" or "project". Represents a reference to the newer hpid type // used when fetching from a view, where hpid can be from posts or groups_posts // n: if setted, define the number of posts to retrieve. Follows the nerdz.atMostPost rules func setPostlist() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var following, followers bool if c.QueryParam("following") != "" { following = true } if c.QueryParam("followers") != "" { followers = true } for _, t := range []string{"olderType", "newerType"} { tValue := c.QueryParam(t) if tValue != "" { if tValue != "user" && tValue != "project" { message := fmt.Sprintf(`Unsupported %s %s. Only "user" or "project" are allowed`, t, tValue) return c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: message, Message: message, Status: http.StatusBadRequest, Success: false, }) } } } var olderModel, newerModel igor.DBModel if c.QueryParam("olderType") == "user" { olderModel = nerdz.UserPost{} } else { olderModel = nerdz.ProjectPost{} } if c.QueryParam("newerType") == "user" { newerModel = nerdz.UserPost{} } else { newerModel = nerdz.ProjectPost{} } var language string lang := c.QueryParam("lang") if lang == "" { language = "" } else { if !utils.InSlice(lang, nerdz.Configuration.Languages) { message := "Not supported language: " + lang return c.JSON(http.StatusBadRequest, &rest.Response{ HumanMessage: message, Message: message, Status: http.StatusBadRequest, Success: false, }) } language = lang } old := c.QueryParam("older") new := c.QueryParam("newer") older, _ := strconv.ParseUint(old, 10, 64) newer, _ := strconv.ParseUint(new, 10, 64) n, _ := strconv.ParseUint(c.QueryParam("n"), 10, 8) c.Set("postlistOptions", &nerdz.PostlistOptions{ Following: following, Followers: followers, Language: language, N: nerdz.AtMostPosts(n), Older: older, OlderModel: olderModel, Newer: newer, NewerModel: newerModel, }) return next(c) }) } }
func main() { e := echo.New() // New permissions middleware perm, err := permissionHSTORE.New() if err != nil { log.Fatalln(err) } // Blank slate, no default permissions //perm.Clear() // Set up a middleware handler for Echo, with a custom "permission denied" message. permissionHandler := echo.MiddlewareFunc(func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { // Check if the user has the right admin/user rights if perm.Rejected(w(c), req(c)) { // Deny the request return echo.NewHTTPError(http.StatusForbidden, "Permission denied!") } // Continue the chain of middleware return next(c) }) }) // Logging middleware e.Use(middleware.Logger()) // Enable the permissions middleware, must come before recovery e.Use(permissionHandler) // Recovery middleware e.Use(middleware.Recover()) // Get the userstate, used in the handlers below userstate := perm.UserState() e.Get("/", echo.HandlerFunc(func(c echo.Context) error { var buf bytes.Buffer b2s := map[bool]string{false: "false", true: "true"} buf.WriteString("Has user bob: " + b2s[userstate.HasUser("bob")] + "\n") buf.WriteString("Logged in on server: " + b2s[userstate.IsLoggedIn("bob")] + "\n") buf.WriteString("Is confirmed: " + b2s[userstate.IsConfirmed("bob")] + "\n") buf.WriteString("Username stored in cookies (or blank): " + userstate.Username(req(c)) + "\n") buf.WriteString("Current user is logged in, has a valid cookie and *user rights*: " + b2s[userstate.UserRights(req(c))] + "\n") buf.WriteString("Current user is logged in, has a valid cookie and *admin rights*: " + b2s[userstate.AdminRights(req(c))] + "\n") buf.WriteString("\nTry: /register, /confirm, /remove, /login, /logout, /makeadmin, /clear, /data and /admin") return c.String(http.StatusOK, buf.String()) })) e.Get("/register", echo.HandlerFunc(func(c echo.Context) error { userstate.AddUser("bob", "hunter1", "*****@*****.**") return c.String(http.StatusOK, fmt.Sprintf("User bob was created: %v\n", userstate.HasUser("bob"))) })) e.Get("/confirm", echo.HandlerFunc(func(c echo.Context) error { userstate.MarkConfirmed("bob") return c.String(http.StatusOK, fmt.Sprintf("User bob was confirmed: %v\n", userstate.IsConfirmed("bob"))) })) e.Get("/remove", echo.HandlerFunc(func(c echo.Context) error { userstate.RemoveUser("bob") return c.String(http.StatusOK, fmt.Sprintf("User bob was removed: %v\n", !userstate.HasUser("bob"))) })) e.Get("/login", echo.HandlerFunc(func(c echo.Context) error { // Headers will be written, for storing a cookie userstate.Login(w(c), "bob") return c.String(http.StatusOK, fmt.Sprintf("bob is now logged in: %v\n", userstate.IsLoggedIn("bob"))) })) e.Get("/logout", echo.HandlerFunc(func(c echo.Context) error { userstate.Logout("bob") return c.String(http.StatusOK, fmt.Sprintf("bob is now logged out: %v\n", !userstate.IsLoggedIn("bob"))) })) e.Get("/makeadmin", echo.HandlerFunc(func(c echo.Context) error { userstate.SetAdminStatus("bob") return c.String(http.StatusOK, fmt.Sprintf("bob is now administrator: %v\n", userstate.IsAdmin("bob"))) })) e.Get("/clear", echo.HandlerFunc(func(c echo.Context) error { userstate.ClearCookie(w(c)) return c.String(http.StatusOK, "Clearing cookie") })) e.Get("/data", echo.HandlerFunc(func(c echo.Context) error { return c.String(http.StatusOK, "user page that only logged in users must see!") })) e.Get("/admin", echo.HandlerFunc(func(c echo.Context) error { var buf bytes.Buffer buf.WriteString("super secret information that only logged in administrators must see!\n\n") if usernames, err := userstate.AllUsernames(); err == nil { buf.WriteString("list of all users: " + strings.Join(usernames, ", ")) } return c.String(http.StatusOK, buf.String()) })) // Serve e.Run(standard.New(":3000")) }
// LoggerFromConfig returns a logger middleware from config. // See `Logger()`. func LoggerFromConfig(config LoggerConfig) echo.MiddlewareFunc { config.template = fasttemplate.New(config.Format, "${", "}") config.color = color.New() if w, ok := config.Output.(*os.File); ok && !isatty.IsTerminal(w.Fd()) { config.color.Disable() } return func(next echo.Handler) echo.Handler { return echo.HandlerFunc(func(c echo.Context) (err error) { rq := c.Request() rs := c.Response() start := time.Now() if err = next.Handle(c); err != nil { c.Error(err) } stop := time.Now() _, err = config.template.ExecuteFunc(config.Output, func(w io.Writer, tag string) (int, error) { switch tag { case "time_rfc3339": return w.Write([]byte(time.Now().Format(time.RFC3339))) case "remote_ip": ra := rq.RemoteAddress() if ip := rq.Header().Get(echo.XRealIP); ip != "" { ra = ip } else if ip = rq.Header().Get(echo.XForwardedFor); ip != "" { ra = ip } else { ra, _, _ = net.SplitHostPort(ra) } return w.Write([]byte(ra)) case "uri": return w.Write([]byte(rq.URI())) case "method": return w.Write([]byte(rq.Method())) case "path": p := rq.URL().Path() if p == "" { p = "/" } return w.Write([]byte(p)) case "status": n := rs.Status() s := color.Green(n) switch { case n >= 500: s = color.Red(n) case n >= 400: s = color.Yellow(n) case n >= 300: s = color.Cyan(n) } return w.Write([]byte(s)) case "response_time": return w.Write([]byte(stop.Sub(start).String())) case "response_size": return w.Write([]byte(strconv.FormatInt(rs.Size(), 10))) default: return w.Write([]byte(fmt.Sprintf("[unknown tag %s]", tag))) } }) return }) } }
func main() { // Echo instance e := echo.New() // Middleware echo e.Use(middleware.Logger()) logg := e.Logger() e.Use(middleware.Recover()) e.Use(middleware.Gzip()) e.Use(middleware.Secure()) e.Use(middleware.CORS()) e.Use(middleware.BodyLimit("200M")) // gopkg.in/mgo.v2 db := midd.NewMgo(viper.GetString("db.url"), viper.GetString("db.name")) defer db.Session.Close() e.Use(midd.Mgo(db)) // github.com/thoas/stats middStat := stats.New() e.Use(standard.WrapMiddleware(middStat.Handler)) // Route for stats e.Get("/stats", echo.HandlerFunc(func(c echo.Context) error { return c.JSON(http.StatusOK, middStat.Data()) })) // API v1 Restricted group Token in header api := e.Group("/apiv1") api.Use(middleware.JWTWithConfig(middleware.JWTConfig{ SigningKey: []byte(midd.SigningKey), TokenLookup: "header:Authorization"})) api.Post("/user", handler.PostUser) api.Get("/user/:id", handler.GetUser) // API v1 Token as first param apit := e.Group("/apiv1token") apit.Use(middleware.JWTWithConfig(middleware.JWTConfig{ SigningKey: []byte(midd.SigningKey), TokenLookup: "query:token"})) apit.Post("/user", handler.PostUser) apit.Get("/user/:id", handler.GetUser) // Serve index file e.File("/", "public/index.html") // Serve favicon e.File("/favicon.ico", "public/favicon.ico") // Serve static files e.Static("/scripts", "public/scripts") midd.GenerateToken() // Get server info var svrHostname string if runtime.GOOS == "windows" { svrHostname = fmt.Sprintf("%s.%s", os.Getenv("COMPUTERNAME"), os.Getenv("USERDNSDOMAIN")) } else { svrHostname, _ = os.Hostname() } webInterfacePort := viper.GetString("web.interface") logg.Printf("%s for %s %s on %d cores\n%s%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH, runtime.NumCPU(), svrHostname, webInterfacePort) mgoInfo, _ := db.Session.BuildInfo() logg.Printf("MongoDB %s %d bits\n", mgoInfo.Version, mgoInfo.Bits) // github.com/tylerb/graceful std := standard.New(webInterfacePort) std.SetHandler(e) graceful.ListenAndServe(std.Server, 5*time.Second) }