From 15c4e34716e3e19d4f3a9d5d1f03de1e0e45b653 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 10 Jun 2013 14:11:26 +0200 Subject: [PATCH] DATACMNS-335 - PageableHandlerMethodArgumentResolver now has configurable max page size. The default is set to 2000. --- ...PageableHandlerMethodArgumentResolver.java | 20 +++++++++--- .../data/web/PageableDefaultUnitTest.java | 13 +++++--- ...HandlerMethodArgumentResolverUnitTest.java | 31 +++++++++++++++++-- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java index 8e834eac1..e68fadb53 100644 --- a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java @@ -47,8 +47,7 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum * that if you need to stick to the former request parameters an 1-indexed behavior. This will be removed in the next * major version (1.7). So consider migrating to the new way of exposing request parameters. */ - @Deprecated - public static final PageableHandlerMethodArgumentResolver LEGACY; + @Deprecated public static final PageableHandlerMethodArgumentResolver LEGACY; static { LEGACY = new PageableHandlerMethodArgumentResolver(); @@ -65,6 +64,7 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum private static final String DEFAULT_SIZE_PROPERTY = "size"; private static final String DEFAULT_PREFIX = ""; private static final String DEFAULT_QUALIFIER_SEPARATOR = "_"; + private static final int DEFAULT_MAX_PAGE_SIZE = 2000; private Pageable fallbackPageable = DEFAULT_PAGE_REQUEST; private SortHandlerMethodArgumentResolver sortResolver = new SortHandlerMethodArgumentResolver(); @@ -72,6 +72,7 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum private String sizeProperty = DEFAULT_SIZE_PROPERTY; private String prefix = DEFAULT_PREFIX; private String qualifierSeparator = DEFAULT_QUALIFIER_SEPARATOR; + private int maxPageSize = DEFAULT_MAX_PAGE_SIZE; private boolean oneIndexedParameters = false; /** @@ -88,6 +89,16 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum this.fallbackPageable = fallbackPageable; } + /** + * Configures the maximum page size to be accepted. This allows to put an upper boundary of the page size to prevent + * potential attacks trying to issue an {@link OutOfMemoryError}. Defaults to {@link #DEFAULT_MAX_PAGE_SIZE}. + * + * @param maxPageSize the maxPageSize to set + */ + public void setMaxPageSize(int maxPageSize) { + this.maxPageSize = maxPageSize; + } + /** * Configures the parameter name to be used to find the page number in the request. Defaults to {@code page}. * @@ -173,12 +184,12 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum Pageable pageable = (Pageable) value; String pagePropertyName = getParameterNameToUse(pageProperty, parameter); - String propertyToLookup = getParameterNameToUse(sizeProperty, parameter); + String sizePropertyName = getParameterNameToUse(sizeProperty, parameter); int pageNumber = pageable.getPageNumber(); builder.queryParam(pagePropertyName, oneIndexedParameters ? pageNumber + 1 : pageNumber); - builder.queryParam(propertyToLookup, pageable.getPageSize()); + builder.queryParam(sizePropertyName, pageable.getPageSize() <= maxPageSize ? pageable.getPageSize() : maxPageSize); sortResolver.enhance(builder, parameter, pageable.getSort()); } @@ -201,6 +212,7 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum : defaultOrFallback.getPageNumber(); int pageSize = StringUtils.hasText(pageSizeString) ? Integer.parseInt(pageSizeString) : defaultOrFallback .getPageSize(); + pageSize = pageSize > maxPageSize ? maxPageSize : pageSize; Sort sort = sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory); return new PageRequest(page, pageSize, sort == null ? defaultOrFallback.getSort() : sort); diff --git a/src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java b/src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java index 439e147fa..a9d0c88f0 100644 --- a/src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java +++ b/src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java @@ -27,6 +27,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.util.UriComponentsBuilder; @@ -48,8 +49,7 @@ public abstract class PageableDefaultUnitTest { static final PageRequest REFERENCE_WITH_SORT = new PageRequest(PAGE_NUMBER, PAGE_SIZE, SORT); static final PageRequest REFERENCE_WITH_SORT_FIELDS = new PageRequest(PAGE_NUMBER, PAGE_SIZE, new Sort(SORT_FIELDS)); - @Rule - public ExpectedException exception = ExpectedException.none(); + @Rule public ExpectedException exception = ExpectedException.none(); @Test public void supportsPageable() { @@ -124,11 +124,16 @@ public abstract class PageableDefaultUnitTest { resolver.resolveArgument(parameter, null, TestUtils.getWebRequest(), null); } - private void assertSupportedAndResult(MethodParameter parameter, Pageable pageable) throws Exception { + protected void assertSupportedAndResult(MethodParameter parameter, Pageable pageable) throws Exception { + assertSupportedAndResult(parameter, pageable, TestUtils.getWebRequest()); + } + + protected void assertSupportedAndResult(MethodParameter parameter, Pageable pageable, NativeWebRequest request) + throws Exception { HandlerMethodArgumentResolver resolver = getResolver(); assertThat(resolver.supportsParameter(parameter), is(true)); - assertThat(resolver.resolveArgument(parameter, null, TestUtils.getWebRequest(), null), is((Object) pageable)); + assertThat(resolver.resolveArgument(parameter, null, request, null), is((Object) pageable)); } protected void assertUriStringFor(Pageable pageable, String expected) { diff --git a/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java b/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java index a63692da6..c0f313976 100644 --- a/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java +++ b/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java @@ -17,9 +17,13 @@ package org.springframework.data.web; import org.junit.Test; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.MethodParameter; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.web.SortDefault.SortDefaults; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.request.ServletWebRequest; /** * Unit tests for {@link PageableHandlerMethodArgumentResolver}. Pulls in defaulting tests from @@ -39,9 +43,30 @@ public class PageableHandlerMethodArgumentResolverUnitTest extends PageableDefau assertUriStringFor(REFERENCE_WITH_SORT_FIELDS, basicString + "&sort=firstname,lastname,asc"); } + /** + * @see DATACMNS-335 + */ + @Test + public void preventsPageSizeFromExceedingMayValueIfConfigured() throws Exception { + + // Write side + assertUriStringFor(new PageRequest(0, 200), "page=0&size=100"); + + // Read side + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("page", "0"); + request.addParameter("size", "200"); + + MethodParameter parameter = new MethodParameter(Sample.class.getMethod("supportedMethod", Pageable.class), 0); + + assertSupportedAndResult(parameter, new PageRequest(0, 100), new ServletWebRequest(request)); + } + @Override protected PageableHandlerMethodArgumentResolver getResolver() { - return new PageableHandlerMethodArgumentResolver(); + PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver(); + resolver.setMaxPageSize(100); + return resolver; } @Override @@ -57,8 +82,8 @@ public class PageableHandlerMethodArgumentResolverUnitTest extends PageableDefau void simpleDefault(@PageableDefault(size = PAGE_SIZE, page = PAGE_NUMBER) Pageable pageable); - void simpleDefaultWithSort( - @PageableDefault(size = PAGE_SIZE, page = PAGE_NUMBER, sort = { "firstname", "lastname" }) Pageable pageable); + void simpleDefaultWithSort(@PageableDefault(size = PAGE_SIZE, page = PAGE_NUMBER, + sort = { "firstname", "lastname" }) Pageable pageable); void simpleDefaultWithSortAndDirection(@PageableDefault(size = PAGE_SIZE, page = PAGE_NUMBER, sort = { "firstname", "lastname" }, direction = Direction.DESC) Pageable pageable);