merge of the actual 2.x into the 3.0
diff --git a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
index 6c9d87d..d53401e 100644
--- a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
+++ b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
@@ -937,12 +937,12 @@
}
@Override
- public synchronized void mark(int readlimit) {
+ public void mark(int readlimit) {
in.mark(readlimit);
}
@Override
- public synchronized void reset() throws IOException {
+ public void reset() throws IOException {
checkAborted();
in.reset();
}
diff --git a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
index 2e03b30..56f8dd5 100644
--- a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
+++ b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
@@ -941,12 +941,12 @@
}
@Override
- public synchronized void mark(int readlimit) {
+ public void mark(int readlimit) {
in.mark(readlimit);
}
@Override
- public synchronized void reset() throws IOException {
+ public void reset() throws IOException {
checkAborted();
in.reset();
}
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
index 15725e7..4070300 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -496,7 +496,7 @@
if (contentLengths != null) {
try {
- int bodyLength = Integer.parseInt(contentLengths.get(0));
+ long bodyLength = Long.parseLong(contentLengths.get(0));
if (bodyLength == 0) {
expectContent = false;
return;
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
index 0a3ede0..7dccd87 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -31,7 +31,7 @@
abstract boolean parse(ByteBuffer input) throws ParseException;
- static TransferEncodingParser createFixedLengthParser(AsynchronousBodyInputStream responseBody, int expectedLength) {
+ static TransferEncodingParser createFixedLengthParser(AsynchronousBodyInputStream responseBody, long expectedLength) {
return new FixedLengthEncodingParser(responseBody, expectedLength);
}
@@ -42,11 +42,11 @@
private static class FixedLengthEncodingParser extends TransferEncodingParser {
- private final int expectedLength;
+ private final long expectedLength;
private final AsynchronousBodyInputStream responseBody;
- private volatile int consumedLength = 0;
+ private volatile long consumedLength = 0;
- FixedLengthEncodingParser(AsynchronousBodyInputStream responseBody, int expectedLength) {
+ FixedLengthEncodingParser(AsynchronousBodyInputStream responseBody, long expectedLength) {
this.expectedLength = expectedLength;
this.responseBody = responseBody;
}
diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index 5f91902..a85d6df 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -2210,4 +2210,80 @@
</tgroup>
</table>
</section>
+ <section xml:id="appendix-properties-multipart">
+ <title>Multipart configuration properties</title>
+
+ <para>
+ List of multipart configuration properties that can be found in &jersey.media.multipart.MultiPartProperties; class.
+ </para>
+
+ <table>
+ <title>
+ List of multipart configuration properties settable in the
+ &jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE; configuration file.
+ </title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Constant</entry>
+ <entry>Value</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.BUFFER_THRESHOLD;</entry>
+ <entry><literal>jersey.config.multipart.bufferThreshold</literal></entry>
+ <entry>
+ <para>
+ Name of the resource property for the threshold size (in bytes) above which a
+ body part entity will be buffered to disk instead of being held in memory.
+ </para>
+ <para>
+ The default value is &jersey.message.MessageProperties.IO_DEFAULT_BUFFER_SIZE;
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.MAX_PARTS;</entry>
+ <entry><literal>jersey.config.multipart.maxParts</literal></entry>
+ <entry>
+ <para>
+ Limit the maximum number of parts the multipart entity can have. If the limit is over,
+ the error response status <literal>413 - REQUEST_ENTITY_TOO_LARGE</literal>
+ is returned.
+ </para>
+ <para>
+ By default, the number is unlimited.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE;</entry>
+ <entry><literal>jersey-multipart-config.properties</literal></entry>
+ <entry>
+ <para>
+ Name of a properties resource that (if found in the classpath
+ for this application) will be used to configure the settings returned
+ by our getter methods.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>&jersey.media.multipart.MultiPartProperties.TEMP_DIRECTORY;</entry>
+ <entry><literal>jersey.config.multipart.tempDir</literal></entry>
+ <entry>
+ <para>
+ Name of the resource property for the directory to store temporary files containing body parts
+ of multipart message that extends allowed memory threshold.
+ </para>
+ <para>
+ The default value is not set (will be taken from <literal>java.io.tmpdir</literal> system property).
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
</appendix>
\ No newline at end of file
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent
index 6c285ea..1822bfb 100644
--- a/docs/src/main/docbook/jersey.ent
+++ b/docs/src/main/docbook/jersey.ent
@@ -536,7 +536,12 @@
<!ENTITY jersey.media.multipart.FormDataParam "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/FormDataParam.html'>@FormDataParam</link>" >
<!ENTITY jersey.media.multipart.MultiPart "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPart.html'>MultiPart</link>" >
<!ENTITY jersey.media.multipart.MultiPartFeature "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartFeature.html'>MultiPartFeature</link>" >
-<!ENTITY jersey.media.multipart.StreamDataBodyPart "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/file/StreamDataBodyPart.html'>StreamDataBodyPart</link>" >
+<!ENTITY jersey.media.multipart.MultiPartProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html'>MultiPartProperties</link>" >
+<!ENTITY jersey.media.multipart.MultiPartProperties.BUFFER_THRESHOLD "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#BUFFER_THRESHOLD'>MultiPartProperties.BUFFER_THRESHOLD</link>">
+<!ENTITY jersey.media.multipart.MultiPartProperties.MAX_PARTS "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#MAX_PARTS'>MultiPartProperties.MAX_PARTS</link>">
+<!ENTITY jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#MULTI_PART_CONFIG_RESOURCE'>MultiPartProperties.MULTI_PART_CONFIG_RESOURCE</link>">
+<!ENTITY jersey.media.multipart.MultiPartProperties.TEMP_DIRECTORY "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/MultiPartProperties.html#TEMP_DIRECTORY'>MultiPartProperties.TEMP_DIRECTORY</link>">
+<!ENTITY jersey.media.multipart.StreamDataBodyPart "<link xlink:href='&jersey.javadoc.uri.prefix;/media/multipart/file/StreamDataBodyPart.html'>StreamDataBodyPart</link>">
<!ENTITY jersey.message.MessageBodyWorkers "<link xlink:href='&jersey.javadoc.uri.prefix;/message/MessageBodyWorkers.html'>MessageBodyWorkers</link>">
<!ENTITY jersey.message.MessageProperties "<link xlink:href='&jersey.javadoc.uri.prefix;/message/MessageProperties.html'>MessageProperties</link>">
<!ENTITY jersey.message.MessageProperties.DEFLATE_WITHOUT_ZLIB "<link xlink:href='&jersey.javadoc.uri.prefix;/message/MessageProperties.html#DEFLATE_WITHOUT_ZLIB'>MessageProperties.DEFLATE_WITHOUT_ZLIB</link>">
diff --git a/docs/src/main/docbook/media.xml b/docs/src/main/docbook/media.xml
index 6849118..dccbe9b 100644
--- a/docs/src/main/docbook/media.xml
+++ b/docs/src/main/docbook/media.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" standalone="no"?>
<!--
- Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -1878,5 +1878,24 @@
</tip>
</section>
</section>
+ <section xml:id="multipart.configuration">
+ <title>Properties for configuring the Multipart</title>
+ <para>
+ There are multiple options that can be used when configuring
+ the multipart. See &jersey.media.multipart.MultiPartProperties; or <xref linkend="appendix-properties-multipart"/>
+ for the possibilities.
+ </para>
+ <para>
+ The options can set in a configuration file specified by the
+ &jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE; property.
+ That is the standard Java properties file.
+ </para>
+ <para>
+ Or the options can be set programmatically,
+ by registering <literal>ContextResolver<MultiPartProperties></literal>. For instance:
+ </para>
+ <programlisting language="java">ResourceConfig resourceConfig = new ResourceConfig();
+resourceConfig.register(new MultiPartProperties().bufferThreshold(65535).maxParts(2).resolver());</programlisting>
+ </section>
</section>
</chapter>
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java
index 68abedb..00d6aba 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
import jakarta.ws.rs.ext.ContextResolver;
import org.glassfish.jersey.internal.util.PropertiesClass;
+import org.glassfish.jersey.message.internal.ReaderWriter;
/**
* Injectable JavaBean containing the configuration parameters for
@@ -38,12 +39,17 @@
/**
* Default threshold size for buffer.
*/
- public static final int DEFAULT_BUFFER_THRESHOLD = 4096;
+ public static final int DEFAULT_BUFFER_THRESHOLD = ReaderWriter.BUFFER_SIZE;
/**
+ * <p>
* Name of a properties resource that (if found in the classpath
* for this application) will be used to configure the settings returned
* by our getter methods.
+ * </p>
+ * <p>
+ * The resource name is {@code jersey-multipart-config.properties}.
+ * </p>
*/
public static final String MULTI_PART_CONFIG_RESOURCE = "jersey-multipart-config.properties";
@@ -51,7 +57,7 @@
* Name of the resource property for the threshold size (in bytes) above which a body part entity will be
* buffered to disk instead of being held in memory.
*
- * The default value is {@value #DEFAULT_BUFFER_THRESHOLD}.
+ * The default value is {@link #DEFAULT_BUFFER_THRESHOLD}.
*/
public static final String BUFFER_THRESHOLD = "jersey.config.multipart.bufferThreshold";
@@ -61,8 +67,20 @@
public static final int BUFFER_THRESHOLD_MEMORY_ONLY = -1;
/**
+ * <p>
+ * Limit the maximum number of parts the multipart entity can have. If the limit is over,
+ * the error response status {@link jakarta.ws.rs.core.Response.Status#REQUEST_ENTITY_TOO_LARGE} is returned.
+ * </p>
+ * <p>
+ * By default, the number is unlimited.
+ * </p>
+ * @since 2.44
+ */
+ public static final String MAX_PARTS = "jersey.config.multipart.maxParts";
+
+ /**
* Name of the resource property for the directory to store temporary files containing body parts of multipart message that
- * extends allowed memory threshold..
+ * extends allowed memory threshold.
*
* The default value is not set (will be taken from {@code java.io.tmpdir} system property).
*/
@@ -80,6 +98,11 @@
private String tempDir = null;
/**
+ * Maximum number of entity parts allowed.
+ */
+ private int maxParts = Integer.MAX_VALUE;
+
+ /**
* Load and customize (if necessary) the configuration values for the
* {@code jersey-multipart} injection binder.
*
@@ -114,6 +137,15 @@
}
/**
+ * Return maximum number of entity parts allowed.
+ * @return maximum number of parts.
+ * @since 2.44
+ */
+ public int getMaxParts() {
+ return maxParts;
+ }
+
+ /**
* Set the size (in bytes) of the entity of an incoming {@link BodyPart} before it will be buffered to disk.
*
* @param threshold size of body part.
@@ -139,6 +171,17 @@
}
/**
+ * Set the maximum number of received parts of a multipart entity.
+ * @param maxParts The maximum number of entity parts.
+ * @return {@code MultiPartProperties} instance.
+ * @since 2.44
+ */
+ public MultiPartProperties maxParts(int maxParts) {
+ this.maxParts = maxParts;
+ return this;
+ }
+
+ /**
* Configure the values returned by this instance's getters based on
* the contents of a properties resource, if it exists on the classpath
* for this application.
@@ -169,6 +212,9 @@
if (props.containsKey(TEMP_DIRECTORY)) {
this.tempDir = props.getProperty(TEMP_DIRECTORY);
}
+ if (props.contains(MAX_PARTS)) {
+ this.maxParts = Integer.parseInt(props.getProperty(MAX_PARTS));
+ }
} catch (final IOException e) {
throw new IllegalArgumentException(e);
} finally {
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java
index d95b320..2da4623 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueParamProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -232,7 +234,13 @@
@Override
public Object apply(ContainerRequest request) {
// Return the field value for the field specified by the sourceName property.
- final List<FormDataBodyPart> parts = getEntity(request).getFields(parameter.getSourceName());
+ final String sourceName = parameter.getAnnotations().length == 1
+ ? parameter.getSourceName()
+ : Arrays.stream(parameter.getAnnotations())
+ .filter(ann -> FormDataParam.class.isInstance(ann))
+ .map(ann -> FormDataParam.class.cast(ann))
+ .findFirst().get().value();
+ final List<FormDataBodyPart> parts = getEntity(request).getFields(sourceName);
final FormDataBodyPart part = parts != null ? parts.get(0) : null;
final MediaType mediaType = part != null ? part.getMediaType() : MediaType.TEXT_PLAIN_TYPE;
@@ -357,34 +365,38 @@
} else {
return null;
}
- } else if (parameter.getSourceAnnotation().annotationType() == FormDataParam.class) {
- final String paramName = parameter.getSourceName();
- if (paramName == null || paramName.isEmpty()) {
- // Invalid query parameter name
- return null;
- }
+ } else {
+ for (Annotation sourceAnnotation : parameter.getAnnotations()) {
+ if (sourceAnnotation.annotationType() == FormDataParam.class) {
+ final String paramName = ((FormDataParam) sourceAnnotation).value(); // sourceName refers to the last anno
+ if (paramName == null || paramName.isEmpty()) {
+ // Invalid query parameter name
+ return null;
+ }
- if (Collection.class == rawType || List.class == rawType) {
- final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
+ if (Collection.class == rawType || List.class == rawType) {
+ final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
- if (FormDataBodyPart.class == clazz) {
- // Return a collection of form data body part.
- return new ListFormDataBodyPartValueProvider(paramName);
- } else if (FormDataContentDisposition.class == clazz) {
- // Return a collection of form data content disposition.
- return new ListFormDataContentDispositionProvider(paramName);
- } else {
- // Return a collection of specific type.
- return new FormDataParamValueProvider(parameter, get(parameter));
+ if (FormDataBodyPart.class == clazz) {
+ // Return a collection of form data body part.
+ return new ListFormDataBodyPartValueProvider(paramName);
+ } else if (FormDataContentDisposition.class == clazz) {
+ // Return a collection of form data content disposition.
+ return new ListFormDataContentDispositionProvider(paramName);
+ } else {
+ // Return a collection of specific type.
+ return new FormDataParamValueProvider(parameter, get(parameter));
+ }
+ } else if (FormDataBodyPart.class == rawType) {
+ return new FormDataBodyPartProvider(paramName);
+ } else if (FormDataContentDisposition.class == rawType) {
+ return new FormDataContentDispositionProvider(paramName);
+ } else if (File.class == rawType) {
+ return new FileProvider(paramName);
+ } else {
+ return new FormDataParamValueProvider(parameter, get(parameter));
+ }
}
- } else if (FormDataBodyPart.class == rawType) {
- return new FormDataBodyPartProvider(paramName);
- } else if (FormDataContentDisposition.class == rawType) {
- return new FormDataContentDispositionProvider(paramName);
- } else if (File.class == rawType) {
- return new FileProvider(paramName);
- } else {
- return new FormDataParamValueProvider(parameter, get(parameter));
}
}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
index c867078..edb80bd 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -28,6 +28,7 @@
import java.util.logging.Logger;
import jakarta.ws.rs.BadRequestException;
+import jakarta.ws.rs.ClientErrorException;
import jakarta.ws.rs.ConstrainedTo;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.RuntimeType;
@@ -36,6 +37,7 @@
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.MessageBodyReader;
import jakarta.ws.rs.ext.Providers;
@@ -79,6 +81,7 @@
*/
private Provider<MessageBodyWorkers> messageBodyWorkers;
private final MIMEConfig mimeConfig;
+ private final int maxParts;
/**
* Accepts constructor injection of the configuration parameters for this
@@ -98,6 +101,8 @@
properties = new MultiPartProperties();
}
+ maxParts = properties.getMaxParts();
+
this.messageBodyWorkers = messageBodyWorkers;
mimeConfig = createMimeConfig(properties);
}
@@ -205,7 +210,12 @@
fileNameFix = userAgent != null && userAgent.contains(" MSIE ");
}
- for (final MIMEPart mimePart : getMimeParts(mimeMessage)) {
+ final List<MIMEPart> mimeParts = getMimeParts(mimeMessage);
+ if (mimeParts.size() > maxParts) {
+ throw new ClientErrorException(Response.Status.REQUEST_ENTITY_TOO_LARGE);
+ }
+
+ for (final MIMEPart mimePart : mimeParts) {
final BodyPart bodyPart = formData ? new FormDataBodyPart(fileNameFix) : new BodyPart();
// Configure providers.
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/OrderParamTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/OrderParamTest.java
new file mode 100644
index 0000000..23cc7a8
--- /dev/null
+++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/OrderParamTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.media.multipart.internal;
+
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.message.internal.ReaderWriter;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.model.ParamQualifier;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class OrderParamTest extends JerseyTest {
+ @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @ParamQualifier
+ public static @interface AnnoWithValue {
+ String value() default "";
+ }
+
+ @Path("/order")
+ public static class OrderTestResource {
+ @POST
+ @Path("/dataAfter")
+ @Consumes(value = MediaType.MULTIPART_FORM_DATA)
+ public String orderBefore(@FormDataParam("file") @AnnoWithValue("xxx") InputStream inputStream) throws IOException {
+ return ReaderWriter.readFromAsString(inputStream, MediaType.TEXT_PLAIN_TYPE);
+ }
+
+ @POST
+ @Path("/dataBefore")
+ @Consumes(value = MediaType.MULTIPART_FORM_DATA)
+ public String orderAfter(@AnnoWithValue("zzz") @FormDataParam("file") InputStream inputStream) throws IOException {
+ return ReaderWriter.readFromAsString(inputStream, MediaType.TEXT_PLAIN_TYPE);
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(OrderTestResource.class).register(MultiPartFeature.class);
+ }
+
+ @Test
+ public void testOrder() {
+ final String MSG = "Hello";
+ FormDataMultiPart multiPart = new FormDataMultiPart();
+ multiPart.field("file", MSG, MediaType.TEXT_PLAIN_TYPE);
+ try (Response response = target("order")
+ .register(MultiPartFeature.class)
+ .path("dataBefore").request()
+ .post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ assertEquals(200, response.getStatus());
+ assertEquals(MSG, response.readEntity(String.class));
+ }
+
+ try (Response response = target("order")
+ .register(MultiPartFeature.class)
+ .path("dataAfter").request()
+ .post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ assertEquals(200, response.getStatus());
+ assertEquals(MSG, response.readEntity(String.class));
+ }
+ }
+}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/RestrictionsTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/RestrictionsTest.java
new file mode 100644
index 0000000..9906f11
--- /dev/null
+++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/RestrictionsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.media.multipart.internal;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.media.multipart.MultiPartProperties;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+public class RestrictionsTest extends JerseyTest {
+ @Path("/")
+ public static class RestrictionsTestResource {
+ @POST
+ @Path("max.parts")
+ public String postMaxPart(@FormDataParam("part1") String part1, @FormDataParam("part2") String part2) {
+ return part1 + part2;
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(RestrictionsTestResource.class)
+ .register(MultiPartFeature.class)
+ .register(new MultiPartProperties().maxParts(2).resolver());
+ }
+
+ @Override
+ protected void configureClient(ClientConfig config) {
+ config.register(MultiPartFeature.class);
+ }
+
+ @Test
+ public void testPassNumberOfParts() {
+ FormDataMultiPart multiPart = new FormDataMultiPart();
+ multiPart.field("part1", "he", MediaType.TEXT_PLAIN_TYPE);
+ multiPart.field("part2", "llo", MediaType.TEXT_PLAIN_TYPE);
+ try (Response r = target("max.parts").request().post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ Assertions.assertEquals(200, r.getStatus());
+ Assertions.assertEquals("hello", r.readEntity(String.class));
+ }
+ }
+
+ @Test
+ public void testFailsNumberOfParts() {
+ FormDataMultiPart multiPart = new FormDataMultiPart();
+ multiPart.field("part1", "he", MediaType.TEXT_PLAIN_TYPE);
+ multiPart.field("part2", "llo", MediaType.TEXT_PLAIN_TYPE);
+ multiPart.field("part3", "!", MediaType.TEXT_PLAIN_TYPE);
+ try (Response r = target("max.parts").request().post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+ Assertions.assertEquals(Response.Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode(), r.getStatus());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 701e0f7..8261cea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2116,7 +2116,6 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- <release.tests.args>-Dmaven.test.skip=false</release.tests.args>-->
<!-- <release.preparationGoals>clean install</release.preparationGoals>-->
- <skip.e2e>false</skip.e2e>
<skip.tests>false</skip.tests>
<xdk.absolute.path />
<surefire.security.argline />
diff --git a/tests/e2e/pom.xml b/tests/e2e/pom.xml
index 024afea..94d1d8e 100644
--- a/tests/e2e/pom.xml
+++ b/tests/e2e/pom.xml
@@ -41,7 +41,6 @@
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<enableAssertions>false</enableAssertions>
- <skipTests>${skip.e2e}</skipTests>
<excludes>
<!--TODO remove after jakartification-->
<exclude>org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java</exclude>