From 14cdfc77da479cfd8c95708311000ce53bf22b31 Mon Sep 17 00:00:00 2001 From: Jonah Back Date: Thu, 7 Apr 2022 10:15:23 -0400 Subject: [PATCH] feat: add caching to application js bundle since it has a unique name (#9008) * feat: add caching to application js bundle since it has a unique name Signed-off-by: Jonah Back * chore: simplify check and add tests Signed-off-by: Michael Crenshaw Co-authored-by: Michael Crenshaw --- server/server.go | 11 ++++++++++ server/server_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/server/server.go b/server/server.go index 5a273f005ca61..ad2f71649cb72 100644 --- a/server/server.go +++ b/server/server.go @@ -11,6 +11,7 @@ import ( "net/url" "os" "os/exec" + "path" "reflect" "regexp" go_runtime "runtime" @@ -910,11 +911,21 @@ func (server *ArgoCDServer) newStaticAssetsHandler() func(http.ResponseWriter, * } http.ServeContent(w, r, "index.html", modTime, io.NewByteReadSeeker(data)) } else { + if isMainJsBundle(r.URL) { + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") + } http.FileServer(server.staticAssets).ServeHTTP(w, r) } } } +var mainJsBundleRegex = regexp.MustCompile(`^main\.[0-9a-f]{20}\.js$`) + +func isMainJsBundle(url *url.URL) bool { + filename := path.Base(url.Path) + return mainJsBundleRegex.Match([]byte(filename)) +} + type registerFunc func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) error // mustRegisterGWHandler is a convenience function to register a gateway handler diff --git a/server/server_test.go b/server/server_test.go index 59eaa4f4e3564..4cc5e715edf1f 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http/httptest" + "net/url" "strings" "testing" "time" @@ -673,3 +674,51 @@ func TestOIDCConfigChangeDetection_NoChange(t *testing.T) { //Then assert.Equal(t, result, false, "no error since no config change") } + +func TestIsMainJsBundle(t *testing.T) { + testCases := []struct{ + name string + url string + isMainJsBundle bool + }{ + { + name: "localhost with valid main bundle", + url: "https://localhost:8080/main.e4188e5adc97bbfc00c3.js", + isMainJsBundle: true, + }, + { + name: "localhost and deep path with valid main bundle", + url: "https://localhost:8080/some/argo-cd-instance/main.e4188e5adc97bbfc00c3.js", + isMainJsBundle: true, + }, + { + name: "font file", + url: "https://localhost:8080/assets/fonts/google-fonts/Heebo-Bols.woff2", + isMainJsBundle: false, + }, + { + name: "no dot after main", + url: "https://localhost:8080/main/e4188e5adc97bbfc00c3.js", + isMainJsBundle: false, + }, + { + name: "wrong extension character", + url: "https://localhost:8080/main.e4188e5adc97bbfc00c3/js", + isMainJsBundle: false, + }, + { + name: "wrong hash length", + url: "https://localhost:8080/main.e4188e5adc97bbfc00c3abcdefg.js", + isMainJsBundle: false, + }, + } + for _, testCase := range testCases { + testCaseCopy := testCase + t.Run(testCaseCopy.name, func(t *testing.T) { + t.Parallel() + testUrl, _ := url.Parse(testCaseCopy.url) + isMainJsBundle := isMainJsBundle(testUrl) + assert.Equal(t, testCaseCopy.isMainJsBundle, isMainJsBundle) + }) + } +}