Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public final class RequestUtils {

public static final String EMPTY_BODY = "";

private static final int MAX_FORM_PARAMS = 1000;

private RequestUtils() {}

public static boolean isRestRequest(HttpRequest request) {
Expand Down Expand Up @@ -97,8 +99,13 @@ public static Map<String, List<String>> getFormParametersMap(HttpRequest request
if (paramNames.isEmpty()) {
return Collections.emptyMap();
}
Map<String, List<String>> params = CollectionUtils.newLinkedHashMap(paramNames.size());
int limit = Math.min(paramNames.size(), MAX_FORM_PARAMS);
Map<String, List<String>> params = CollectionUtils.newLinkedHashMap(limit);
int count = 0;
for (String paramName : paramNames) {
if (count++ >= MAX_FORM_PARAMS) {
break;
}
params.put(paramName, request.formParameterValues(paramName));
}
return params;
Expand Down
56 changes: 56 additions & 0 deletions src/test/java/RequestUtilsInvariantTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.apache.dubbo.rpc.protocol.tri.rest.util;

import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HttpRequest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

class RequestUtilsSecurityTest {

@ParameterizedTest
@ValueSource(ints = {1000000, 100000, 10})
void testFormParametersMapMaintainsMemoryBounds(int paramCount) {
// Invariant: Processing form parameters must not consume unbounded memory

HttpRequest mockRequest = new HttpRequest() {
private final Set<String> names = generateParamNames(paramCount);

@Override
public Collection<String> formParameterNames() {
return names;
}

@Override
public List<String> formParameterValues(String name) {
return Collections.singletonList("value");
}
};

long beforeMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

Map<String, List<String>> result = RequestUtils.getFormParametersMap(mockRequest);

long afterMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
long memoryUsed = afterMemory - beforeMemory;

// Memory usage should be proportional to input size with reasonable constant factor
long maxExpectedMemory = paramCount * 200L; // ~200 bytes per parameter (generous bound)

assertTrue(memoryUsed < maxExpectedMemory || paramCount <= 10,
String.format("Memory usage %d exceeded bound %d for %d parameters",
memoryUsed, maxExpectedMemory, paramCount));

assertEquals(paramCount, result.size());
}

private Set<String> generateParamNames(int count) {
Set<String> names = new HashSet<>();
for (int i = 0; i < count; i++) {
names.add("param" + i);
}
return names;
}
}
Loading