Previously, a Zip64 jar file was identified by the number of entries
in the central directory being 0xFFFF. This value indicates that
there the number of entries is too big for the 2-byte field. However,
a jar may be in Zip64 format due to it exceeding the Zip format's
maximum size rather than its maximum number of entries so this field
cannot be used as a reliable indicator. The Zip specification doesn't
require any of the fields of the end of central directory record to
have a value of 0xFFFF (2-byte fields) or 0xFFFFFFFF (4-byte fields)
when using Zip64 format so we need to take a different approach.
Additionally, a number of places in the code assumed that an entry's
offset would always be available from the central directory file
header directly. This assumption did not hold true when the jar was
a Zip64 archive due to its size as the offset's value would be
0xFFFFFFF indicating that it should be read from the Zip64 extended
information field within the header's extra field instead.
This commit updates the Zip64 detection to look for the Zip64 end of
central directory locator instead. If present, it begins 20 bytes
before the beginning of the end of central directory record. Its
first four bytes are always 0x07064b50. The code that reads the
local header offset has also been updated to refer to the Zip64
extended information field when the offset is too large to fit in
the 4-byte field in the central directory file header. To allow
greater-than-4-byte offsets to be handled, a number of fields,
method parameters, and local variables have had their type changed
from an int to a long.
Fixes gh-27822
Update `JarFile` and `JarFileWrapper` classes so that they no longer
close the `JarFile` early if a `SecurityManager` is in use.
Prior to this commit, the closed `JarFile` would cause (an ultimately
swallowed) NPE in `ZipFile` which manifested itself as a
`ClassNotFoundException` when starting the app.
Closes gh-25538
Update jar `Handler` fallback logic to directly support Tomcat
'jar:war:file' URLs. This commit allows contents to be accessed without
the JDK needing to extracted the nested jar to the temporary folder.
Closes gh-24553
Update the jar `Handler` class to support a non-reflective fallback
mechanism when possible. The updated code attempts to capture a regular
jar URL before our handler is installed. It can then use that URL as
context when creating the a fallback URL. The JDK jar `Handler` will
be copied from the context URL to the fallback URL.
Without this commit, resolving new Tomcat URLs of the form
`jar:war:file:...` would result in an ugly "Illegal reflective access"
warning.
Fixes gh-18631
Update `JarFileEntries` so that the interface is obtained rather than
the concrete implementation. This allows `JarEntry` values to be used
without causing a ClassCastException.
Closes gh-19041
Update the performance improvements to push certificate loading
and storage into the `JarFileEntries` class. This allows us to
keep certificates without needing to cache all entry data. We
now also keep certificates and code signers in a dedicated class
which is set whenever the full jar stream as been read, even if
the contained values are `null`. The logic that assumes META-INF
entries are not signed has been removed in favor of delegating to
the streamed entry results.
See gh-19041
Update Spring Boot nested JarFile support to improve the performance of
signed jars. Prior to this commit, `certificates` and `codeSigners`
were read by streaming the entire jar whenever the existing values
were `null`. Unfortunately, the contract for `getCertificates` and
get `getCodeSigners` states that `null` is a valid return value. This
meant that full jar streaming would occur whenever either method was
called on an entry that had no result. The problem was further
exacerbated by the fact that entries might not be cached.
See gh-19041
Previously, PropertiesLauncher would close each archive that it
iterated over when creating its ClassLoader. This was not aligned
with JarLauncher's behaviour and left the ClassLoader with closed
archives. The close was introduced in [1] and became more apparent
following the change to fail operations on closed archives [2].
This commit updates Launcher to remove the close() that was added in
[1]. This aligns the behavior of PropertiesLauncher with JarLauncher
and ensures that the ClassLoader does not have entries backed by
closed archives on its classpath.
Fixes gh-23165
[1] ad72f86bdb
[2] ed7a5db174
Create a new `JarFileWrapper` class so that we can wrap and existing
`JarFile` and offer a version that can be safely closed.
Prior to this commit, we provided wrapper functionality in the `JarFile`
class itself. Unfortunately, because we override `close` and also create
a lot of wrappers this caused memory issues when running on Java 11.
With Java 11 `java.util.zip.ZipFile` class uses `FinalizableResource`
for any implementation that overrides `close()`. This means that any
wrapper classes will not be garbage collected until the JVM finalizer
thread runs.
Closes gh-22991
Update `LaunchedURLClassLoader` so that packages defined from exploded
archive folders have manifest attributes applied to them. Prior to this
calling `package.getImplementationTitle()` would only return the a
manifiest attribute when running non-exploded.
The root cause of this issue is the way that `URLClassLoader` handles
the different URL types. For URLs that reference a jar the manifest is
available. For URLs that reference a folder it isn't. When running
exploded we use a URL that references to the `BOOT-INF/classes` folder
directly. To fix the issue we now attempt to detect when `definePackage`
is being called directly, and replace `null` entries with actual
manifest values.
Fixes gh-21705