From e9e1703184abfafcd6f1e784b46461d10cb31480 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 20 Jul 2021 16:00:18 -0700 Subject: [PATCH] GUACAMOLE-275: Automatically attempt to refresh browser cache if index.html does not match current build. --- guacamole/pom.xml | 2 + guacamole/src/main/frontend/src/index.html | 5 +- .../main/frontend/src/verifyCachedVersion.js | 85 +++++++++++++++++++ guacamole/src/main/frontend/webpack.config.js | 3 +- .../guacamole/extension/ExtensionModule.java | 4 + pom.xml | 22 ++++- 6 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 guacamole/src/main/frontend/src/verifyCachedVersion.js diff --git a/guacamole/pom.xml b/guacamole/pom.xml index 24cc59ed9..32f434520 100644 --- a/guacamole/pom.xml +++ b/guacamole/pom.xml @@ -154,6 +154,7 @@ translations/*.json index.html + verifyCachedVersion.js @@ -164,6 +165,7 @@ translations/*.json index.html + verifyCachedVersion.js diff --git a/guacamole/src/main/frontend/src/index.html b/guacamole/src/main/frontend/src/index.html index 9dab9ba36..7f007eb55 100644 --- a/guacamole/src/main/frontend/src/index.html +++ b/guacamole/src/main/frontend/src/index.html @@ -24,6 +24,7 @@ + @@ -34,7 +35,7 @@ <% } %> - + @@ -105,7 +106,7 @@ - + diff --git a/guacamole/src/main/frontend/src/verifyCachedVersion.js b/guacamole/src/main/frontend/src/verifyCachedVersion.js new file mode 100644 index 000000000..db9e14409 --- /dev/null +++ b/guacamole/src/main/frontend/src/verifyCachedVersion.js @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Automatically reloads the current page and clears relevant browser cache if + * the build that produced index.html is different/older than the build that + * produced the JavaScript loaded by index.html. + * + * @private + * @param {Location} location + * The Location object representing the URL of the current page. + * + * @param {Storate} [sessionStorage] + * The Storage object that should optionally be used to avoid reloading the + * current page in a loop if it proves impossible to clear cache. + */ +(function verifyCachedVersion(location, sessionStorage) { + + /** + * The meta element containing the build identifier of the Guacamole build + * that produced index.html. + * + * @private + * @type {HTMLMetaElement} + */ + var buildMeta = document.head.querySelector('meta[name=build]'); + + // Verify that index.html came from the same build as this JavaScript file, + // forcing a reload if out-of-date + if (!buildMeta || buildMeta.content !== '${guacamole.build.identifier}') { + + if (sessionStorage) { + + // Bail out if we have already tried to automatically refresh the + // cache but were unsuccessful + if (sessionStorage.getItem('reloadedFor') === '${guacamole.build.identifier}') { + console.warn('The version of Guacamole cached by your ' + + 'browser does not match the version of Guacamole on the ' + + 'server. To avoid unexpected errors, please clear your ' + + 'browser cache.'); + return; + } + + sessionStorage.setItem('reloadedFor', '${guacamole.build.identifier}'); + + } + + // Force refresh of cache by issuing an HTTP request with headers that + // request revalidation of cached content + var xhr = new XMLHttpRequest(); + xhr.open('GET', '', true); + xhr.setRequestHeader('Cache-Control', 'no-cache'); + xhr.setRequestHeader('Pragma', 'no-cache'); + + xhr.onreadystatechange = function readyStateChanged() { + + // Reload current page when ready (this call to reload MAY be + // sufficient in itself to clear cache, but this is not + // guaranteed by any standard) + if (xhr.readyState === XMLHttpRequest.DONE) + location.reload(true); + + }; + + xhr.send(); + + } + +})(window.location, window.sessionStorage); diff --git a/guacamole/src/main/frontend/webpack.config.js b/guacamole/src/main/frontend/webpack.config.js index aa337fbb5..29bb8ddd5 100644 --- a/guacamole/src/main/frontend/webpack.config.js +++ b/guacamole/src/main/frontend/webpack.config.js @@ -121,7 +121,8 @@ module.exports = { { from: 'fonts/**/*' }, { from: 'images/**/*' }, { from: 'layouts/**/*' }, - { from: 'translations/**/*' } + { from: 'translations/**/*' }, + { from: 'verifyCachedVersion.js' } ], { context: 'src/' }), diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index d66d5f455..d5aedb005 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -41,6 +41,7 @@ import org.apache.guacamole.properties.StringSetProperty; import org.apache.guacamole.resource.Resource; import org.apache.guacamole.resource.ResourceServlet; import org.apache.guacamole.resource.SequenceResource; +import org.apache.guacamole.resource.WebApplicationResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -598,6 +599,9 @@ public class ExtensionModule extends ServletModule { Collection javaScriptResources = new ArrayList(); Collection cssResources = new ArrayList(); + // Veriffy that the possibly-cached index.html matches the current build + javaScriptResources.add(new WebApplicationResource(getServletContext(), "/verifyCachedVersion.js")); + // Load all extensions final Set toleratedAuthProviders = getToleratedAuthenticationProviders(); loadExtensions(javaScriptResources, cssResources, toleratedAuthProviders); diff --git a/pom.xml b/pom.xml index e384ad9cc..0480d5bf1 100644 --- a/pom.xml +++ b/pom.xml @@ -115,19 +115,37 @@ - org.codehaus.mojo build-helper-maven-plugin 3.2.0 + + define-project-root rootlocation + + + + define-build-timestamp + + guacamole.build.identifier + build + yyyyMMddHHmmss + + + timestamp-property + + +