diff --git a/.gitpod/Dockerfile b/.gitpod/Dockerfile index 6b71c6707163..f2475612b107 100644 --- a/.gitpod/Dockerfile +++ b/.gitpod/Dockerfile @@ -1,6 +1,6 @@ FROM gitpod/workspace-full -ARG MAVEN_VERSION=3.9.6 +ARG MAVEN_VERSION=3.9.7 RUN brew install gh && \ bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && sdk install maven ${MAVEN_VERSION} && sdk default maven ${MAVEN_VERSION}" diff --git a/ath.sh b/ath.sh index 8bde184008c4..3ab8d159b66e 100644 --- a/ath.sh +++ b/ath.sh @@ -6,7 +6,7 @@ set -o xtrace cd "$(dirname "$0")" # https://github.com/jenkinsci/acceptance-test-harness/releases -export ATH_VERSION=5829.v1ea_976c1636e +export ATH_VERSION=5858.v4b_c4e3b_16099 if [[ $# -eq 0 ]]; then export JDK=17 diff --git a/bom/pom.xml b/bom/pom.xml index 4d4ae6622938..d3aed901a32b 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -38,8 +38,9 @@ THE SOFTWARE. The module contains dependencies that are used by a specific Jenkins version + 2.0.0-M2 2.0.13 - 1860.vb_89682cf8d96 + 1869.v3605a_771fb_e3 2.4.21 @@ -55,7 +56,7 @@ THE SOFTWARE. org.springframework spring-framework-bom - 5.3.35 + 5.3.36 pom import @@ -119,11 +120,6 @@ THE SOFTWARE. commons-collections 3.2.2 - - commons-fileupload - commons-fileupload - 1.5 - commons-io commons-io @@ -149,6 +145,11 @@ THE SOFTWARE. jenkins-stapler-support 1.1 + + jakarta.servlet + jakarta.servlet-api + 4.0.4 + jakarta.servlet.jsp.jstl jakarta.servlet.jsp.jstl-api @@ -189,6 +190,41 @@ THE SOFTWARE. commons-compress 1.26.1 + + org.apache.commons + commons-fileupload2 + ${commons-fileupload2.version} + + + org.apache.commons + commons-fileupload2-core + ${commons-fileupload2.version} + + + org.apache.commons + commons-fileupload2-distribution + ${commons-fileupload2.version} + + + org.apache.commons + commons-fileupload2-jakarta-servlet5 + ${commons-fileupload2.version} + + + org.apache.commons + commons-fileupload2-jakarta-servlet6 + ${commons-fileupload2.version} + + + org.apache.commons + commons-fileupload2-javax + ${commons-fileupload2.version} + + + org.apache.commons + commons-fileupload2-portlet + ${commons-fileupload2.version} + org.codehaus.groovy groovy-all diff --git a/core/pom.xml b/core/pom.xml index faef477b9cd2..61c48e489794 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -160,10 +160,6 @@ THE SOFTWARE. commons-collections commons-collections - - commons-fileupload - commons-fileupload - commons-io commons-io @@ -284,6 +280,14 @@ THE SOFTWARE. + + org.apache.commons + commons-fileupload2-core + + + org.apache.commons + commons-fileupload2-javax + org.codehaus.groovy groovy-all @@ -439,7 +443,6 @@ THE SOFTWARE. jakarta.servlet jakarta.servlet-api - 4.0.4 provided diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index 10b0d179fdd7..d9b37f0fac29 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -52,6 +52,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; @@ -235,7 +236,11 @@ private static Manifest loadLinkedManifest(File archive) throws IOException { dependencyLoader = getBaseClassLoader(atts, dependencyLoader); return new PluginWrapper(pluginManager, archive, manifest, baseResourceURL, - createClassLoader(paths, dependencyLoader, atts), disableFile, dependencies, optionalDependencies); + createClassLoader(computeClassLoaderName(manifest, archive), paths, dependencyLoader, atts), disableFile, dependencies, optionalDependencies); + } + + private static String computeClassLoaderName(Manifest mf, File archive) { + return "PluginClassLoader for " + PluginWrapper.computeShortName(mf, archive.getName()); } private void fix(Attributes atts, List optionalDependencies) { @@ -263,15 +268,28 @@ public static List getImpliedDependencies(String plugi return DetachedPluginsUtil.getImpliedDependencies(pluginName, jenkinsVersion); } - @Deprecated + /** + * @deprecated since TODO use {@link #createClassLoader(String, List, ClassLoader, Attributes)} + */ + @Deprecated(since = "TODO") protected ClassLoader createClassLoader(List paths, ClassLoader parent) throws IOException { return createClassLoader(paths, parent, null); } /** - * Creates the classloader that can load all the specified jar files and delegate to the given parent. + * @deprecated since TODO use {@link #createClassLoader(String, List, ClassLoader, Attributes)} */ + @Deprecated(since="TODO") protected ClassLoader createClassLoader(List paths, ClassLoader parent, Attributes atts) throws IOException { + // generate a legacy id so at least we can track to something + return createClassLoader("unidentified-" + UUID.randomUUID(), paths, parent, atts); + } + + /** + * Creates a classloader that can load all the specified jar files and delegate to the given parent. + * @since TODO + */ + protected ClassLoader createClassLoader(String name, List paths, ClassLoader parent, Attributes atts) throws IOException { boolean usePluginFirstClassLoader = atts != null && Boolean.parseBoolean(atts.getValue("PluginFirstClassLoader")); @@ -285,9 +303,9 @@ protected ClassLoader createClassLoader(List paths, ClassLoader parent, At } URLClassLoader2 classLoader; if (usePluginFirstClassLoader) { - classLoader = new PluginFirstClassLoader2(urls.toArray(new URL[0]), parent); + classLoader = new PluginFirstClassLoader2(name, urls.toArray(new URL[0]), parent); } else { - classLoader = new URLClassLoader2(urls.toArray(new URL[0]), parent); + classLoader = new URLClassLoader2(name, urls.toArray(new URL[0]), parent); } return classLoader; } @@ -561,7 +579,7 @@ static final class DependencyClassLoader extends ClassLoader { } DependencyClassLoader(ClassLoader parent, File archive, List dependencies, PluginManager pluginManager) { - super(parent); + super("dependency ClassLoader for " + archive.getPath(), parent); this._for = archive; this.dependencies = List.copyOf(dependencies); this.pluginManager = pluginManager; diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 3525b931ef78..b0cf56bf907d 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -80,6 +80,7 @@ import java.io.OutputStreamWriter; import java.io.RandomAccessFile; import java.io.Serializable; +import java.io.UncheckedIOException; import java.io.Writer; import java.net.HttpURLConnection; import java.net.MalformedURLException; @@ -132,7 +133,7 @@ import jenkins.util.VirtualFile; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload2.core.FileItem; import org.apache.commons.io.input.CountingInputStream; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; @@ -1166,7 +1167,9 @@ public void copyFrom(FilePath src) throws IOException, InterruptedException { public void copyFrom(FileItem file) throws IOException, InterruptedException { if (channel == null) { try { - file.write(new File(remote)); + file.write(Paths.get(remote)); + } catch (UncheckedIOException e) { + throw e.getCause(); } catch (IOException e) { throw e; } catch (Exception e) { @@ -1180,6 +1183,14 @@ public void copyFrom(FileItem file) throws IOException, InterruptedException { } } + /** + * @deprecated use {@link #copyFrom(FileItem)} + */ + @Deprecated + public void copyFrom(org.apache.commons.fileupload.FileItem file) throws IOException, InterruptedException { + copyFrom(file.toFileUpload2FileItem()); + } + /** * Code that gets executed on the machine where the {@link FilePath} is local. * Used to act on {@link FilePath}. diff --git a/core/src/main/java/hudson/PluginFirstClassLoader2.java b/core/src/main/java/hudson/PluginFirstClassLoader2.java index 974939d53acb..30618835c8a7 100644 --- a/core/src/main/java/hudson/PluginFirstClassLoader2.java +++ b/core/src/main/java/hudson/PluginFirstClassLoader2.java @@ -25,8 +25,9 @@ public class PluginFirstClassLoader2 extends URLClassLoader2 { registerAsParallelCapable(); } - public PluginFirstClassLoader2(@NonNull URL[] urls, @NonNull ClassLoader parent) { - super(Objects.requireNonNull(urls), Objects.requireNonNull(parent)); + + public PluginFirstClassLoader2(String name, @NonNull URL[] urls, @NonNull ClassLoader parent) { + super(name, Objects.requireNonNull(urls), Objects.requireNonNull(parent)); } /** diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 1fd5358454a6..5d80c6e623e4 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -139,10 +139,12 @@ import jenkins.util.xml.RestrictiveEntityResolver; import net.sf.json.JSONArray; import net.sf.json.JSONObject; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload2.core.DiskFileItem; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.javax.JavaxServletDiskFileUpload; +import org.apache.commons.fileupload2.javax.JavaxServletFileUpload; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; @@ -1099,7 +1101,7 @@ protected void copyBundledPlugin(URL src, String fileName) throws IOException { } /*package*/ static @CheckForNull Manifest parsePluginManifest(URL bundledJpi) { - try (URLClassLoader cl = new URLClassLoader(new URL[]{bundledJpi})) { + try (URLClassLoader cl = new URLClassLoader("Temporary classloader for parsing " + bundledJpi.toString(), new URL[]{bundledJpi}, ClassLoader.getSystemClassLoader())) { InputStream in = null; try { URL res = cl.findResource(PluginWrapper.MANIFEST_FILENAME); @@ -1832,13 +1834,21 @@ static class FileUploadPluginCopier implements PluginCopier { } @Override - public void copy(File target) throws Exception { - fileItem.write(target); + public void copy(File target) throws IOException { + try { + fileItem.write(Util.fileToPath(target)); + } catch (UncheckedIOException e) { + throw e.getCause(); + } } @Override public void cleanup() { - fileItem.delete(); + try { + fileItem.delete(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } } @@ -1873,8 +1883,8 @@ public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, Servl String fileName = ""; PluginCopier copier; File tmpDir = Files.createTempDirectory("uploadDir").toFile(); - ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, tmpDir)); - List items = upload.parseRequest(req); + JavaxServletFileUpload upload = new JavaxServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get()); + List items = upload.parseRequest(req); String string = items.get(1).getString(); if (string != null && !string.isBlank()) { // this is a URL deployment @@ -2337,7 +2347,7 @@ public static final class UberClassLoader extends ClassLoader { } public UberClassLoader(List activePlugins) { - super(PluginManager.class.getClassLoader()); + super("UberClassLoader", PluginManager.class.getClassLoader()); this.activePlugins = activePlugins; } diff --git a/core/src/main/java/hudson/console/HyperlinkNote.java b/core/src/main/java/hudson/console/HyperlinkNote.java index 93e2ff40f493..1e582dab2b4a 100644 --- a/core/src/main/java/hudson/console/HyperlinkNote.java +++ b/core/src/main/java/hudson/console/HyperlinkNote.java @@ -88,10 +88,8 @@ static String encodeTo(String url, String text, BiFunction build) { return new BuildWrapper() { @@ -241,11 +259,120 @@ private File getFileParameterFolderUnderBuild(AbstractBuild build) { /** * Default implementation from {@link File}. + * + * @deprecated use {@link FileItemImpl2} */ - public static final class FileItemImpl implements FileItem { - private final File file; + @Deprecated + public static final class FileItemImpl implements org.apache.commons.fileupload.FileItem { + private final FileItem delegate; public FileItemImpl(File file) { + if (file == null) { + throw new NullPointerException("file"); + } + this.delegate = new FileItemImpl2(file); + } + + @Override + public InputStream getInputStream() throws IOException { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getInputStream(); + } + + @Override + public String getContentType() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getContentType(); + } + + @Override + @SuppressFBWarnings(value = "FILE_UPLOAD_FILENAME", justification = "for compatibility") + public String getName() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getName(); + } + + @Override + public boolean isInMemory() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).isInMemory(); + } + + @Override + public long getSize() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getSize(); + } + + @Override + public byte[] get() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).get(); + } + + @Override + public String getString(String encoding) throws UnsupportedEncodingException { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getString(encoding); + } + + @Override + public String getString() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getString(); + } + + @Override + public void write(File to) throws Exception { + org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).write(to); + } + + @Override + public void delete() { + org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).delete(); + } + + @Override + public String getFieldName() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getFieldName(); + } + + @Override + public void setFieldName(String name) { + org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).setFieldName(name); + } + + @Override + public boolean isFormField() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).isFormField(); + } + + @Override + public void setFormField(boolean state) { + org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).setFormField(state); + } + + @Override + @Deprecated + public OutputStream getOutputStream() throws IOException { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getOutputStream(); + } + + @Override + public org.apache.commons.fileupload.FileItemHeaders getHeaders() { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).getHeaders(); + } + + @Override + public void setHeaders(org.apache.commons.fileupload.FileItemHeaders headers) { + org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(delegate).setHeaders(headers); + } + + @Override + public FileItem toFileUpload2FileItem() { + return delegate; + } + } + + /** + * Default implementation from {@link File}. + */ + public static final class FileItemImpl2 implements FileItem { + private final File file; + + public FileItemImpl2(File file) { if (file == null) { throw new NullPointerException("file"); } @@ -287,8 +414,12 @@ public byte[] get() { } @Override - public String getString(String encoding) throws UnsupportedEncodingException { - return new String(get(), encoding); + public String getString(Charset toCharset) throws IOException { + try { + return new String(get(), toCharset); + } catch (UncheckedIOException e) { + throw e.getCause(); + } } @Override @@ -297,17 +428,19 @@ public String getString() { } @Override - public void write(File to) throws Exception { - new FilePath(file).copyTo(new FilePath(to)); + public FileItem write(Path to) throws IOException { + try { + new FilePath(file).copyTo(new FilePath(to.toFile())); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return this; } @Override - public void delete() { - try { - Files.deleteIfExists(file.toPath()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + public FileItem delete() throws IOException { + Files.deleteIfExists(Util.fileToPath(file)); + return this; } @Override @@ -316,7 +449,8 @@ public String getFieldName() { } @Override - public void setFieldName(String name) { + public FileItem setFieldName(String name) { + return this; } @Override @@ -325,7 +459,8 @@ public boolean isFormField() { } @Override - public void setFormField(boolean state) { + public FileItem setFormField(boolean state) { + return this; } @Override @@ -336,11 +471,12 @@ public OutputStream getOutputStream() throws IOException { @Override public FileItemHeaders getHeaders() { - return new FileItemHeadersImpl(); + return FileItemFactory.AbstractFileItemBuilder.newFileItemHeaders(); } @Override - public void setHeaders(FileItemHeaders headers) { + public FileItemHeadersProvider setHeaders(FileItemHeaders headers) { + return this; } } } diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index 8c4e3183100a..92f1d374fb08 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -626,11 +626,11 @@ public Collection getOverrides() { } /** - * @deprecated see {@link LazyBuildMixIn#createHistoryWidget()} + * @deprecated Remove any override, history widget is now created via {@link jenkins.widgets.WidgetFactory} implementation. */ @Deprecated(forRemoval = true, since = "2.410") protected HistoryWidget createHistoryWidget() { - return new HistoryWidget(this, getBuilds(), HISTORY_ADAPTER); + throw new IllegalStateException("HistoryWidget is now created via WidgetFactory implementation"); } public static final HistoryWidget.Adapter HISTORY_ADAPTER = new Adapter<>() { diff --git a/core/src/main/java/hudson/util/MaskingClassLoader.java b/core/src/main/java/hudson/util/MaskingClassLoader.java index 74bbbe1a9863..dfad754fc170 100644 --- a/core/src/main/java/hudson/util/MaskingClassLoader.java +++ b/core/src/main/java/hudson/util/MaskingClassLoader.java @@ -59,7 +59,7 @@ public MaskingClassLoader(ClassLoader parent, String... masks) { } public MaskingClassLoader(ClassLoader parent, Collection masks) { - super(parent); + super("Masking ClassLoader of " + parent.getName(), parent); this.masksClasses = List.copyOf(masks); /* diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java index 8633a77e1534..f173cff9802b 100644 --- a/core/src/main/java/hudson/util/MultipartFormDataParser.java +++ b/core/src/main/java/hudson/util/MultipartFormDataParser.java @@ -27,17 +27,21 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; -import org.apache.commons.fileupload.FileCountLimitExceededException; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadBase; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload2.core.DiskFileItem; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException; +import org.apache.commons.fileupload2.core.FileUploadSizeException; +import org.apache.commons.fileupload2.javax.JavaxServletDiskFileUpload; +import org.apache.commons.fileupload2.javax.JavaxServletFileUpload; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -52,7 +56,7 @@ public class MultipartFormDataParser implements AutoCloseable { /** * Limits the number of form fields that can be processed in one multipart/form-data request. - * Used to set {@link org.apache.commons.fileupload.servlet.ServletFileUpload#setFileCountMax(long)}. + * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setFileCountMax(long)}. * Despite the name, this applies to all form fields, not just actual file attachments. * Set to {@code -1} to disable limits. */ @@ -60,7 +64,7 @@ public class MultipartFormDataParser implements AutoCloseable { /** * Limits the size (in bytes) of individual fields that can be processed in one multipart/form-data request. - * Used to set {@link org.apache.commons.fileupload.servlet.ServletFileUpload#setFileSizeMax(long)}. + * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setFileSizeMax(long)}. * Despite the name, this applies to all form fields, not just actual file attachments. * Set to {@code -1} to disable limits. */ @@ -68,7 +72,7 @@ public class MultipartFormDataParser implements AutoCloseable { /** * Limits the total request size (in bytes) that can be processed in one multipart/form-data request. - * Used to set {@link org.apache.commons.fileupload.servlet.ServletFileUpload#setSizeMax(long)}. + * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setSizeMax(long)}. * Set to {@code -1} to disable limits. */ private static /* nonfinal for Jenkins script console */ long FILEUPLOAD_MAX_SIZE = Long.getLong(MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_SIZE", -1); @@ -82,20 +86,20 @@ public MultipartFormDataParser(HttpServletRequest request, int maxParts, long ma throw new ServletException("Error creating temporary directory", e); } tmpDir.deleteOnExit(); - ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, tmpDir)); + JavaxServletFileUpload upload = new JavaxServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get()); upload.setFileCountMax(maxParts); upload.setFileSizeMax(maxPartSize); upload.setSizeMax(maxSize); try { for (FileItem fi : upload.parseRequest(request)) byName.put(fi.getFieldName(), fi); - } catch (FileCountLimitExceededException e) { + } catch (FileUploadFileCountLimitException e) { throw new ServletException("File upload field count limit exceeded. Consider setting the Java system property " + MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_FILES to a value greater than " + FILEUPLOAD_MAX_FILES + ", or to -1 to disable this limit.", e); - } catch (FileUploadBase.FileSizeLimitExceededException e) { + } catch (FileUploadByteCountLimitException e) { throw new ServletException("File upload field size limit exceeded. Consider setting the Java system property " + MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_FILE_SIZE to a value greater than " + FILEUPLOAD_MAX_FILE_SIZE + ", or to -1 to disable this limit.", e); - } catch (FileUploadBase.SizeLimitExceededException e) { + } catch (FileUploadSizeException e) { throw new ServletException("File upload total size limit exceeded. Consider setting the Java system property " + MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_SIZE to a value greater than " + FILEUPLOAD_MAX_SIZE + ", or to -1 to disable this limit.", e); } catch (FileUploadException e) { @@ -118,17 +122,30 @@ public String get(String key) { return fi.getString(); } - public FileItem getFileItem(String key) { + public FileItem getFileItem2(String key) { return byName.get(key); } + /** + * @deprecated use {@link #getFileItem2(String)} + */ + @Deprecated + public org.apache.commons.fileupload.FileItem getFileItem(String key) { + return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem(getFileItem2(key)); + } + /** * If any file is created on the disk, delete them all. * Even if this method is not called, the resource will be still cleaned up later by GC. */ public void cleanUp() { - for (FileItem item : byName.values()) - item.delete(); + for (FileItem item : byName.values()) { + try { + item.delete(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } } /** Alias for {@link #cleanUp}. */ diff --git a/core/src/main/java/jenkins/agents/CloudSet.java b/core/src/main/java/jenkins/agents/CloudSet.java index e69a3f9add3c..addefceb83ff 100644 --- a/core/src/main/java/jenkins/agents/CloudSet.java +++ b/core/src/main/java/jenkins/agents/CloudSet.java @@ -242,9 +242,13 @@ private void handleNewCloudPage(Descriptor descriptor, String name, Stapl */ @POST public synchronized void doDoCreate(StaplerRequest req, StaplerResponse rsp, - @QueryParameter String type) throws IOException, ServletException, Descriptor.FormException { + @QueryParameter String cloudDescriptorName) throws IOException, ServletException, Descriptor.FormException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); - Cloud cloud = Cloud.all().find(type).newInstance(req, req.getSubmittedForm()); + Descriptor cloudDescriptor = Cloud.all().findByName(cloudDescriptorName); + if (cloudDescriptor == null) { + throw new Failure(String.format("No cloud type ā€˜%sā€™ is known", cloudDescriptorName)); + } + Cloud cloud = cloudDescriptor.newInstance(req, req.getSubmittedForm()); if (!Jenkins.get().clouds.add(cloud)) { LOGGER.log(Level.WARNING, () -> "Creating duplicate cloud name " + cloud.name + ". Plugin " + Jenkins.get().getPluginManager().whichPlugin(cloud.getClass()) + " should be updated to support user provided name."); } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index b08ac6c8941d..7fe515fddf0e 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4492,7 +4492,7 @@ public void doDoFingerprintCheck(StaplerRequest req, StaplerResponse rsp) throws rsp.sendError(HttpServletResponse.SC_FORBIDDEN, "No crumb found"); } rsp.sendRedirect2(req.getContextPath() + "/fingerprint/" + - Util.getDigestOf(p.getFileItem("name").getInputStream()) + '/'); + Util.getDigestOf(p.getFileItem2("name").getInputStream()) + '/'); } } diff --git a/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java b/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java index 570048c5327f..203ea976bccd 100644 --- a/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java +++ b/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java @@ -39,7 +39,6 @@ import hudson.model.RunMap; import hudson.model.listeners.ItemListener; import hudson.model.queue.SubTask; -import hudson.widgets.BuildHistoryWidget; import hudson.widgets.HistoryWidget; import java.io.File; import java.io.IOException; @@ -297,10 +296,11 @@ public List getEstimatedDurationCandidates() { } /** - * Suitable for {@link Job#createHistoryWidget}. + * @deprecated Remove any code calling this method, history widget is now created via {@link jenkins.widgets.WidgetFactory} implementation. */ + @Deprecated(forRemoval = true, since = "TODO") public final HistoryWidget createHistoryWidget() { - return new BuildHistoryWidget(asJob(), builds, Job.HISTORY_ADAPTER); + throw new IllegalStateException("HistoryWidget is now created via WidgetFactory implementation"); } /** diff --git a/core/src/main/java/jenkins/util/URLClassLoader2.java b/core/src/main/java/jenkins/util/URLClassLoader2.java index 72611bc49432..3fdedcbeada0 100644 --- a/core/src/main/java/jenkins/util/URLClassLoader2.java +++ b/core/src/main/java/jenkins/util/URLClassLoader2.java @@ -17,14 +17,43 @@ public class URLClassLoader2 extends URLClassLoader implements JenkinsClassLoade registerAsParallelCapable(); } + /** + * @deprecated use {@link URLClassLoader2#URLClassLoader2(String, URL[])} + */ + @Deprecated(since = "TODO") public URLClassLoader2(URL[] urls) { super(urls); } + /** + * @deprecated use {@link URLClassLoader2#URLClassLoader2(String, URL[], ClassLoader)} + */ + @Deprecated(since = "TODO") public URLClassLoader2(URL[] urls, ClassLoader parent) { super(urls, parent); } + /** + * Create a new {@link URLClassLoader2} with the given name and URLS and the {@link #getSystemClassLoader()} as its parent. + * @param name name of this classloader. + * @param urls the list of URLS to find classes in. + * @since TODO + */ + public URLClassLoader2(String name, URL[] urls) { + super(name, urls, getSystemClassLoader()); + } + + /** + * Create a new {@link URLClassLoader2} with the given name, URLS parent. + * @param name name of this classloader. + * @param urls the list of URLS to find classes in. + * @param parent the parent to search for classes before we look in the {@code urls} + * @since TODO + */ + public URLClassLoader2(String name, URL[] urls, ClassLoader parent) { + super(name, urls, parent); + } + @Override public void addURL(URL url) { super.addURL(url); diff --git a/core/src/main/java/org/jenkins/ui/symbol/Symbol.java b/core/src/main/java/org/jenkins/ui/symbol/Symbol.java index 9973acc18da5..9a07556d7c71 100644 --- a/core/src/main/java/org/jenkins/ui/symbol/Symbol.java +++ b/core/src/main/java/org/jenkins/ui/symbol/Symbol.java @@ -8,13 +8,30 @@ import hudson.Util; import java.io.IOException; import java.io.InputStream; +import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import jenkins.model.Jenkins; import org.apache.commons.io.IOUtils; +import org.apache.tools.ant.filters.StringInputStream; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; /** * Helper class to load symbols from Jenkins core or plugins. @@ -88,12 +105,37 @@ private static String loadSymbol(String namespace, String name) { LOGGER.log(Level.FINE, "Failed to load symbol " + name, e); } } - return markup.replaceAll("().*?()", "$1$2") - .replaceAll(" "The given src for the svg is not a valid xml document"); + return PLACEHOLDER_SVG; + } + + return markup; } @CheckForNull diff --git a/core/src/main/resources/hudson/PluginManager/PluginCycleDependenciesMonitor/message.jelly b/core/src/main/resources/hudson/PluginManager/PluginCycleDependenciesMonitor/message.jelly index 5ccac430ecd2..cb20ebf8dfe7 100644 --- a/core/src/main/resources/hudson/PluginManager/PluginCycleDependenciesMonitor/message.jelly +++ b/core/src/main/resources/hudson/PluginManager/PluginCycleDependenciesMonitor/message.jelly @@ -24,7 +24,7 @@ THE SOFTWARE. -
+
${%PluginCycles}
diff --git a/core/src/main/resources/hudson/PluginManager/PluginDeprecationMonitor/message.jelly b/core/src/main/resources/hudson/PluginManager/PluginDeprecationMonitor/message.jelly index 45c4cead0a44..1f5ec400bd3c 100644 --- a/core/src/main/resources/hudson/PluginManager/PluginDeprecationMonitor/message.jelly +++ b/core/src/main/resources/hudson/PluginManager/PluginDeprecationMonitor/message.jelly @@ -24,7 +24,7 @@ THE SOFTWARE. -
+
${%DeprecatedPlugins}
diff --git a/core/src/main/resources/hudson/PluginManager/PluginUpdateMonitor/message.jelly b/core/src/main/resources/hudson/PluginManager/PluginUpdateMonitor/message.jelly index 73182ec483e4..b1f9ba193d49 100644 --- a/core/src/main/resources/hudson/PluginManager/PluginUpdateMonitor/message.jelly +++ b/core/src/main/resources/hudson/PluginManager/PluginUpdateMonitor/message.jelly @@ -24,7 +24,7 @@ THE SOFTWARE. -
+
${%RequiredPluginUpdates}
diff --git a/core/src/main/resources/hudson/PluginManager/advanced.jelly b/core/src/main/resources/hudson/PluginManager/advanced.jelly index 8d0e6abcd22e..81948afa6e80 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced.jelly +++ b/core/src/main/resources/hudson/PluginManager/advanced.jelly @@ -37,7 +37,7 @@ THE SOFTWARE. -
+
${%proxyMovedBlurb(rootURL+"/manage/configure")}
diff --git a/core/src/main/resources/hudson/PluginManager/installed.jelly b/core/src/main/resources/hudson/PluginManager/installed.jelly index c22c9ddeeba1..3c3ee43e0193 100644 --- a/core/src/main/resources/hudson/PluginManager/installed.jelly +++ b/core/src/main/resources/hudson/PluginManager/installed.jelly @@ -54,7 +54,7 @@ THE SOFTWARE. data-is-restart-required="${app.updateCenter.isRestartRequiredForCompletion()}" /> -
${%Warning}: ${%requires.restart}
+
${%Warning}: ${%requires.restart}