Moving app from singular to being created for every request (#9889)

* Moving app from singular to being created for every request.

* Automatic refactor

* Adding license header

* Feedback fixes
Этот коммит содержится в:
Christopher Speller
2018-11-28 10:56:21 -08:00
коммит произвёл GitHub
родитель 1bcf08aa4b
Коммит da265fbaf7
68 изменённых файлов: 1272 добавлений и 1096 удалений

Просмотреть файл

@@ -9,8 +9,6 @@ import (
"regexp"
"strings"
goi18n "github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
@@ -21,18 +19,13 @@ import (
type Context struct {
App *app.App
Log *mlog.Logger
Session model.Session
Params *Params
Err *model.AppError
T goi18n.TranslateFunc
RequestId string
IpAddress string
Path string
siteURLHeader string
}
func (c *Context) LogAudit(extraInfo string) {
audit := &model.Audit{UserId: c.Session.UserId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
audit := &model.Audit{UserId: c.App.Session.UserId, IpAddress: c.App.IpAddress, Action: c.App.Path, ExtraInfo: extraInfo, SessionId: c.App.Session.Id}
if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
c.LogError(r.Err)
}
@@ -40,11 +33,11 @@ func (c *Context) LogAudit(extraInfo string) {
func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
if len(c.Session.UserId) > 0 {
extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.Session.UserId)
if len(c.App.Session.UserId) > 0 {
extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.App.Session.UserId)
}
audit := &model.Audit{UserId: userId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
audit := &model.Audit{UserId: userId, IpAddress: c.App.IpAddress, Action: c.App.Path, ExtraInfo: extraInfo, SessionId: c.App.Session.Id}
if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
c.LogError(r.Err)
}
@@ -53,7 +46,7 @@ func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
func (c *Context) LogError(err *model.AppError) {
// Filter out 404s, endless reconnects and browser compatibility errors
if err.StatusCode == http.StatusNotFound ||
(c.Path == "/api/v3/users/websocket" && err.StatusCode == http.StatusUnauthorized) ||
(c.App.Path == "/api/v3/users/websocket" && err.StatusCode == http.StatusUnauthorized) ||
err.Id == "web.check_browser_compatibility.app_error" {
c.LogDebug(err)
} else {
@@ -90,16 +83,16 @@ func (c *Context) LogDebug(err *model.AppError) {
}
func (c *Context) IsSystemAdmin() bool {
return c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM)
return c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM)
}
func (c *Context) SessionRequired() {
if !*c.App.Config().ServiceSettings.EnableUserAccessTokens && c.Session.Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN {
if !*c.App.Config().ServiceSettings.EnableUserAccessTokens && c.App.Session.Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserAccessToken", http.StatusUnauthorized)
return
}
if len(c.Session.UserId) == 0 {
if len(c.App.Session.UserId) == 0 {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserRequired", http.StatusUnauthorized)
return
}
@@ -112,11 +105,11 @@ func (c *Context) MfaRequired() {
}
// OAuth integrations are excepted
if c.Session.IsOAuth {
if c.App.Session.IsOAuth {
return
}
if user, err := c.App.GetUser(c.Session.UserId); err != nil {
if user, err := c.App.GetUser(c.App.Session.UserId); err != nil {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "MfaRequired", http.StatusUnauthorized)
return
} else {
@@ -129,7 +122,7 @@ func (c *Context) MfaRequired() {
// Special case to let user get themself
subpath, _ := utils.GetSubpathFromConfig(c.App.Config())
if c.Path == path.Join(subpath, "/api/v4/users/me") {
if c.App.Path == path.Join(subpath, "/api/v4/users/me") {
return
}
@@ -190,7 +183,7 @@ func NewInvalidUrlParamError(parameter string) *model.AppError {
}
func (c *Context) SetPermissionError(permission *model.Permission) {
c.Err = model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+c.Session.UserId+", "+"permission="+permission.Id, http.StatusForbidden)
c.Err = model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+c.App.Session.UserId+", "+"permission="+permission.Id, http.StatusForbidden)
}
func (c *Context) SetSiteURLHeader(url string) {
@@ -207,7 +200,7 @@ func (c *Context) RequireUserId() *Context {
}
if c.Params.UserId == model.ME {
c.Params.UserId = c.Session.UserId
c.Params.UserId = c.App.Session.UserId
}
if len(c.Params.UserId) != 26 {

Просмотреть файл

@@ -16,33 +16,33 @@ import (
func (w *Web) NewHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
return &Handler{
App: w.App,
HandleFunc: h,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
}
}
func (w *Web) NewStaticHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
return &Handler{
App: w.App,
HandleFunc: h,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
}
}
type Handler struct {
App *app.App
HandleFunc func(*Context, http.ResponseWriter, *http.Request)
RequireSession bool
TrustRequester bool
RequireMfa bool
IsStatic bool
GetGlobalAppOptions app.AppOptionCreator
HandleFunc func(*Context, http.ResponseWriter, *http.Request)
RequireSession bool
TrustRequester bool
RequireMfa bool
IsStatic bool
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -50,12 +50,14 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
mlog.Debug(fmt.Sprintf("%v - %v", r.Method, r.URL.Path))
c := &Context{}
c.App = h.App
c.T, _ = utils.GetTranslationsAndLocale(w, r)
c.RequestId = model.NewId()
c.IpAddress = utils.GetIpAddress(r)
c.App = app.New(
h.GetGlobalAppOptions()...,
)
c.App.T, _ = utils.GetTranslationsAndLocale(w, r)
c.App.RequestId = model.NewId()
c.App.IpAddress = utils.GetIpAddress(r)
c.Params = ParamsFromRequest(r)
c.Path = r.URL.Path
c.App.Path = r.URL.Path
c.Log = c.App.Log
token, tokenLocation := app.ParseAuthTokenFromRequest(r)
@@ -72,7 +74,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
siteURLHeader := app.GetProtocol(r) + "://" + r.Host + subpath
c.SetSiteURLHeader(siteURLHeader)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
w.Header().Set(model.HEADER_REQUEST_ID, c.App.RequestId)
w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.BuildNumber, c.App.ClientConfigHash(), c.App.License() != nil))
if *c.App.Config().ServiceSettings.TLSStrictTransport {
@@ -106,20 +108,20 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else if !session.IsOAuth && tokenLocation == app.TokenLocationQueryString {
c.Err = model.NewAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token, http.StatusUnauthorized)
} else {
c.Session = *session
c.App.Session = *session
}
// Rate limit by UserID
if c.App.Srv.RateLimiter != nil && c.App.Srv.RateLimiter.UserIdRateLimit(c.Session.UserId, w) {
if c.App.Srv.RateLimiter != nil && c.App.Srv.RateLimiter.UserIdRateLimit(c.App.Session.UserId, w) {
return
}
}
c.Log = c.App.Log.With(
mlog.String("path", c.Path),
mlog.String("request_id", c.RequestId),
mlog.String("ip_addr", c.IpAddress),
mlog.String("user_id", c.Session.UserId),
mlog.String("path", c.App.Path),
mlog.String("request_id", c.App.RequestId),
mlog.String("ip_addr", c.App.IpAddress),
mlog.String("user_id", c.App.Session.UserId),
mlog.String("method", r.Method),
)
@@ -137,8 +139,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Handle errors that have occurred
if c.Err != nil {
c.Err.Translate(c.T)
c.Err.RequestId = c.RequestId
c.Err.Translate(c.App.T)
c.Err.RequestId = c.App.RequestId
if c.Err.Id == "api.context.session_expired.app_error" {
c.LogInfo(c.Err)

Просмотреть файл

@@ -18,10 +18,10 @@ func handlerForHTTPErrors(c *Context, w http.ResponseWriter, r *http.Request) {
}
func TestHandlerServeHTTPErrors(t *testing.T) {
a, err := app.New(app.StoreOverride(testStore), app.DisableConfigWatch)
defer a.Shutdown()
s, err := app.NewServer(app.StoreOverride(testStore), app.DisableConfigWatch)
defer s.Shutdown()
web := NewWeb(a, a.Srv.Router)
web := New(s, s.AppOptions, s.Router)
if err != nil {
panic(err)
}
@@ -61,15 +61,17 @@ func handlerForHTTPSecureTransport(c *Context, w http.ResponseWriter, r *http.Re
}
func TestHandlerServeHTTPSecureTransport(t *testing.T) {
a, err := app.New(app.StoreOverride(testStore), app.DisableConfigWatch)
defer a.Shutdown()
s, err := app.NewServer(app.StoreOverride(testStore), app.DisableConfigWatch)
defer s.Shutdown()
a := s.FakeApp()
a.UpdateConfig(func(config *model.Config) {
*config.ServiceSettings.TLSStrictTransport = true
*config.ServiceSettings.TLSStrictTransportMaxAge = 6000
})
web := NewWeb(a, a.Srv.Router)
web := New(s, s.AppOptions, s.Router)
if err != nil {
panic(err)
}

Просмотреть файл

@@ -97,7 +97,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
action := relayProps["action"]
if user, err := samlInterface.DoLogin(encodedXML, relayProps); err != nil {
if action == model.OAUTH_ACTION_MOBILE {
err.Translate(c.T)
err.Translate(c.App.T)
w.Write([]byte(err.ToJson()))
} else {
c.Err = err
@@ -142,7 +142,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
c.Session = *session
c.App.Session = *session
if val, ok := relayProps["redirect_to"]; ok {
http.Redirect(w, r, c.GetSiteURLHeader()+val, http.StatusFound)
@@ -153,7 +153,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
case model.OAUTH_ACTION_MOBILE:
ReturnStatusOK(w)
case model.OAUTH_ACTION_CLIENT:
err = c.App.SendMessageToExtension(w, relayProps["extension_id"], c.Session.Token)
err = c.App.SendMessageToExtension(w, relayProps["extension_id"], c.App.Session.Token)
if err != nil {
c.Err = err

Просмотреть файл

@@ -19,20 +19,20 @@ import (
)
func (w *Web) InitStatic() {
if *w.App.Config().ServiceSettings.WebserverMode != "disabled" {
utils.UpdateAssetsSubpathFromConfig(w.App.Config())
if *w.ConfigService.Config().ServiceSettings.WebserverMode != "disabled" {
utils.UpdateAssetsSubpathFromConfig(w.ConfigService.Config())
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
mlog.Debug(fmt.Sprintf("Using client directory at %v", staticDir))
subpath, _ := utils.GetSubpathFromConfig(w.App.Config())
subpath, _ := utils.GetSubpathFromConfig(w.ConfigService.Config())
mime.AddExtensionType(".wasm", "application/wasm")
staticHandler := staticFilesHandler(http.StripPrefix(path.Join(subpath, "static"), http.FileServer(http.Dir(staticDir))))
pluginHandler := staticFilesHandler(http.StripPrefix(path.Join(subpath, "static", "plugins"), http.FileServer(http.Dir(*w.App.Config().PluginSettings.ClientDirectory))))
pluginHandler := staticFilesHandler(http.StripPrefix(path.Join(subpath, "static", "plugins"), http.FileServer(http.Dir(*w.ConfigService.Config().PluginSettings.ClientDirectory))))
if *w.App.Config().ServiceSettings.WebserverMode == "gzip" {
if *w.ConfigService.Config().ServiceSettings.WebserverMode == "gzip" {
staticHandler = gziphandler.GzipHandler(staticHandler)
pluginHandler = gziphandler.GzipHandler(pluginHandler)
}
@@ -56,8 +56,8 @@ func root(c *Context, w http.ResponseWriter, r *http.Request) {
if !CheckClientCompatability(r.UserAgent()) {
w.Header().Set("Cache-Control", "no-store")
page := utils.NewHTMLTemplate(c.App.HTMLTemplates(), "unsupported_browser")
page.Props["Title"] = c.T("web.error.unsupported_browser.title")
page.Props["Message"] = c.T("web.error.unsupported_browser.message")
page.Props["Title"] = c.App.T("web.error.unsupported_browser.title")
page.Props["Message"] = c.App.T("web.error.unsupported_browser.message")
page.RenderToWriter(w)
return
}

Просмотреть файл

@@ -15,20 +15,23 @@ import (
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/services/configservice"
"github.com/mattermost/mattermost-server/utils"
)
type Web struct {
App *app.App
MainRouter *mux.Router
GetGlobalAppOptions app.AppOptionCreator
ConfigService configservice.ConfigService
MainRouter *mux.Router
}
func NewWeb(a *app.App, root *mux.Router) *Web {
func New(config configservice.ConfigService, globalOptions app.AppOptionCreator, root *mux.Router) *Web {
mlog.Debug("Initializing web routes")
web := &Web{
App: a,
MainRouter: root,
GetGlobalAppOptions: globalOptions,
ConfigService: config,
MainRouter: root,
}
web.InitWebhooks()
@@ -56,22 +59,22 @@ func CheckClientCompatability(agentString string) bool {
return true
}
func Handle404(a *app.App, w http.ResponseWriter, r *http.Request) {
func Handle404(config configservice.ConfigService, w http.ResponseWriter, r *http.Request) {
err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound)
mlog.Debug(fmt.Sprintf("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r)))
if IsApiCall(a, r) {
if IsApiCall(config, r) {
w.WriteHeader(err.StatusCode)
err.DetailedError = "There doesn't appear to be an api call for the url='" + r.URL.Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
w.Write([]byte(err.ToJson()))
} else {
utils.RenderWebAppError(a.Config(), w, r, err, a.AsymmetricSigningKey())
utils.RenderWebAppError(config.Config(), w, r, err, config.AsymmetricSigningKey())
}
}
func IsApiCall(a *app.App, r *http.Request) bool {
subpath, _ := utils.GetSubpathFromConfig(a.Config())
func IsApiCall(config configservice.ConfigService, r *http.Request) bool {
subpath, _ := utils.GetSubpathFromConfig(config.Config())
return strings.HasPrefix(r.URL.Path, path.Join(subpath, "api")+"/")
}

Просмотреть файл

@@ -37,7 +37,8 @@ func StopTestStore() {
}
type TestHelper struct {
App *app.App
App *app.App
Server *app.Server
BasicUser *model.User
BasicChannel *model.Channel
@@ -47,10 +48,11 @@ type TestHelper struct {
}
func Setup() *TestHelper {
a, err := app.New(app.StoreOverride(testStore), app.DisableConfigWatch)
s, err := app.NewServer(app.StoreOverride(testStore), app.DisableConfigWatch)
if err != nil {
panic(err)
}
a := s.FakeApp()
prevListenAddress := *a.Config().ServiceSettings.ListenAddress
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
serverErr := a.StartServer()
@@ -59,7 +61,7 @@ func Setup() *TestHelper {
}
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
NewWeb(a, a.Srv.Router)
New(s, s.AppOptions, s.Router)
URL = fmt.Sprintf("http://localhost:%v", a.Srv.ListenAddr.Port)
ApiClient = model.NewAPIv4Client(URL)
@@ -73,7 +75,8 @@ func Setup() *TestHelper {
})
th := &TestHelper{
App: a,
App: a,
Server: s,
}
return th
@@ -98,7 +101,7 @@ func (th *TestHelper) InitBasic() *TestHelper {
}
func (th *TestHelper) TearDown() {
th.App.Shutdown()
th.Server.Shutdown()
if err := recover(); err != nil {
StopTestStore()
panic(err)