summaryrefslogtreecommitdiffstats
path: root/web/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'web/handlers.go')
-rw-r--r--web/handlers.go158
1 files changed, 158 insertions, 0 deletions
diff --git a/web/handlers.go b/web/handlers.go
new file mode 100644
index 000000000..e2521674a
--- /dev/null
+++ b/web/handlers.go
@@ -0,0 +1,158 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package web
+
+import (
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/mattermost/mattermost-server/app"
+ "github.com/mattermost/mattermost-server/mlog"
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/utils"
+)
+
+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,
+ }
+}
+
+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,
+ }
+}
+
+type Handler struct {
+ App *app.App
+ 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) {
+ now := time.Now()
+ 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.Params = ParamsFromRequest(r)
+
+ token, tokenLocation := app.ParseAuthTokenFromRequest(r)
+
+ // CSRF Check
+ if tokenLocation == app.TokenLocationCookie && h.RequireSession && !h.TrustRequester {
+ if r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML {
+ c.Err = model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to be a CSRF attempt", http.StatusUnauthorized)
+ token = ""
+ }
+ }
+
+ c.SetSiteURLHeader(app.GetProtocol(r) + "://" + r.Host)
+
+ w.Header().Set(model.HEADER_REQUEST_ID, c.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 h.IsStatic {
+ // Instruct the browser not to display us in an iframe unless is the same origin for anti-clickjacking
+ w.Header().Set("X-Frame-Options", "SAMEORIGIN")
+ w.Header().Set("Content-Security-Policy", "frame-ancestors 'self'")
+ } else {
+ // All api response bodies will be JSON formatted by default
+ w.Header().Set("Content-Type", "application/json")
+
+ if r.Method == "GET" {
+ w.Header().Set("Expires", "0")
+ }
+ }
+
+ if len(token) != 0 {
+ session, err := c.App.GetSession(token)
+
+ if err != nil {
+ mlog.Info(fmt.Sprintf("Invalid session err=%v", err.Error()))
+ if err.StatusCode == http.StatusInternalServerError {
+ c.Err = err
+ } else if h.RequireSession {
+ c.RemoveSessionCookie(w, r)
+ c.Err = model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token, http.StatusUnauthorized)
+ }
+ } 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
+ }
+
+ // Rate limit by UserID
+ if c.App.Srv.RateLimiter != nil && c.App.Srv.RateLimiter.UserIdRateLimit(c.Session.UserId, w) {
+ return
+ }
+ }
+
+ c.Path = r.URL.Path
+
+ if c.Err == nil && h.RequireSession {
+ c.SessionRequired()
+ }
+
+ if c.Err == nil && h.RequireMfa {
+ c.MfaRequired()
+ }
+
+ if c.Err == nil {
+ h.HandleFunc(c, w, r)
+ }
+
+ // Handle errors that have occurred
+ if c.Err != nil {
+ c.Err.Translate(c.T)
+ c.Err.RequestId = c.RequestId
+
+ if c.Err.Id == "api.context.session_expired.app_error" {
+ c.LogInfo(c.Err)
+ } else {
+ c.LogError(c.Err)
+ }
+
+ c.Err.Where = r.URL.Path
+
+ // Block out detailed error when not in developer mode
+ if !*c.App.Config().ServiceSettings.EnableDeveloper {
+ c.Err.DetailedError = ""
+ }
+
+ w.WriteHeader(c.Err.StatusCode)
+ w.Write([]byte(c.Err.ToJson()))
+
+ if c.App.Metrics != nil {
+ c.App.Metrics.IncrementHttpError()
+ }
+ }
+
+ if c.App.Metrics != nil {
+ c.App.Metrics.IncrementHttpRequest()
+
+ if r.URL.Path != model.API_URL_SUFFIX+"/websocket" {
+ elapsed := float64(time.Since(now)) / float64(time.Second)
+ c.App.Metrics.ObserveHttpRequestDuration(elapsed)
+ }
+ }
+}