From 8fa428f825323d6bc0d3051ad44d84a249fcaf39 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Fri, 29 Sep 2023 17:59:02 +0100 Subject: [PATCH] Skip reconstructing body from request params if query present This allows restoring optimization in StringHttpMessageConverter that was undone in 23162b for 6.0.x. Closes gh-31327 --- .../converter/StringHttpMessageConverter.java | 6 ++++- .../http/server/ServletServerHttpRequest.java | 2 +- .../server/ServletServerHttpRequestTests.java | 22 ++++++++++++++----- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java index 8b8793e277..5a408d8749 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java @@ -93,7 +93,11 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter clazz, HttpInputMessage inputMessage) throws IOException { Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType()); - return StreamUtils.copyToString(inputMessage.getBody(), charset); + long length = inputMessage.getHeaders().getContentLength(); + byte[] bytes = (length >= 0 && length <= Integer.MAX_VALUE ? + inputMessage.getBody().readNBytes((int) length) : + inputMessage.getBody().readAllBytes()); + return new String(bytes, charset); } @Override diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java index ee2af3a17e..47789cf114 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java @@ -209,7 +209,7 @@ public class ServletServerHttpRequest implements ServerHttpRequest { @Override public InputStream getBody() throws IOException { - if (isFormPost(this.servletRequest)) { + if (isFormPost(this.servletRequest) && this.servletRequest.getQueryString() == null) { return getBodyFromServletRequestParameters(this.servletRequest); } else { diff --git a/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java b/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java index d2ccc761e7..91eb6c1a1f 100644 --- a/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -167,9 +167,8 @@ public class ServletServerHttpRequestTests { assertThat(result).as("Invalid content returned").isEqualTo(content); } - @Test + @Test // gh-13318 void getFormBody() throws IOException { - // Charset (SPR-8676) mockRequest.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); mockRequest.setMethod("POST"); mockRequest.addParameter("name 1", "value 1"); @@ -177,8 +176,7 @@ public class ServletServerHttpRequestTests { mockRequest.addParameter("name 3", (String) null); byte[] result = FileCopyUtils.copyToByteArray(request.getBody()); - byte[] content = "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3".getBytes( - StandardCharsets.UTF_8); + byte[] content = "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3".getBytes(StandardCharsets.UTF_8); assertThat(result).as("Invalid content returned").isEqualTo(content); } @@ -192,4 +190,18 @@ public class ServletServerHttpRequestTests { assertThat(result).as("Invalid content returned").isEqualTo(content); } + @Test // gh-31327 + void getFormBodyWhenQueryParamsAlsoPresent() throws IOException { + mockRequest.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); + mockRequest.setMethod("POST"); + mockRequest.setQueryString("q=1"); + mockRequest.addParameter("q", "1"); + mockRequest.setContent("foo=bar".getBytes(StandardCharsets.UTF_8)); + mockRequest.addHeader("Content-Length", 7); + + byte[] result = FileCopyUtils.copyToByteArray(request.getBody()); + byte[] content = "foo=bar".getBytes(StandardCharsets.UTF_8); + assertThat(result).as("Invalid content returned").isEqualTo(content); + } + }