diff --git a/dist/lib/ext/commons-fileupload.jar b/dist/lib/ext/commons-fileupload.jar
deleted file mode 100644
index 5e608753c1b..00000000000
Binary files a/dist/lib/ext/commons-fileupload.jar and /dev/null differ
diff --git a/dist/lib/ext/commons-fileupload2-javax.jar b/dist/lib/ext/commons-fileupload2-javax.jar
new file mode 100644
index 00000000000..286076d19ce
Binary files /dev/null and b/dist/lib/ext/commons-fileupload2-javax.jar differ
diff --git a/dist/lib/ext/commons-io.jar b/dist/lib/ext/commons-io.jar
index 177e58dc65d..eb316f40209 100644
Binary files a/dist/lib/ext/commons-io.jar and b/dist/lib/ext/commons-io.jar differ
diff --git a/release.gradle b/release.gradle
index dbf9ab79065..218cbcc2145 100644
--- a/release.gradle
+++ b/release.gradle
@@ -151,7 +151,7 @@ task prepareBin() {
include "**/bsh.jar"
include "**/closure-compiler-unshaded.jar"
include "**/commons-collections4.jar"
- include "**/commons-fileupload.jar"
+ include "**/commons-fileupload2-javax.jar"
include "**/commons-io.jar"
include "**/commons-logging.jar"
include "**/Filters.jar"
diff --git a/zhtml/build.gradle b/zhtml/build.gradle
index 6d6d5ab4120..deb738a2624 100644
--- a/zhtml/build.gradle
+++ b/zhtml/build.gradle
@@ -14,7 +14,7 @@ idea {
dependencies {
api project(':zul')
- api 'commons-io:commons-io:2.8.0'
+ api 'commons-io:commons-io:2.13.0'
api 'org.zkoss:zsoup:1.8.2.5'
}
diff --git a/zk-parent/pom.xml b/zk-parent/pom.xml
index 0beb8cc26d5..33dba19958a 100644
--- a/zk-parent/pom.xml
+++ b/zk-parent/pom.xml
@@ -106,14 +106,14 @@
${slf4j.version}
- commons-fileupload
- commons-fileupload
- 1.5
+ org.apache.commons
+ commons-fileupload2-javax
+ 2.0.0-M1
commons-io
commons-io
- 2.8.0
+ 2.13.0
commons-lang
diff --git a/zk/build.gradle b/zk/build.gradle
index fe0ba49895e..38f272cc562 100644
--- a/zk/build.gradle
+++ b/zk/build.gradle
@@ -22,8 +22,8 @@ java {
dependencies {
api project(':zweb')
api project(':zkwebfragment')
- api 'commons-fileupload:commons-fileupload:1.5'
- api 'commons-io:commons-io:2.8.0'
+ api 'org.apache.commons:commons-fileupload2-javax:2.0.0-M1'
+ api 'commons-io:commons-io:2.13.0'
compileOnly "javax.servlet:servlet-api:${servletVersion}"
compileOnly "javax.portlet:portlet-api:${portletVersion}"
compileOnly 'javax.websocket:javax.websocket-api:1.1'
diff --git a/zk/src/main/java/org/zkoss/zk/au/http/AuMultipartUploader.java b/zk/src/main/java/org/zkoss/zk/au/http/AuMultipartUploader.java
index 0d2604443fd..eacad407120 100644
--- a/zk/src/main/java/org/zkoss/zk/au/http/AuMultipartUploader.java
+++ b/zk/src/main/java/org/zkoss/zk/au/http/AuMultipartUploader.java
@@ -21,7 +21,9 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.net.URLDecoder;
+import java.nio.charset.Charset;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
@@ -36,14 +38,15 @@
import java.util.Set;
import java.util.stream.Collectors;
+import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
-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.AbstractFileUpload;
+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.core.FileUploadSizeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -77,12 +80,57 @@
public class AuMultipartUploader {
private static final String FILE_DATA = AuMultipartUploader.class.getName() + ".FILE_DATA";
private static final Logger log = LoggerFactory.getLogger(AuMultipartUploader.class);
+ private static final String JAVAX_UPLOAD_CLASS = "org.apache.commons.fileupload2.javax.JavaxServletFileUpload";
+ private static final String JAKARTA_UPLOAD_CLASS = "org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload";
+ private static final String JAVAX_DISK_UPLOAD_CLASS = "org.apache.commons.fileupload2.javax.JavaxServletDiskFileUpload";
+ private static final String JAKARTA_DISK_UPLOAD_CLASS = "org.apache.commons.fileupload2.jakarta.JakartaServletDiskFileUpload";
+
+ private static Class> getServletFileUploadClass() {
+ try {
+ return Class.forName(JAVAX_UPLOAD_CLASS);
+ } catch (ClassNotFoundException ex0) {
+ try {
+ return Class.forName(JAKARTA_UPLOAD_CLASS);
+ } catch (ClassNotFoundException ex1) {
+ throw new RuntimeException("Failed to find " + JAVAX_UPLOAD_CLASS + " or " + JAKARTA_UPLOAD_CLASS);
+ }
+ }
+ }
+
+ public static boolean isMultipartContent(HttpServletRequest request) {
+ Class> clazz = getServletFileUploadClass();
+ try {
+ Method method = clazz.getMethod("isMultipartContent", HttpServletRequest.class);
+ return (boolean) method.invoke(null, request);
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to invoke " + clazz.getName() + "#isMultipartContent(HttpServletRequest)", ex);
+ }
+ }
+
+ private static AbstractFileUpload newServletDiskFileUpload(DiskFileItemFactory factory) {
+ Class> clazz;
+ try {
+ clazz = Class.forName(JAVAX_DISK_UPLOAD_CLASS);
+ } catch (ClassNotFoundException ex0) {
+ try {
+ clazz = Class.forName(JAKARTA_DISK_UPLOAD_CLASS);
+ } catch (ClassNotFoundException ex1) {
+ throw new RuntimeException("Failed to find " + JAVAX_DISK_UPLOAD_CLASS + " or " + JAKARTA_DISK_UPLOAD_CLASS);
+ }
+ }
+ try {
+ return (AbstractFileUpload) clazz.getDeclaredConstructor(DiskFileItemFactory.class).newInstance(factory);
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to create a new instance of " + clazz.getName(), ex);
+ }
+ }
+
public static AuDecoder parseRequest(HttpServletRequest request, AuDecoder decoder) {
Map params = getFileuploadMetaPerWebApp(
WebApps.getCurrent());
- ServletFileUpload upload = new ServletFileUpload(
- new DiskFileItemFactory((Integer) params.get("sizeThreadHold"),
- (File) params.get("repository")));
+ AbstractFileUpload upload = newServletDiskFileUpload(new DiskFileItemFactory.Builder()
+ .setBufferSize((Integer) params.get("sizeThreadHold"))
+ .setPath(((File) params.get("repository")).toPath()).get());
try {
List fileItems = upload.parseRequest(request);
Map dataMap = new HashMap<>(fileItems.size());
@@ -176,15 +224,15 @@ private static Map getFileuploadMetaPerWebApp(WebApp webApp) {
params.put("sizeThreadHold", sizeThreadHold);
- File repository = null;
-
- if (conf.getFileRepository() != null) {
+ ServletContext context = webApp.getServletContext();
+ File repository = (File) context.getAttribute("javax.servlet.context.tempdir");
+ if (repository == null)
+ repository = (File) context.getAttribute("jakarta.servlet.context.tempdir");
+ if (conf.getFileRepository() != null)
repository = new File(conf.getFileRepository());
- if (!repository.isDirectory()) {
- log.warn("The file repository is not a directory! [" + repository + "]");
- }
- params.put("repository", repository);
- }
+ if (!repository.isDirectory())
+ log.warn("The file repository is not a directory! [" + repository + "]");
+ params.put("repository", repository);
org.zkoss.zk.ui.sys.DiskFileItemFactory dfiFactory = null;
if (conf.getFileItemFactoryClass() != null) {
@@ -269,8 +317,8 @@ public List decode(Object request, Desktop desktop) {
reconstructPacket(auRequest.getData(), _reqData, desktop, params);
Long fileSize = (Long) params.get("fileSize");
if (maxSizeLong >= 0 && fileSize > maxSizeLong) {
- String errorMessage = uploadErrorMessage(new FileUploadBase.SizeLimitExceededException(null, fileSize, maxSizeLong));
- throw new FileUploadBase.SizeLimitExceededException(errorMessage, fileSize, maxSizeLong);
+ String errorMessage = uploadErrorMessage(new FileUploadSizeException(null, fileSize, maxSizeLong));
+ throw new FileUploadSizeException(errorMessage, fileSize, maxSizeLong);
}
} catch (Exception e) {
throw UiException.Aide.wrap(e);
@@ -285,11 +333,11 @@ public boolean isIgnorable(Object request, WebApp wapp) {
}
private static String uploadErrorMessage(Throwable ex) {
log.error("Failed to upload", ex);
- if (ex instanceof FileUploadBase.SizeLimitExceededException) {
+ if (ex instanceof FileUploadSizeException) {
try {
- FileUploadBase.SizeLimitExceededException fex = (FileUploadBase.SizeLimitExceededException) ex;
+ FileUploadSizeException fex = (FileUploadSizeException) ex;
long size = fex.getActualSize();
- long limit = fex.getPermittedSize();
+ long limit = fex.getPermitted();
final Class> msgClass = Classes.forNameByThread("org.zkoss.zul.mesg.MZul");
Field msgField = msgClass.getField("UPLOAD_ERROR_EXCEED_MAXSIZE");
int divisor1 = 1024;
@@ -529,7 +577,7 @@ private static final Media processItem(Desktop desktop, FileItem fi, boolean alw
if (charset == null)
charset = conf.getUploadCharset();
}
- return fi.isInMemory() ? new AMedia(name, null, ctype, fi.getString(charset))
+ return fi.isInMemory() ? new AMedia(name, null, ctype, fi.getString(Charset.forName(charset)))
: new ReaderMedia(name, null, ctype, fi, charset);
}
}
diff --git a/zk/src/main/java/org/zkoss/zk/au/http/DHtmlUpdateServlet.java b/zk/src/main/java/org/zkoss/zk/au/http/DHtmlUpdateServlet.java
index cf89bf09f67..642a42da87c 100644
--- a/zk/src/main/java/org/zkoss/zk/au/http/DHtmlUpdateServlet.java
+++ b/zk/src/main/java/org/zkoss/zk/au/http/DHtmlUpdateServlet.java
@@ -33,7 +33,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -446,7 +445,7 @@ public void process(Session sess, HttpServletRequest request, HttpServletRespons
final WebApp wapp = sess.getWebApp();
final WebAppCtrl wappc = (WebAppCtrl) wapp;
AuDecoder audec = getAuDecoder(wapp);
- boolean multipartContent = ServletFileUpload.isMultipartContent(request);
+ boolean multipartContent = AuMultipartUploader.isMultipartContent(request);
if (multipartContent) {
audec = AuMultipartUploader.parseRequest(request, audec);
}
diff --git a/zk/src/main/java/org/zkoss/zk/au/http/ServletRequestContext.java b/zk/src/main/java/org/zkoss/zk/au/http/ServletRequestContext.java
index d667b8c1af2..0ff2d2dfca2 100644
--- a/zk/src/main/java/org/zkoss/zk/au/http/ServletRequestContext.java
+++ b/zk/src/main/java/org/zkoss/zk/au/http/ServletRequestContext.java
@@ -32,8 +32,8 @@
import javax.servlet.http.HttpServletRequest;
-import org.apache.commons.fileupload.FileUploadBase;
-import org.apache.commons.fileupload.UploadContext;
+import org.apache.commons.fileupload2.core.AbstractFileUpload;
+import org.apache.commons.fileupload2.core.RequestContext;
/**
* An implementation of RequestContext, for commons-fileupload.
@@ -42,7 +42,7 @@
* @author rudyhuang
* @since 9.6.0
*/
-class ServletRequestContext implements UploadContext {
+class ServletRequestContext implements RequestContext {
private final HttpServletRequest _request;
public ServletRequestContext(HttpServletRequest request) {
@@ -60,16 +60,10 @@ public String getContentType() {
}
@Override
- @Deprecated
- public int getContentLength() {
- return _request.getContentLength();
- }
-
- @Override
- public long contentLength() {
+ public long getContentLength() {
long size;
try {
- size = Long.parseLong(_request.getHeader(FileUploadBase.CONTENT_LENGTH));
+ size = Long.parseLong(_request.getHeader(AbstractFileUpload.CONTENT_LENGTH));
} catch (NumberFormatException e) {
size = _request.getContentLength();
}
@@ -84,7 +78,7 @@ public InputStream getInputStream() throws IOException {
@Override
public String toString() {
return String.format("ContentLength=%s, ContentType=%s",
- this.contentLength(),
+ this.getContentLength(),
this.getContentType());
}
}
diff --git a/zk/src/main/java/org/zkoss/zk/ui/sys/DiskFileItemFactory.java b/zk/src/main/java/org/zkoss/zk/ui/sys/DiskFileItemFactory.java
index 5ecbdbda6f2..139262b1a24 100644
--- a/zk/src/main/java/org/zkoss/zk/ui/sys/DiskFileItemFactory.java
+++ b/zk/src/main/java/org/zkoss/zk/ui/sys/DiskFileItemFactory.java
@@ -13,7 +13,7 @@
import java.io.File;
-import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload2.core.FileItem;
import org.zkoss.util.media.Media;
@@ -22,7 +22,7 @@
* Factories can provide their own custom configuration, over and above that provided
* by the default file upload implementation.
*
- * Unlike {@link org.apache.commons.fileupload.FileItemFactory}, this factory
+ * Unlike {@link org.apache.commons.fileupload2.core.FileItemFactory}, this factory
* needs two extra information, sizeThreshold and repository.
*
* @author jumperchen
diff --git a/zkdoc/release-note b/zkdoc/release-note
index 5dcdf2639cf..dbd9ea056c1 100644
--- a/zkdoc/release-note
+++ b/zkdoc/release-note
@@ -2,8 +2,10 @@ ZK 10.0.0
* Features
* Bugs
+ ZK-5393: Update ZK jars to jakarta-friendly uploads
* Upgrade Notes
+ + Upgrade commons-fileupload to commons-fileupload2-javax 2.0.0-M1 and commons-io to 2.13.0 to support jakarta-friendly uploads
--------
ZK 10.0.0-Beta
diff --git a/zksandbox/build.gradle b/zksandbox/build.gradle
index 27286177fcc..79277609a11 100644
--- a/zksandbox/build.gradle
+++ b/zksandbox/build.gradle
@@ -41,9 +41,9 @@ repositories {
}
dependencies {
- implementation 'commons-io:commons-io:2.8.0'
+ implementation 'commons-io:commons-io:2.13.0'
implementation 'commons-logging:commons-logging:1.1.1'
- implementation 'commons-fileupload:commons-fileupload:1.5'
+ implementation 'org.apache.commons:commons-fileupload2-javax:2.0.0-M1'
implementation "org.zkoss.theme:breeze:${version}"
implementation "org.zkoss.theme:sapphire:${version}"
implementation "org.zkoss.theme:silvertail:${version}"
diff --git a/zktest/build.gradle b/zktest/build.gradle
index 797241d135d..db2cf70e1a6 100644
--- a/zktest/build.gradle
+++ b/zktest/build.gradle
@@ -61,8 +61,8 @@ dependencies {
implementation "org.zkoss.theme:sapphire:${version}"
implementation "org.zkoss.theme:atlantic:${version}"
implementation 'commons-logging:commons-logging:1.1.1'
- implementation 'commons-fileupload:commons-fileupload:1.5'
- implementation 'commons-io:commons-io:2.8.0'
+ implementation 'org.apache.commons:commons-fileupload2-javax:2.0.0-M1'
+ implementation 'commons-io:commons-io:2.13.0'
implementation "org.zkoss.zk:zk:${version}"
implementation "org.zkoss.zk:zkplus:${version}"
implementation "org.zkoss.zk:zkplus-legacy:${version}"
diff --git a/zktest/src/main/java/org/zkoss/zktest/test2/tree/PackageData.java b/zktest/src/main/java/org/zkoss/zktest/test2/tree/PackageData.java
index 7fae52dd686..9dab201ae71 100644
--- a/zktest/src/main/java/org/zkoss/zktest/test2/tree/PackageData.java
+++ b/zktest/src/main/java/org/zkoss/zktest/test2/tree/PackageData.java
@@ -42,7 +42,7 @@ public class PackageData {
// opened
new DirectoryTreeNode(new PackageDataUnit("/ext",null),
new DirectoryTreeNode[] {
- new DirectoryTreeNode(new PackageDataUnit("commons-fileupload.jar", "Upload Features")),
+ new DirectoryTreeNode(new PackageDataUnit("commons-fileupload2-javax.jar", "Upload Features")),
new DirectoryTreeNode(new PackageDataUnit("commons-io.jar", "Upload Features")),
new DirectoryTreeNode(new PackageDataUnit("jcommon.jar", "Chart Component")),
new DirectoryTreeNode(new PackageDataUnit("jfreechar.jar", "Chart Component")),
diff --git a/zktest/src/main/webapp/test2/B100-ZK-5393.zul b/zktest/src/main/webapp/test2/B100-ZK-5393.zul
new file mode 100644
index 00000000000..9c3a523f919
--- /dev/null
+++ b/zktest/src/main/webapp/test2/B100-ZK-5393.zul
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zktest/src/main/webapp/test2/config.properties b/zktest/src/main/webapp/test2/config.properties
index 9f50fabafa1..794f711f2a4 100644
--- a/zktest/src/main/webapp/test2/config.properties
+++ b/zktest/src/main/webapp/test2/config.properties
@@ -3161,6 +3161,7 @@ B90-ZK-4431.zul=A,E,Multislider
##zats##B100-ZK-5035.zul=A,E,Listbox,Column,AddChild,Checkmark
##zats##B100-ZK-5453.zul=A,E,Chosenbox,XSS
##zats##B100-ZK-5025.zul=A,E,Menu,Menupopup,Menuitem,focus,hover
+##zats##B100-ZK-5393.zul=A,E,FileUpload,JakartaEE
##
# Features - 3.0.x version
diff --git a/zktest/src/test/java/org/zkoss/zktest/zats/test2/B100_ZK_5393Test.java b/zktest/src/test/java/org/zkoss/zktest/zats/test2/B100_ZK_5393Test.java
new file mode 100644
index 00000000000..cf64f82cd38
--- /dev/null
+++ b/zktest/src/test/java/org/zkoss/zktest/zats/test2/B100_ZK_5393Test.java
@@ -0,0 +1,32 @@
+/* B100_ZK_5393Test.java
+
+ Purpose:
+
+ Description:
+
+ History:
+ Fri Dec 01 17:33:57 CST 2023, Created by rebeccalai
+
+Copyright (C) 2023 Potix Corporation. All Rights Reserved.
+*/
+package org.zkoss.zktest.zats.test2;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import org.zkoss.test.webdriver.WebDriverTestCase;
+
+public class B100_ZK_5393Test extends WebDriverTestCase {
+ @Test
+ public void test() throws Exception {
+ connect();
+ waitResponse();
+ dropUploadFile(jq("@dropupload"), Paths.get("src/main/webapp/test2/img/sun.jpg"));
+ waitResponse();
+ assertNoAnyError();
+ assertEquals("sun.jpg", getZKLog());
+ }
+}