hunk.code_window: 			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))
  
hunk.labels: keep keep keep keep replace keep keep keep keep
hunk.after_edit: 	subpath, _ := utils.GetSubpathFromConfig(c.App.Config())
   	siteURLHeader := app.GetProtocol(r) + "://" + r.Host + subpath
   	c.SetSiteURLHeader(siteURLHeader)
  
hunk.file_path: web/handlers.go
hunk.type: replace
file: // 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)
  	c.Path = r.URL.Path
  	c.Log = c.App.Log
  
  	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 {
  			c.Log.Info("Invalid session", mlog.Err(err))
  			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.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("method", r.Method),
  	)
  
  	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 = ""
  		}
  
  		// Sanitize all 5xx error messages in hardened mode
  		if *c.App.Config().ServiceSettings.ExperimentalEnableHardenedMode && c.Err.StatusCode >= 500 {
  			c.Err.Id = ""
  			c.Err.Message = "Internal Server Error"
  			c.Err.DetailedError = ""
  			c.Err.StatusCode = 500
  			c.Err.Where = ""
  			c.Err.IsOAuth = false
  		}
  
  		if IsApiCall(c.App, r) || IsWebhookCall(c.App, r) || len(r.Header.Get("X-Mobile-App")) > 0 {
  			w.WriteHeader(c.Err.StatusCode)
  			w.Write([]byte(c.Err.ToJson()))
  		} else {
  			utils.RenderWebAppError(c.App.Config(), w, r, c.Err, c.App.AsymmetricSigningKey())
  		}
  
  		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)
  		}
  	}
  }
  