8264048: Fix caching in Jar URL connections when an entry is missing

Co-authored-by: Daniel Fuchs <dfuchs@openjdk.org>
Reviewed-by: bchristi, dfuchs
This commit is contained in:
Aleksei Efimov 2021-04-06 10:43:59 +00:00
parent bf26a2558f
commit a611c462f9
6 changed files with 371 additions and 27 deletions

View file

@ -71,17 +71,99 @@ class JarFileFactory implements URLJarFile.URLJarFileCloseController {
return get(url, true);
}
JarFile get(URL url, boolean useCaches) throws IOException {
/**
* Get or create a {@code JarFile} for the given {@code url}.
* If {@code useCaches} is true, this method attempts to find
* a jar file in the cache, and if so, returns it.
* If no jar file is found in the cache, or {@code useCaches}
* is false, the method creates a new jar file.
* If the URL points to a local file, the returned jar file
* will not be put in the cache yet.
* The caller should then call {@link #cacheIfAbsent(URL, JarFile)}
* with the returned jar file, if updating the cache is desired.
* @param url the jar file url
* @param useCaches whether the cache should be used
* @return a new or cached jar file.
* @throws IOException if the jar file couldn't be created
*/
JarFile getOrCreate(URL url, boolean useCaches) throws IOException {
if (useCaches == false) {
return get(url, false);
}
URL patched = urlFor(url);
if (!URLJarFile.isFileURL(patched)) {
// A temporary file will be created, we can prepopulate
// the cache in this case.
return get(url, useCaches);
}
// We have a local file. Do not prepopulate the cache.
JarFile result;
synchronized (instance) {
result = getCachedJarFile(patched);
}
if (result == null) {
result = URLJarFile.getJarFile(patched, this);
}
if (result == null)
throw new FileNotFoundException(url.toString());
return result;
}
/**
* Close the given jar file if it isn't present in the cache.
* Otherwise, does nothing.
* @param url the jar file URL
* @param jarFile the jar file to close
* @return true if the jar file has been closed, false otherwise.
* @throws IOException if an error occurs while closing the jar file.
*/
boolean closeIfNotCached(URL url, JarFile jarFile) throws IOException {
url = urlFor(url);
JarFile result;
synchronized (instance) {
result = getCachedJarFile(url);
}
if (result != jarFile) jarFile.close();
return result != jarFile;
}
boolean cacheIfAbsent(URL url, JarFile jarFile) {
try {
url = urlFor(url);
} catch (IOException x) {
// should not happen
return false;
}
JarFile cached;
synchronized (instance) {
String key = urlKey(url);
cached = fileCache.get(key);
if (cached == null) {
fileCache.put(key, jarFile);
urlCache.put(jarFile, url);
}
}
return cached == null || cached == jarFile;
}
private URL urlFor(URL url) throws IOException {
if (url.getProtocol().equalsIgnoreCase("file")) {
// Deal with UNC pathnames specially. See 4180841
String host = url.getHost();
if (host != null && !host.isEmpty() &&
!host.equalsIgnoreCase("localhost")) {
!host.equalsIgnoreCase("localhost")) {
url = new URL("file", "", "//" + host + url.getPath());
}
}
return url;
}
JarFile get(URL url, boolean useCaches) throws IOException {
url = urlFor(url);
JarFile result;
JarFile local_result;
@ -116,7 +198,7 @@ class JarFileFactory implements URLJarFile.URLJarFileCloseController {
/**
* Callback method of the URLJarFileCloseController to
* indicate that the JarFile is close. This way we can
* indicate that the JarFile is closed. This way we can
* remove the JarFile from the cache
*/
public void close(JarFile jarFile) {