diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-01-05 21:05:40 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-05 21:05:40 +0800 |
commit | 15a475b7dbcf7923d9518dff7764b20e404eb774 (patch) | |
tree | 8789f1f82c5e41345b442df4e58120bdd5f8bade /routers | |
parent | 126c9331d6d8789563fae5d5bac2196d63fee0e8 (diff) | |
download | gitea-15a475b7dbcf7923d9518dff7764b20e404eb774.tar.gz gitea-15a475b7dbcf7923d9518dff7764b20e404eb774.zip |
Fix recovery middleware to render gitea style page. (#13857)
* Some changes to fix recovery
* Move Recovery to middlewares
* Remove trace code
* Fix lint
* add session middleware and remove dependent on macaron for sso
* Fix panic 500 page rendering
* Fix bugs
* Fix fmt
* Fix vendor
* recover unnecessary change
* Fix lint and addd some comments about the copied codes.
* Use util.StatDir instead of com.StatDir
Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'routers')
-rw-r--r-- | routers/init.go | 34 | ||||
-rw-r--r-- | routers/routes/chi.go | 32 | ||||
-rw-r--r-- | routers/routes/recovery.go | 105 |
3 files changed, 121 insertions, 50 deletions
diff --git a/routers/init.go b/routers/init.go index ca8944bb2b..ff2ddcc0b7 100644 --- a/routers/init.go +++ b/routers/init.go @@ -26,19 +26,18 @@ import ( "code.gitea.io/gitea/modules/markup/external" repo_migrations "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/notification" - "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/task" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/services/mailer" mirror_service "code.gitea.io/gitea/services/mirror" pull_service "code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/repository" "code.gitea.io/gitea/services/webhook" - "gitea.com/macaron/i18n" "gitea.com/macaron/macaron" ) @@ -93,33 +92,6 @@ func initDBEngine(ctx context.Context) (err error) { return nil } -// InitLocales loads the locales -func InitLocales() { - localeNames, err := options.Dir("locale") - - if err != nil { - log.Fatal("Failed to list locale files: %v", err) - } - localFiles := make(map[string][]byte) - - for _, name := range localeNames { - localFiles[name], err = options.Locale(name) - - if err != nil { - log.Fatal("Failed to load %s locale file. %v", name, err) - } - } - i18n.I18n(i18n.Options{ - SubURL: setting.AppSubURL, - Files: localFiles, - Langs: setting.Langs, - Names: setting.Names, - DefaultLang: "en-US", - Redirect: false, - CookieDomain: setting.SessionConfig.Domain, - }) -} - // PreInstallInit preloads the configuration to check if we need to run install func PreInstallInit(ctx context.Context) bool { setting.NewContext() @@ -129,7 +101,7 @@ func PreInstallInit(ctx context.Context) bool { log.Trace("Custom path: %s", setting.CustomPath) log.Trace("Log path: %s", setting.LogRootPath) log.Trace("Preparing to run install page") - InitLocales() + translation.InitLocales() if setting.EnableSQLite3 { log.Info("SQLite3 Supported") } @@ -170,7 +142,7 @@ func GlobalInit(ctx context.Context) { log.Trace("Log path: %s", setting.LogRootPath) // Setup i18n - InitLocales() + translation.InitLocales() NewServices() diff --git a/routers/routes/chi.go b/routers/routes/chi.go index 00689441b7..c0ac88957e 100644 --- a/routers/routes/chi.go +++ b/routers/routes/chi.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/routers" + "gitea.com/go-chi/session" "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" "github.com/prometheus/client_golang/prometheus" @@ -37,7 +38,7 @@ type routerLoggerOptions struct { } // SignedUserName returns signed user's name via context -// FIXME currently no any data stored on gin.Context but macaron.Context, so this will +// FIXME currently no any data stored on chi.Context but macaron.Context, so this will // return "" before we remove macaron totally func SignedUserName(req *http.Request) string { if v, ok := req.Context().Value("SignedUserName").(string); ok { @@ -97,24 +98,6 @@ func LoggerHandler(level log.Level) func(next http.Handler) http.Handler { } } -// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so. -// Although similar to macaron.Recovery() the main difference is that this error will be created -// with the gitea 500 page. -func Recovery() func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - defer func() { - if err := recover(); err != nil { - combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) - http.Error(w, combinedErr, 500) - } - }() - - next.ServeHTTP(w, req) - }) - } -} - func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { if storageSetting.ServeDirect { @@ -202,6 +185,17 @@ func NewChi() chi.Router { c.Use(LoggerHandler(setting.RouterLogLevel)) } } + c.Use(session.Sessioner(session.Options{ + Provider: setting.SessionConfig.Provider, + ProviderConfig: setting.SessionConfig.ProviderConfig, + CookieName: setting.SessionConfig.CookieName, + CookiePath: setting.SessionConfig.CookiePath, + Gclifetime: setting.SessionConfig.Gclifetime, + Maxlifetime: setting.SessionConfig.Maxlifetime, + Secure: setting.SessionConfig.Secure, + Domain: setting.SessionConfig.Domain, + })) + c.Use(Recovery()) if setting.EnableAccessLog { setupAccessLogger(c) diff --git a/routers/routes/recovery.go b/routers/routes/recovery.go new file mode 100644 index 0000000000..870a219c41 --- /dev/null +++ b/routers/routes/recovery.go @@ -0,0 +1,105 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package routes + +import ( + "fmt" + "net/http" + + "code.gitea.io/gitea/modules/auth/sso" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/middlewares" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" + + "gitea.com/go-chi/session" + "github.com/unrolled/render" +) + +type dataStore struct { + Data map[string]interface{} +} + +func (d *dataStore) GetData() map[string]interface{} { + return d.Data +} + +// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so. +// Although similar to macaron.Recovery() the main difference is that this error will be created +// with the gitea 500 page. +func Recovery() func(next http.Handler) http.Handler { + var isDevelopment = setting.RunMode != "prod" + return func(next http.Handler) http.Handler { + rnd := render.New(render.Options{ + Extensions: []string{".tmpl"}, + Directory: "templates", + Funcs: templates.NewFuncMap(), + Asset: templates.GetAsset, + AssetNames: templates.GetAssetNames, + IsDevelopment: isDevelopment, + }) + + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + defer func() { + // Why we need this? The first recover will try to render a beautiful + // error page for user, but the process can still panic again, then + // we have to just recover twice and send a simple error page that + // should not panic any more. + defer func() { + if err := recover(); err != nil { + combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) + log.Error(combinedErr) + if isDevelopment { + http.Error(w, combinedErr, 500) + } else { + http.Error(w, http.StatusText(500), 500) + } + } + }() + + if err := recover(); err != nil { + combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) + log.Error("%v", combinedErr) + + lc := middlewares.Locale(w, req) + sess := session.GetSession(req) + + var store = dataStore{ + Data: templates.Vars{ + "Language": lc.Language(), + "CurrentURL": setting.AppSubURL + req.URL.RequestURI(), + "i18n": lc, + }, + } + + // Get user from session if logged in. + user, _ := sso.SignedInUser(req, &store, sess) + if user != nil { + store.Data["IsSigned"] = true + store.Data["SignedUser"] = user + store.Data["SignedUserID"] = user.ID + store.Data["SignedUserName"] = user.Name + store.Data["IsAdmin"] = user.IsAdmin + } else { + store.Data["SignedUserID"] = int64(0) + store.Data["SignedUserName"] = "" + } + + w.Header().Set(`X-Frame-Options`, `SAMEORIGIN`) + + if setting.RunMode != "prod" { + store.Data["ErrMsg"] = combinedErr + } + err := rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store.Data)) + if err != nil { + log.Error("%v", err) + } + } + }() + + next.ServeHTTP(w, req) + }) + } +} |