This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new 1a16a0a2879 Introduce default value for maxFormParameterCount (#3177)
1a16a0a2879 is described below
commit 1a16a0a28799a119472f0f54c297dc9799c32b5a
Author: Andriy Redko <[email protected]>
AuthorDate: Thu Jun 4 11:40:57 2026 -0400
Introduce default value for maxFormParameterCount (#3177)
---
.../java/org/apache/cxf/jaxrs/utils/FormUtils.java | 9 +-
.../org/apache/cxf/jaxrs/utils/FormUtilsTest.java | 137 ++++++++++++++++++---
2 files changed, 122 insertions(+), 24 deletions(-)
diff --git
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java
index f8443785baa..44f3a6d0b7e 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java
@@ -54,6 +54,8 @@ import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
public final class FormUtils {
+ public static final int DEFAULT_MAX_FORM_PARAM_COUNT = 500;
+
public static final String FORM_PARAMS_FROM_HTTP_PARAMS =
"set.form.parameters.from.http.parameters";
public static final String FORM_PARAM_MAP = "org.apache.cxf.form_data";
public static final String FORM_PARAM_MAP_DECODED =
"org.apache.cxf.form_data.decoded";
@@ -290,11 +292,8 @@ public final class FormUtils {
if (m == null || m.getExchange() == null ||
m.getExchange().getInMessage() == null) {
return;
}
- String maxPartsCountProp = (String)m.getExchange()
- .getInMessage().getContextualProperty(MAX_FORM_PARAM_COUNT);
- if (maxPartsCountProp == null) {
- return;
- }
+ final String maxPartsCountProp =
MessageUtils.getContextualString(m.getExchange().getInMessage(),
+ MAX_FORM_PARAM_COUNT,
Integer.toString(DEFAULT_MAX_FORM_PARAM_COUNT));
try {
int maxPartsCount = Integer.parseInt(maxPartsCountProp);
if (maxPartsCount != -1 && numberOfParts >= maxPartsCount) {
diff --git
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
index 61a5844ce22..fedde8d08fd 100644
---
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
+++
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
@@ -19,40 +19,59 @@
package org.apache.cxf.jaxrs.utils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.EntityPart;
+import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
+import org.apache.cxf.jaxrs.ext.multipart.Attachment;
+import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.Message;
import org.junit.Test;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class FormUtilsTest {
-
- private static final String HTTP_PARAM1 = "httpParam1";
- private static final String HTTP_PARAM2 = "httpParam2";
- private static final String HTTP_PARAM_VALUE1 = "httpValue1";
- private static final String HTTP_PARAM_VALUE2 = "httpValue2";
-
- private static final String FORM_PARAM1 = "formParam1";
- private static final String FORM_PARAM2 = "formParam2";
- private static final String FORM_PARAM_VALUE1 = "formValue1";
- private static final String FORM_PARAM_VALUE2 = "formValue2";
+ private static final String HTTP_PARAM = "httpParam";
+ private static final String HTTP_PARAM1 = HTTP_PARAM + "1";
+ private static final String HTTP_PARAM2 = HTTP_PARAM + "2";
+ private static final String HTTP_PARAM_VALUE = "httpValue";
+ private static final String HTTP_PARAM_VALUE1 = HTTP_PARAM_VALUE + "1";
+ private static final String HTTP_PARAM_VALUE2 = HTTP_PARAM_VALUE + "2";
+
+ private static final String FORM_PARAM = "formParam";
+ private static final String FORM_PARAM1 = FORM_PARAM + "1";
+ private static final String FORM_PARAM2 = FORM_PARAM + "2";
+ private static final String FORM_PARAM_VALUE = "formValue";
+ private static final String FORM_PARAM_VALUE1 = FORM_PARAM_VALUE + "1";
+ private static final String FORM_PARAM_VALUE2 = FORM_PARAM_VALUE + "2";
private Message mockMessage;
private HttpServletRequest mockRequest;
@Test
public void populateMapFromStringFromHTTP() {
- mockObjects(null);
+ mockObjects(null, 2);
MultivaluedMap<String, String> params = new MetadataMap<>();
FormUtils.populateMapFromString(params, mockMessage, null,
StandardCharsets.UTF_8.name(),
@@ -65,7 +84,7 @@ public class FormUtilsTest {
@Test
public void populateMapFromStringFromHTTPWithProp() {
- mockObjects("false");
+ mockObjects("false", 2);
MultivaluedMap<String, String> params = new MetadataMap<>();
FormUtils.populateMapFromString(params, mockMessage, null,
StandardCharsets.UTF_8.name(),
@@ -76,7 +95,7 @@ public class FormUtilsTest {
@Test
public void populateMapFromStringFromBody() {
- mockObjects(null);
+ mockObjects(null, 2);
MultivaluedMap<String, String> params = new MetadataMap<>();
String postBody = FORM_PARAM1 + "=" + FORM_PARAM_VALUE1 + "&" +
FORM_PARAM2 + "=" + FORM_PARAM_VALUE2;
@@ -89,19 +108,99 @@ public class FormUtilsTest {
}
- private void mockObjects(String formPropertyValue) {
+ @Test
+ public void populateMapFromBodyExceedsDefaultMaxFormParams() {
+ mockObjects(null, FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT);
+
+ final MultivaluedMap<String, String> params = new MetadataMap<>();
+ final String postBody = IntStream
+ .range(1, FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT + 1)
+ .mapToObj(i -> FORM_PARAM + i + "=" + FORM_PARAM_VALUE + i)
+ .collect(Collectors.joining("&"));
+ final WebApplicationException ex =
assertThrows(WebApplicationException.class,
+ () -> FormUtils.populateMapFromString(params, mockMessage,
postBody,
+ StandardCharsets.UTF_8.name(), false));
+ assertThat(ex.getResponse().getStatus(), equalTo(413)); /* Request
Entity Too Large */
+
+ // Increase the limit and try again
+ when(mockMessage.getContextualProperty("maxFormParameterCount"))
+
.thenReturn(Integer.toString(FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT + 1));
+ FormUtils.populateMapFromString(params, mockMessage, null,
StandardCharsets.UTF_8.name(), false, mockRequest);
+ assertEquals(500, params.size());
+ }
+
+ @Test
+ public void populateMapFromMultiPartExceedsDefaultMaxFormParams() {
+ mockObjects(null, FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT);
+
+ final MultivaluedMap<String, String> params = new MetadataMap<>();
+ final MultipartBody body = new MultipartBody(IntStream
+ .range(1, FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT + 1)
+ .mapToObj(i -> {
+ final MultivaluedMap<String, String> headers = new
MetadataMap<>();
+ headers.putSingle("Content-ID",
UUID.randomUUID().toString());
+ return new Attachment(InputStream.nullInputStream(),
headers);
+ })
+ .toList());
+ final WebApplicationException ex =
assertThrows(WebApplicationException.class,
+ () -> FormUtils.populateMapFromMultipart(params, body,
mockMessage, false));
+ assertThat(ex.getResponse().getStatus(), equalTo(413)); /* Request
Entity Too Large */
+
+ // Increase the limit and try again
+ when(mockMessage.getContextualProperty("maxFormParameterCount"))
+
.thenReturn(Integer.toString(FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT + 1));
+ FormUtils.populateMapFromMultipart(params, body, mockMessage, false);
+ assertEquals(500, params.size());
+ }
+
+ @Test
+ public void populateMapFromEntrityPartExceedsDefaultMaxFormParams() {
+ mockObjects(null, FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT);
+
+ final MultivaluedMap<String, String> params = new MetadataMap<>();
+ final List<EntityPart> body = IntStream
+ .range(1, FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT + 1)
+ .mapToObj(i -> {
+ try {
+ return
EntityPart.withName(UUID.randomUUID().toString())
+ .mediaType(MediaType.APPLICATION_OCTET_STREAM)
+ .content(InputStream.nullInputStream())
+ .build();
+ } catch (final IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ })
+ .toList();
+ final WebApplicationException ex =
assertThrows(WebApplicationException.class,
+ () -> FormUtils.populateMapFromEntityParts(params, body,
mockMessage, false));
+ assertThat(ex.getResponse().getStatus(), equalTo(413)); /* Request
Entity Too Large */
+
+ // Increase the limit and try again
+ when(mockMessage.getContextualProperty("maxFormParameterCount"))
+
.thenReturn(Integer.toString(FormUtils.DEFAULT_MAX_FORM_PARAM_COUNT + 1));
+ FormUtils.populateMapFromEntityParts(params, body, mockMessage, false);
+ assertEquals(500, params.size());
+ }
+
+ private void mockObjects(String formPropertyValue, int params) {
+ final ExchangeImpl exchange = new ExchangeImpl();
+
mockMessage = mock(Message.class);
when(mockMessage.getContextualProperty(FormUtils.FORM_PARAMS_FROM_HTTP_PARAMS))
.thenReturn(formPropertyValue);
- when(mockMessage.getExchange()).thenReturn(null);
+ when(mockMessage.getExchange()).thenReturn(exchange);
when(mockMessage.put(FormUtils.FORM_PARAM_MAP_DECODED, true))
.thenReturn(null);
-
+ exchange.setInMessage(mockMessage);
+
mockRequest = mock(HttpServletRequest.class);
- String[] httpParamNames = {HTTP_PARAM1, HTTP_PARAM2};
+ String[] httpParamNames = IntStream.range(1, params + 1)
+ .mapToObj(i -> "httpParam" + i)
+ .toArray(String[]::new);
Enumeration<String> httpParamsEnum =
Collections.enumeration(Arrays.asList(httpParamNames));
when(mockRequest.getParameterNames()).thenReturn(httpParamsEnum);
- when(mockRequest.getParameterValues(HTTP_PARAM1)).thenReturn(new
String[] {HTTP_PARAM_VALUE1});
- when(mockRequest.getParameterValues(HTTP_PARAM2)).thenReturn(new
String[] {HTTP_PARAM_VALUE2});
+ for (int i = 1; i <= httpParamNames.length; ++i) {
+ when(mockRequest.getParameterValues(HTTP_PARAM +
i)).thenReturn(new String[] {HTTP_PARAM_VALUE + i});
+ }
}
}
\ No newline at end of file