Repository: traefik/traefik
File: pkg/api/dashboard/dashboard.go (Go)

Code before:
type indexTemplateData struct {
	APIUrl string
}

// Handler expose dashboard routes.
type Handler struct {
	BasePath string

	assets fs.FS // optional assets, to override the webui.FS default
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	assets := h.assets
	if assets == nil {
		assets = webui.FS
	}

	// allow iframes from traefik domains only
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
	w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")

	// The content type must be guessed by the file server.
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
	w.Header().Del("Content-Type")

	if r.URL.Path == "/" {
		indexTemplate, err := template.ParseFS(assets, "index.html")
		if err != nil {
			log.Error().Err(err).Msg("Unable to parse index template")
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}

		apiPath := strings.TrimSuffix(h.BasePath, "/") + "/api/"
		if err = indexTemplate.Execute(w, indexTemplateData{APIUrl: apiPath}); err != nil {
			log.Error().Err(err).Msg("Unable to render index template")
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}

		return
	}

	http.FileServerFS(assets).ServeHTTP(w, r)
}

// Append adds dashboard routes on the given router, optionally using the given
// assets (or webui.FS otherwise).
func Append(router *mux.Router, basePath string, customAssets fs.FS) error {
	assets := customAssets
	if assets == nil {

Review comment (suggestion):
When testing using a `--api.insecure` I don't fall into this condition and end up with a non-templated `index.html`.

Code after:
	APIUrl string
}

// Handler expose dashboard routes.
type Handler struct {
	BasePath string

	assets fs.FS // optional assets, to override the webui.FS default
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	assets := h.assets
	if assets == nil {
		assets = webui.FS
	}

	// allow iframes from traefik domains only
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
	w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")

	// The content type must be guessed by the file server.
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
	w.Header().Del("Content-Type")

	if r.RequestURI == "/" {
		indexTemplate, err := template.ParseFS(assets, "index.html")
		if err != nil {
			log.Error().Err(err).Msg("Unable to parse index template")
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}

		apiPath := strings.TrimSuffix(h.BasePath, "/") + "/api/"
		if err = indexTemplate.Execute(w, indexTemplateData{APIUrl: apiPath}); err != nil {
			log.Error().Err(err).Msg("Unable to render index template")
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}

		return
	}

	http.FileServerFS(assets).ServeHTTP(w, r)
}

// Append adds dashboard routes on the given router, optionally using the given
// assets (or webui.FS otherwise).
func Append(router *mux.Router, basePath string, customAssets fs.FS) error {
	assets := customAssets
	if assets == nil {
		assets = webui.FS