diff --git a/src/main/java/hudson/remoting/Channel.java b/src/main/java/hudson/remoting/Channel.java index 86c508eb1..be0b7d675 100644 --- a/src/main/java/hudson/remoting/Channel.java +++ b/src/main/java/hudson/remoting/Channel.java @@ -1018,29 +1018,7 @@ public boolean preloadJar(ClassLoader local, URL... jars) throws IOException, In jars[i] = url; contents[i] = Util.readFully(url.openStream()); } - try { - return call(new PreloadJarTask2(jars, contents, local)); - } catch (IOException ex) { - if (ex.getCause() instanceof IllegalAccessError) { - logger.log( - Level.FINE, - ex, - () -> "Failed to call PreloadJarTask2 on " + this + ", retrying with PreloadJarTask"); - // When the agent is running an outdated version of remoting, we cannot access nonpublic classes in the - // same package, as PreloadJarTask2 would be loaded from the controller, and hence a different module/ - // classloader, than the rest of remoting. As a result PreloadJarTask2 will throw IllegalAccessError: - // - // java.lang.IllegalAccessError: failed to access class hudson.remoting.RemoteClassLoader from class - // hudson.remoting.PreloadJarTask2 (hudson.remoting.RemoteClassLoader is in unnamed module of loader - // 'app'; hudson.remoting.PreloadJarTask2 is in unnamed module of loader 'Jenkins v${project.version}' - // @795f104a) - // - // Identify this error here and fall back to PreloadJarTask, relying on the restrictive controller-side - // implementation of IClassLoader#fetchJar. - return call(new PreloadJarTask(jars, local)); - } - throw ex; - } + return call(new PreloadJarTask2(jars, contents, local)); } /** diff --git a/src/main/java/hudson/remoting/DumbClassLoaderBridge.java b/src/main/java/hudson/remoting/DumbClassLoaderBridge.java index 2e1944ab3..49ae12dcc 100644 --- a/src/main/java/hudson/remoting/DumbClassLoaderBridge.java +++ b/src/main/java/hudson/remoting/DumbClassLoaderBridge.java @@ -2,7 +2,6 @@ import edu.umd.cs.findbugs.annotations.NonNull; import java.io.IOException; -import java.net.URL; import java.util.Map; /** @@ -24,11 +23,6 @@ class DumbClassLoaderBridge implements RemoteClassLoader.IClassLoader { this.base = base; } - @Override - public byte[] fetchJar(URL url) throws IOException { - return base.fetchJar(url); - } - @Override public byte[] fetch(String className) throws ClassNotFoundException { return base.fetch(className); diff --git a/src/main/java/hudson/remoting/JarURLValidator.java b/src/main/java/hudson/remoting/JarURLValidator.java deleted file mode 100644 index 4e95f07d7..000000000 --- a/src/main/java/hudson/remoting/JarURLValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -package hudson.remoting; - -import java.io.IOException; -import java.net.URL; - -/** - * Validate a URL attempted to be read by the remote end (agent side). - * - * @deprecated Do not use, intended as a temporary workaround only. - */ -// TODO Remove once we no longer require compatibility with remoting before 2024-08. -@Deprecated -public interface JarURLValidator { - void validate(URL url) throws IOException; -} diff --git a/src/main/java/hudson/remoting/PreloadJarTask.java b/src/main/java/hudson/remoting/PreloadJarTask.java deleted file mode 100644 index e0f8dd754..000000000 --- a/src/main/java/hudson/remoting/PreloadJarTask.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package hudson.remoting; - -import edu.umd.cs.findbugs.annotations.CheckForNull; -import java.io.IOException; -import java.net.URL; -import org.jenkinsci.remoting.Role; -import org.jenkinsci.remoting.RoleChecker; - -/** - * {@link Callable} used to deliver a jar file to {@link RemoteClassLoader}. - * - * @author Kohsuke Kawaguchi - * @deprecated Retained for compatibility with pre-2024-08 remoting only (see {@link Channel#preloadJar(ClassLoader, java.net.URL...)}), use {@link hudson.remoting.PreloadJarTask2}. - */ -@Deprecated -final class PreloadJarTask implements DelegatingCallable { - /** - * Jar file to be preloaded. - */ - private final URL[] jars; - - // TODO: This implementation exists starting from - // https://github.com/jenkinsci/remoting/commit/f3d0a81fdf46a10c3c6193faf252efaeaee98823 - // Since this time nothing has blown up, but it still seems to be suspicious. - // The solution for null classloaders is available in RemoteDiagnostics.Script#call() in the Jenkins core codebase - @CheckForNull - private transient ClassLoader target = null; - - PreloadJarTask(URL[] jars, @CheckForNull ClassLoader target) { - this.jars = jars; - this.target = target; - } - - @Override - public ClassLoader getClassLoader() { - return target; - } - - @Override - public Boolean call() throws IOException { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (!(cl instanceof RemoteClassLoader)) { - return false; - } - - RemoteClassLoader rcl = (RemoteClassLoader) cl; - boolean r = false; - for (URL jar : jars) { - r |= rcl.prefetch(jar); - } - return r; - } - - /** - * This task is only useful in the context that allows remote classloading, and by that point - * any access control check is pointless. So just declare the worst possible role. - */ - @Override - public void checkRoles(RoleChecker checker) throws SecurityException { - checker.check(this, Role.UNKNOWN); - } - - private static final long serialVersionUID = -773448303394727271L; -} diff --git a/src/main/java/hudson/remoting/PreloadJarTask2.java b/src/main/java/hudson/remoting/PreloadJarTask2.java index 1f76b5b90..4e2fbbcba 100644 --- a/src/main/java/hudson/remoting/PreloadJarTask2.java +++ b/src/main/java/hudson/remoting/PreloadJarTask2.java @@ -31,10 +31,6 @@ /** * {@link Callable} used to deliver a jar file to {@link RemoteClassLoader}. - *

- * This replaces {@link hudson.remoting.PreloadJarTask} and delivers the jar contents as part of the Callable rather - * than needing to call {@link hudson.remoting.RemoteClassLoader#prefetch(java.net.URL)}. - *

* @since TODO 2024-08 */ final class PreloadJarTask2 implements DelegatingCallable { diff --git a/src/main/java/hudson/remoting/RemoteClassLoader.java b/src/main/java/hudson/remoting/RemoteClassLoader.java index 83eabda71..3dd44ba99 100644 --- a/src/main/java/hudson/remoting/RemoteClassLoader.java +++ b/src/main/java/hudson/remoting/RemoteClassLoader.java @@ -675,33 +675,6 @@ public static void deleteDirectoryOnExit(File dir) { Util.deleteDirectoryOnExit(dir); } - /** - * Prefetches the jar into this class loader. - * - * @param jar Jar to be prefetched. Note that this file is an file on the other end, - * and doesn't point to anything meaningful locally. - * @return true if the prefetch happened. false if the jar is already prefetched. - * @deprecated Only left in for compatibility with pre-2024-08 remoting. Use {@link #prefetch(java.net.URL, byte[])} instead. - * @see Channel#preloadJar(Callable, Class[]) - * @see hudson.remoting.PreloadJarTask - * @see hudson.remoting.PreloadJarTask2 - */ - @Deprecated - /*package*/ boolean prefetch(URL jar) throws IOException { - synchronized (prefetchedJars) { - if (prefetchedJars.contains(jar)) { - return false; - } - - String p = jar.getPath().replace('\\', '/'); - p = Util.getBaseName(p); - File localJar = Util.makeResource(p, proxy.fetchJar(jar)); - addURL(localJar.toURI().toURL()); - prefetchedJars.add(jar); - return true; - } - } - /** * Prefetches the specified jar with the specified content into this classloader. * @param jar Jar to be prefetched. Note that this file is an file on the other end, @@ -873,9 +846,6 @@ public static class ClassFile2 extends ResourceFile { * Remoting interface. */ public interface IClassLoader { - @Deprecated - byte[] fetchJar(URL url) throws IOException; - /** * Retrieves the bytecode of a class. */ @@ -998,31 +968,6 @@ public ClassLoaderProxy(@NonNull ClassLoader cl, Channel channel) { this.channel = channel; } - @Override - @SuppressFBWarnings( - value = "URLCONNECTION_SSRF_FD", - justification = "URL validation is being done through JarURLValidator") - public byte[] fetchJar(URL url) throws IOException { - final Object o = channel.getProperty(JarURLValidator.class); - if (o == null) { - final boolean disabled = Boolean.getBoolean(Channel.class.getName() + ".DISABLE_JAR_URL_VALIDATOR"); - LOGGER.log(Level.FINE, "Default behavior for URL: " + url + " with disabled flag: " + disabled); - if (!disabled) { - throw new IOException( - "No hudson.remoting.JarURLValidator has been set for this channel, so all #fetchJar calls are rejected." - + " This is likely a bug in Jenkins." - + " As a workaround, try updating the agent.jar file."); - } - } else { - if (o instanceof JarURLValidator) { - ((JarURLValidator) o).validate(url); - } else { - throw new IOException("Unexpected channel property hudson.remoting.JarURLValidator value: " + o); - } - } - return Util.readFully(url.openStream()); - } - @Override public byte[] fetch(String className) throws ClassNotFoundException { if (!USE_BOOTSTRAP_CLASSLOADER && cl == PSEUDO_BOOTSTRAP) { @@ -1316,11 +1261,6 @@ private RemoteIClassLoader(int oid, IClassLoader proxy) { this.oid = oid; } - @Override - public byte[] fetchJar(URL url) throws IOException { - return proxy.fetchJar(url); - } - @Override public byte[] fetch(String className) throws ClassNotFoundException { return proxy.fetch(className); @@ -1398,11 +1338,6 @@ public Map fetch3(String className) throws ClassNotFoundExce throw new ClassNotFoundException(className, cause); } - @Override - public byte[] fetchJar(URL url) throws IOException { - throw new IOException("Cannot fetch " + url, cause); - } - @Override public byte[] getResource(String name) throws IOException { throw new IOException("Cannot get " + name, cause);