Refactor context out of API packages (#8755)

* Refactor context out of API packages

* Update function names per feedback

* Move webhook handlers to web and fix web tests

* Move more webhook tests out of api package

* Fix static handler
Этот коммит содержится в:
Joram Wilander
2018-05-14 10:24:58 -04:00
коммит произвёл GitHub
родитель 7e7c551987
Коммит 47250c6629
16 изменённых файлов: 708 добавлений и 611 удалений

158
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)
}
}
}