MM-57839: Rewrite static assets only if needed (#27076)

* Rewrite static assets only if needed

Refactor UpdateAssetsSubpathInDir so that the actual rewriting of files
happen in two different functions: one for root.html, another for
manifest.json and *.css files.

I would have wanted to simply do a

  if pathToReplace == newPath { return nil }

when those two variables are defined, but the logic for root.html is not
that simple, and that may miss some edge cases, so I opted out for
simply moving the actual rewriting to individual functions, which check
for their corresponding conditions to perform the update:
  1. for root.html, check that the edited file is indeed different than
     the original one
  2. for manifest.json and *.css files, rewrite them only if
     pathToReplace != newPath, which in this case is clear that that's the
     only modification we do

* Fix expected error msg in test

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Alejandro García Montoro 2024-06-13 12:01:57 +02:00 committed by GitHub
parent bf8ddb4bdc
commit d81ce03168
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 37 additions and 7 deletions

View File

@ -51,16 +51,17 @@ func UpdateAssetsSubpathInDir(subpath, directory string) error {
subpath = "/"
}
// Resolve the static directory
staticDir, found := fileutils.FindDir(directory)
if !found {
return errors.New("failed to find client dir")
}
staticDir, err := filepath.EvalSymlinks(staticDir)
if err != nil {
return errors.Wrapf(err, "failed to resolve symlinks to %s", staticDir)
}
// Read the old root.html file
rootHTMLPath := filepath.Join(staticDir, "root.html")
oldRootHTML, err := os.ReadFile(rootHTMLPath)
if err != nil {
@ -77,12 +78,25 @@ func UpdateAssetsSubpathInDir(subpath, directory string) error {
alreadyRewritten = true
}
// Determine the old and new paths
pathToReplace := path.Join(oldSubpath, "static") + "/"
newPath := path.Join(subpath, "static") + "/"
mlog.Debug("Rewriting static assets", mlog.String("from_subpath", oldSubpath), mlog.String("to_subpath", subpath))
// Update the root.html file
if err := updateRootFile(string(oldRootHTML), rootHTMLPath, alreadyRewritten, pathToReplace, newPath, subpath); err != nil {
return fmt.Errorf("failed to update root.html: %w", err)
}
newRootHTML := string(oldRootHTML)
// Update the manifest.json and *.css files
if err := updateManifestAndCSSFiles(staticDir, pathToReplace, newPath, subpath); err != nil {
return fmt.Errorf("failed to update manifest.json and *.css files: %w", err)
}
return nil
}
func updateRootFile(oldRootHTML string, rootHTMLPath string, alreadyRewritten bool, pathToReplace, newPath, subpath string) error {
newRootHTML := oldRootHTML
reCSP := regexp.MustCompile(`<meta http-equiv="Content-Security-Policy" content="script-src 'self' cdn.rudderlabs.com/ js.stripe.com/v3([^"]*)">`)
if results := reCSP.FindAllString(newRootHTML, -1); len(results) == 0 {
@ -110,13 +124,29 @@ func UpdateAssetsSubpathInDir(subpath, directory string) error {
newRootHTML = strings.Replace(newRootHTML, "</style>", fmt.Sprintf("</style><script>%s</script>", script), 1)
}
if newRootHTML == oldRootHTML {
mlog.Debug("No need to rewrite unmodified root.html", mlog.String("from_subpath", pathToReplace), mlog.String("to_subpath", newPath))
return nil
}
mlog.Debug("Rewriting root.html", mlog.String("from_subpath", pathToReplace), mlog.String("to_subpath", newPath))
// Write out the updated root.html.
if err = os.WriteFile(rootHTMLPath, []byte(newRootHTML), 0); err != nil {
if err := os.WriteFile(rootHTMLPath, []byte(newRootHTML), 0); err != nil {
return errors.Wrapf(err, "failed to update root.html with subpath %s", subpath)
}
return nil
}
func updateManifestAndCSSFiles(staticDir, pathToReplace, newPath, subpath string) error {
if pathToReplace == newPath {
mlog.Debug("No need to rewrite unmodified manifest.json and *.css files", mlog.String("from_subpath", pathToReplace), mlog.String("to_subpath", newPath))
return nil
}
mlog.Debug("Rewriting manifest.json and *.css files", mlog.String("from_subpath", pathToReplace), mlog.String("to_subpath", newPath))
// Rewrite the manifest.json and *.css references to `/static/*` (or a previously rewritten subpath).
err = filepath.Walk(staticDir, func(walkPath string, info os.FileInfo, err error) error {
err := filepath.Walk(staticDir, func(walkPath string, info os.FileInfo, err error) error {
if filepath.Base(walkPath) == "manifest.json" || filepath.Ext(walkPath) == ".css" {
old, err := os.ReadFile(walkPath)
if err != nil {

View File

@ -109,7 +109,7 @@ func TestUpdateAssetsSubpath(t *testing.T) {
baseCSS,
baseManifestJSON,
"/subpath",
fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite"),
fmt.Errorf("failed to update root.html: %w", fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite")),
contentSecurityPolicyNotFoundHTML,
baseCSS,
baseManifestJSON,
@ -120,7 +120,7 @@ func TestUpdateAssetsSubpath(t *testing.T) {
baseCSS,
baseManifestJSON,
"/subpath",
fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite"),
fmt.Errorf("failed to update root.html: %w", fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite")),
contentSecurityPolicyNotFound2HTML,
baseCSS,
baseManifestJSON,