This commit replaces the initial allocation size for the content caching
buffer by a `FastByteArrayOutputStream`. With this variant, allocations
are cheap and we don't need to apply heuristics anymore to guess the
best initial buffer size.

See gh-29775
This commit is contained in:
Brian Clozel 2023-09-11 10:58:01 +02:00
parent 6de0be16c2
commit f83c609436
1 changed files with 4 additions and 12 deletions

View File

@ -17,7 +17,6 @@
package org.springframework.web.util; package org.springframework.web.util;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URLEncoder; import java.net.URLEncoder;
@ -36,6 +35,7 @@ import jakarta.servlet.http.HttpServletRequestWrapper;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.FastByteArrayOutputStream;
/** /**
* {@link jakarta.servlet.http.HttpServletRequest} wrapper that caches all content read from * {@link jakarta.servlet.http.HttpServletRequest} wrapper that caches all content read from
@ -56,9 +56,7 @@ import org.springframework.lang.Nullable;
*/ */
public class ContentCachingRequestWrapper extends HttpServletRequestWrapper { public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
private static final int DEFAULT_BUFFER_SIZE = 1024; private final FastByteArrayOutputStream cachedContent = new FastByteArrayOutputStream();
private final ByteArrayOutputStream cachedContent;
@Nullable @Nullable
private final Integer contentCacheLimit; private final Integer contentCacheLimit;
@ -76,9 +74,6 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
*/ */
public ContentCachingRequestWrapper(HttpServletRequest request) { public ContentCachingRequestWrapper(HttpServletRequest request) {
super(request); super(request);
int contentLength = request.getContentLength();
this.cachedContent = new ByteArrayOutputStream(contentLength >= 0 ?
contentLength : DEFAULT_BUFFER_SIZE);
this.contentCacheLimit = null; this.contentCacheLimit = null;
} }
@ -91,9 +86,6 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
*/ */
public ContentCachingRequestWrapper(HttpServletRequest request, int contentCacheLimit) { public ContentCachingRequestWrapper(HttpServletRequest request, int contentCacheLimit) {
super(request); super(request);
int contentLength = request.getContentLength();
int initialBufferSize = contentLength >= 0 ? contentLength : DEFAULT_BUFFER_SIZE;
this.cachedContent = new ByteArrayOutputStream(Math.min(initialBufferSize, contentCacheLimit));
this.contentCacheLimit = contentCacheLimit; this.contentCacheLimit = contentCacheLimit;
} }
@ -213,7 +205,7 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
* @see #getContentAsByteArray() * @see #getContentAsByteArray()
*/ */
public String getContentAsString() { public String getContentAsString() {
return this.cachedContent.toString(Charset.forName(getCharacterEncoding())); return new String(this.cachedContent.toByteArray(), Charset.forName(getCharacterEncoding()));
} }
/** /**
@ -262,7 +254,7 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
return count; return count;
} }
private void writeToCache(final byte[] b, final int off, int count) { private void writeToCache(final byte[] b, final int off, int count) throws IOException{
if (!this.overflow && count > 0) { if (!this.overflow && count > 0) {
if (contentCacheLimit != null && if (contentCacheLimit != null &&
count + cachedContent.size() > contentCacheLimit) { count + cachedContent.size() > contentCacheLimit) {