This is an automated email from the ASF dual-hosted git repository.

fmariani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git


The following commit(s) were added to refs/heads/main by this push:
     new 6f9d1b650a2 CAMEL-23320: useReaderForPayload corrupts non-text request 
bodies under Spring Boot's default UTF-8 charset (#1747)
6f9d1b650a2 is described below

commit 6f9d1b650a247cad5f8365b8c78dc1b130b25ebc
Author: Federico Mariani <[email protected]>
AuthorDate: Wed Apr 15 11:14:19 2026 +0200

    CAMEL-23320: useReaderForPayload corrupts non-text request bodies under 
Spring Boot's default UTF-8 charset (#1747)
    
    * CAMEL-23320: Fix platform-http binary data corruption and align 
useStreaming with Vert.x
    
    * CAMEL-23320: Fix flaky request timeout test by widening timeout margin
    
    * Adds reproducer for CAMEL-23320
    
    ---------
    
    Co-authored-by: Marco Carletti <[email protected]>
---
 .../http/springboot/PlatformHttpMessage.java       |  21 ++--
 .../springboot/SpringBootPlatformHttpBinding.java  |  26 ++++-
 .../springboot/SpringBootPlatformHttpConsumer.java |   8 +-
 .../springboot/PlatformHttpBinaryUploadTest.java   | 128 ++++++++++++++++++++
 .../http/springboot/PlatformHttpStreamingTest.java |  82 ++++++++++++-
 .../SpringBootPlatformHttpCertificationTest.java   |   1 -
 ...gBootPlatformHttpHeaderFilterStrategyTest.java} |  71 +++++++-----
 .../SpringBootPlatformHttpRequestTimeoutTest.java  |   2 +-
 .../SpringBootPlatformHttpResponseCodeTest.java    | 129 +++++++++++++++++++++
 .../component/platform/http/springboot/example.pdf | Bin 0 -> 553 bytes
 10 files changed, 423 insertions(+), 45 deletions(-)

diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/PlatformHttpMessage.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/PlatformHttpMessage.java
index e106bb554ce..e22f7a57269 100644
--- 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/PlatformHttpMessage.java
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/PlatformHttpMessage.java
@@ -33,6 +33,7 @@ public class PlatformHttpMessage extends DefaultMessage {
     private HttpServletResponse response;
     private HttpBinding binding;
     private boolean requestRead;
+    private boolean streaming;
 
     public PlatformHttpMessage(Exchange exchange, HttpBinding binding, 
HttpServletRequest request,
                                HttpServletResponse response) {
@@ -41,12 +42,12 @@ public class PlatformHttpMessage extends DefaultMessage {
     }
 
     public PlatformHttpMessage(HttpServletRequest request, HttpServletResponse 
response, Exchange exchange,
-                                HttpBinding binding, boolean requestRead) {
+                                HttpBinding binding, boolean streaming) {
         super(exchange);
         this.request = request;
         this.response = response;
         this.binding = binding;
-        this.requestRead = requestRead;
+        this.streaming = streaming;
     }
 
     public void init(Exchange exchange, HttpBinding binding, 
HttpServletRequest request, HttpServletResponse response) {
@@ -62,12 +63,16 @@ public class PlatformHttpMessage extends DefaultMessage {
         if (flag != null && flag) {
             this.setHeader("CamelSkipWwwFormUrlEncoding", Boolean.TRUE);
         }
-        // we need to favor using stream cache so the body can be re-read 
later when routing the message
-        StreamCache newBody = 
camelContext.getTypeConverter().tryConvertTo(StreamCache.class,
-                exchange, getBody());
-        if (newBody != null) {
-            setBody(newBody);
+        if (streaming) {
+            // when streaming, use CachedOutputStream via HttpHelper for 
disk-spoolable large payload support
+            // the body will be an InputStreamCache (re-readable StreamCache)
+            StreamCache newBody = 
camelContext.getTypeConverter().tryConvertTo(StreamCache.class,
+                    exchange, getBody());
+            if (newBody != null) {
+                setBody(newBody);
+            }
         }
+        // when not streaming, the body is already a byte[] (re-readable, no 
conversion needed)
         binding.readRequest(request, this);
     }
 
@@ -105,7 +110,7 @@ public class PlatformHttpMessage extends DefaultMessage {
     }
 
     public PlatformHttpMessage newInstance() {
-        PlatformHttpMessage answer = new PlatformHttpMessage(this.request, 
this.response, this.getExchange(), this.binding, this.requestRead);
+        PlatformHttpMessage answer = new PlatformHttpMessage(this.request, 
this.response, this.getExchange(), this.binding, this.streaming);
         if (answer.camelContext == null) {
             answer.setCamelContext(this.camelContext);
         }
diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpBinding.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpBinding.java
index 7e92af3f625..a69a8ea151f 100644
--- 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpBinding.java
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpBinding.java
@@ -64,6 +64,7 @@ import java.util.UUID;
 public class SpringBootPlatformHttpBinding extends DefaultHttpBinding {
     private static final Logger LOG = 
LoggerFactory.getLogger(SpringBootPlatformHttpBinding.class);
 
+    private boolean streaming;
     private static final String CONTENT_TYPE_FORM_URLENCODED = 
"application/x-www-form-urlencoded";
     private static final List<Method> METHODS_WITH_BODY_ALLOWED = 
List.of(Method.POST,
             Method.PUT, Method.PATCH, Method.DELETE);
@@ -149,6 +150,10 @@ public class SpringBootPlatformHttpBinding extends 
DefaultHttpBinding {
         }
     }
 
+    public void setStreaming(boolean streaming) {
+        this.streaming = streaming;
+    }
+
     public Object parseBody(HttpServletRequest request, Message message) 
throws IOException {
         if (request instanceof StandardMultipartHttpServletRequest ||
                 // In case of Spring FormContentFilter
@@ -156,7 +161,24 @@ public class SpringBootPlatformHttpBinding extends 
DefaultHttpBinding {
             return null;
         }
 
-        return super.parseBody(request, message);
+        int len = request.getContentLength();
+        if (len == 0) {
+            return null;
+        }
+
+        if (streaming) {
+            // use CachedOutputStream for disk-spoolable large payload support 
(like Vert.x streaming)
+            return super.parseBody(request, message);
+        } else {
+            // read entire body into byte[] for fast in-memory access (like 
Vert.x Buffer)
+            if (len > 0) {
+                // known content-length: single allocation, no internal array 
copies
+                return request.getInputStream().readNBytes(len);
+            }
+            // unknown content-length (-1): fall back to incremental read
+            byte[] body = request.getInputStream().readAllBytes();
+            return body.length == 0 ? null : body;
+        }
     }
 
     @Override
@@ -169,7 +191,7 @@ public class SpringBootPlatformHttpBinding extends 
DefaultHttpBinding {
     private static void populateMultiFormData(HttpServletRequest request, 
Message message) {
         if (((PlatformHttpEndpoint) 
message.getExchange().getFromEndpoint()).isPopulateBodyWithForm() &&
                 
METHODS_WITH_BODY_ALLOWED.contains(Method.valueOf(request.getMethod())) &&
-                (message.getBody() instanceof StreamCache ||
+                (message.getBody() instanceof StreamCache || message.getBody() 
instanceof byte[] ||
                         (message.getBody() == null && 
!"POST".equals(request.getMethod()))) &&
                 request.getContentType() != null &&
                 
request.getContentType().contains(CONTENT_TYPE_FORM_URLENCODED)) {
diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpConsumer.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpConsumer.java
index 0755375c58b..2b86c7878d0 100644
--- 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpConsumer.java
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpConsumer.java
@@ -54,11 +54,12 @@ public class SpringBootPlatformHttpConsumer extends 
DefaultConsumer implements P
 
     public SpringBootPlatformHttpConsumer(PlatformHttpEndpoint endpoint, 
Processor processor) {
         super(endpoint, processor);
-        this.binding = new SpringBootPlatformHttpBinding();
+        SpringBootPlatformHttpBinding httpBinding = new 
SpringBootPlatformHttpBinding();
+        httpBinding.setStreaming(endpoint.isUseStreaming());
+        this.binding = httpBinding;
         
this.binding.setHeaderFilterStrategy(endpoint.getHeaderFilterStrategy());
         this.binding.setMuteException(endpoint.isMuteException());
         
this.binding.setFileNameExtWhitelist(endpoint.getFileNameExtWhitelist());
-        this.binding.setUseReaderForPayload(!endpoint.isUseStreaming());
         this.handleWriteResponseError = endpoint.isHandleWriteResponseError();
         this.executor = Executors.newSingleThreadExecutor();
     }
@@ -117,7 +118,8 @@ public class SpringBootPlatformHttpConsumer extends 
DefaultConsumer implements P
         Exchange exchange = createExchange(true);
         exchange.setPattern(ExchangePattern.InOut);
         HttpHelper.setCharsetFromContentType(request.getContentType(), 
exchange);
-        PlatformHttpMessage msg = new PlatformHttpMessage(request, response, 
exchange,binding, false);
+        boolean streaming = getEndpoint().isUseStreaming();
+        PlatformHttpMessage msg = new PlatformHttpMessage(request, response, 
exchange, binding, streaming);
         exchange.setIn(msg);
         msg.init(exchange, binding, request, response);
         String contextPath = getEndpoint().getPath();
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpBinaryUploadTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpBinaryUploadTest.java
new file mode 100644
index 00000000000..40e2c612c81
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpBinaryUploadTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.platform.http.springboot;
+
+import io.restassured.RestAssured;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit6.CamelSpringBootTest;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import 
org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.web.SecurityFilterChain;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests binary file upload through platform-http REST DSL.
+ * Reproducer for <a 
href="https://issues.apache.org/jira/browse/CAMEL-23320";>CAMEL-23320</a>:
+ * binary data corruption caused by Reader-based parsing in non-streaming mode.
+ */
+@EnableAutoConfiguration
+@CamelSpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 
classes = { CamelAutoConfiguration.class,
+        SpringBootPlatformHttpTest.class, 
PlatformHttpBinaryUploadTest.TestConfiguration.class,
+        PlatformHttpComponentAutoConfiguration.class, 
SpringBootPlatformHttpAutoConfiguration.class })
+public class PlatformHttpBinaryUploadTest {
+
+    static final String FILE_NAME = "example.pdf";
+    static Path uploadDir;
+
+    @LocalServerPort
+    private int port;
+
+    @BeforeAll
+    public static void createUploadDir() throws IOException {
+        uploadDir = Files.createTempDirectory(Path.of("target"), 
"platform-http-upload");
+    }
+
+    @AfterAll
+    public static void cleanUploadDir() throws IOException {
+        Files.deleteIfExists(uploadDir.resolve(FILE_NAME));
+        Files.deleteIfExists(uploadDir);
+    }
+
+    @BeforeEach
+    public void setUp() {
+        RestAssured.port = port;
+    }
+
+    @Test
+    void testBinaryPdfUpload() throws IOException {
+        byte[] pdfBytes = 
getClass().getResourceAsStream(FILE_NAME).readAllBytes();
+
+        given()
+                .body(pdfBytes)
+                .contentType("application/pdf")
+                .post("/upload")
+                .then()
+                .statusCode(200);
+
+        Path uploadedFile = uploadDir.resolve(FILE_NAME);
+        assertTrue(Files.exists(uploadedFile), "The uploaded file should 
exist");
+        assertArrayEquals(pdfBytes, Files.readAllBytes(uploadedFile), "The PDF 
should not be corrupted");
+    }
+
+    @Configuration
+    public static class TestConfiguration {
+
+        @Bean
+        public SecurityFilterChain securityFilterChain(HttpSecurity http) 
throws Exception {
+            http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
+                    .csrf(AbstractHttpConfigurer::disable);
+            return http.build();
+        }
+
+        @Bean
+        public RouteBuilder routeBuilder() {
+            return new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    rest().consumes("application/pdf")
+                            .post("/upload")
+                            .to("direct:upload");
+
+                    from("direct:upload")
+                            .convertBodyTo(byte[].class)
+                            .process(exchange -> {
+                                byte[] body = 
exchange.getIn().getBody(byte[].class);
+                                try (FileOutputStream fos = new 
FileOutputStream(
+                                        
uploadDir.resolve(FILE_NAME).toFile())) {
+                                    fos.write(body);
+                                }
+                            })
+                            .setBody(constant("uploaded"));
+                }
+            };
+        }
+    }
+}
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpStreamingTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpStreamingTest.java
index 1d92e987d5a..90499e70fe7 100644
--- 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpStreamingTest.java
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/PlatformHttpStreamingTest.java
@@ -43,6 +43,7 @@ import static io.restassured.RestAssured.given;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.emptyOrNullString;
 import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 @EnableAutoConfiguration
@@ -130,7 +131,7 @@ public class PlatformHttpStreamingTest {
                 .then()
                 .statusCode(200)
                 .header("foo", "bar")
-                .header("BodyClass", containsString("ReaderCache"))
+                .header("BodyClass", containsString("[B"))
                 .body(is("foo=bar"));
     }
 
@@ -155,6 +156,73 @@ public class PlatformHttpStreamingTest {
         assertEquals(fileContent, Files.readString(output, 
StandardCharsets.ISO_8859_1));
     }
 
+    @Test
+    void testNonStreamingWithBinaryData() {
+        byte[] binaryData = new byte[] {0x00, 0x0c, (byte) 0x80, (byte) 0xff, 
(byte) 0xfe, 0x0f, 0x0e};
+        byte[] response = given()
+                .body(binaryData)
+                .contentType(ContentType.BINARY)
+                .post("/binaryData")
+                .then()
+                .statusCode(200)
+                .extract().body().asByteArray();
+        assertArrayEquals(binaryData, response);
+    }
+
+    @Test
+    void testStreamingWithBinaryData() {
+        byte[] binaryData = new byte[] {0x00, 0x0c, (byte) 0x80, (byte) 0xff, 
(byte) 0xfe, 0x0f, 0x0e};
+        byte[] response = given()
+                .body(binaryData)
+                .contentType(ContentType.BINARY)
+                .post("/streamingBinaryData")
+                .then()
+                .statusCode(200)
+                .extract().body().asByteArray();
+        assertArrayEquals(binaryData, response);
+    }
+
+    @Test
+    void testNonStreamingWithKnownContentLength() {
+        // When Content-Length is known, the optimized readNBytes(len) path is 
used
+        // (single byte[] allocation instead of incremental readAllBytes)
+        byte[] largeBody = new byte[8192];
+        for (int i = 0; i < largeBody.length; i++) {
+            largeBody[i] = (byte) (i % 256);
+        }
+        byte[] response = given()
+                .body(largeBody)
+                .contentType(ContentType.BINARY)
+                .post("/binaryData")
+                .then()
+                .statusCode(200)
+                .extract().body().asByteArray();
+        assertArrayEquals(largeBody, response);
+    }
+
+    @Test
+    void testStreamingBodyIsStreamCache() {
+        String requestBody = "streaming body type check";
+        given()
+                .body(requestBody)
+                .post("/streamingBodyType")
+                .then()
+                .statusCode(200)
+                .header("BodyIsStreamCache", "true")
+                .body(is(requestBody));
+    }
+
+    @Test
+    void testNonStreamingBodyIsByteArray() {
+        String requestBody = "non-streaming body type check";
+        given()
+                .body(requestBody)
+                .post("/nonStreamingBodyType")
+                .then()
+                .statusCode(200)
+                .header("BodyIsStreamCache", "false");
+    }
+
     @Configuration
     public static class TestConfiguration {
 
@@ -188,6 +256,18 @@ public class PlatformHttpStreamingTest {
                             .process(exchange ->
                                     
exchange.getMessage().setHeader("BodyClass", 
exchange.getIn().getBody().getClass().getName()))
                             .log("Done processing request");
+
+                    from("platform-http:/binaryData").log("Done processing 
binary request");
+
+                    
from("platform-http:/streamingBinaryData?useStreaming=true").log("Done 
processing streaming binary request");
+                    from("platform-http:/streamingBodyType?useStreaming=true")
+                            .process(exchange -> 
exchange.getMessage().setHeader("BodyIsStreamCache",
+                                    String.valueOf(exchange.getIn().getBody() 
instanceof org.apache.camel.StreamCache)))
+                            .log("Done processing streaming body type check");
+                    from("platform-http:/nonStreamingBodyType")
+                            .process(exchange -> 
exchange.getMessage().setHeader("BodyIsStreamCache",
+                                    String.valueOf(exchange.getIn().getBody() 
instanceof org.apache.camel.StreamCache)))
+                            .log("Done processing non-streaming body type 
check");
                 }
             };
         }
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCertificationTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCertificationTest.java
index 8a9b519dacc..0ce16eb0077 100644
--- 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCertificationTest.java
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCertificationTest.java
@@ -312,7 +312,6 @@ public class SpringBootPlatformHttpCertificationTest 
extends PlatformHttpBase {
     CamelContext camelContext;
 
     @Test
-    @Disabled
     @DisabledIfSystemProperties({
             @DisabledIfSystemProperty(named = "ci.env.name", matches = ".*",
                     disabledReason = "File too large for CI"),
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpHeaderFilterStrategyTest.java
similarity index 58%
copy from 
components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
copy to 
components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpHeaderFilterStrategyTest.java
index 789f85c8352..bfbe92d0d2e 100644
--- 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpHeaderFilterStrategyTest.java
@@ -16,48 +16,54 @@
  */
 package org.apache.camel.component.platform.http.springboot;
 
+import io.restassured.RestAssured;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.http.common.HttpHeaderFilterStrategy;
 import org.apache.camel.spring.boot.CamelAutoConfiguration;
 import org.apache.camel.test.spring.junit6.CamelSpringBootTest;
-import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.web.SecurityFilterChain;
-import 
org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;
-import org.springframework.test.web.servlet.client.RestTestClient;
-import org.springframework.test.web.servlet.client.EntityExchangeResult;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
+import org.springframework.boot.test.web.server.LocalServerPort;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpStatusCode;
+import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.SecurityFilterChain;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.equalTo;
 
 @EnableAutoConfiguration
 @CamelSpringBootTest
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 
classes = { CamelAutoConfiguration.class,
-        SpringBootPlatformHttpRequestTimeoutTest.TestConfiguration.class,
-        PlatformHttpComponentAutoConfiguration.class, 
SpringBootPlatformHttpAutoConfiguration.class, },
-        properties = {"camel.component.platform-http.request-timeout=500"})
-@AutoConfigureMockMvc
-@AutoConfigureRestTestClient
-public class SpringBootPlatformHttpRequestTimeoutTest {
+        SpringBootPlatformHttpHeaderFilterStrategyTest.class,
+        SpringBootPlatformHttpHeaderFilterStrategyTest.TestConfiguration.class,
+        PlatformHttpComponentAutoConfiguration.class, 
SpringBootPlatformHttpAutoConfiguration.class })
+public class SpringBootPlatformHttpHeaderFilterStrategyTest {
+
+    @LocalServerPort
+    private Integer port;
 
-    @Autowired
-    RestTestClient restTestClient;
+    @BeforeEach
+    void setUp() {
+        RestAssured.port = port;
+    }
 
     @Test
-    public void testGetAsync() throws Exception {
-        EntityExchangeResult<String> result = 
restTestClient.get().uri("/slow-get")
-                .exchange()
-                .expectBody(String.class)
-                .returnResult();
-        
Assertions.assertThat(result.getStatus()).isEqualTo(HttpStatusCode.valueOf(503));
+    void customHeaderFilterStrategy() {
+        given()
+                .queryParam("k1", "v1")
+                .queryParam("k2", "v2")
+                .get("/header-filter-strategy")
+                .then()
+                .statusCode(200)
+                .body(equalTo("k1=\nk2=v2"));
     }
 
     @Configuration
     public static class TestConfiguration {
+
         @Bean
         public SecurityFilterChain securityFilterChain(HttpSecurity http) 
throws Exception {
             http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
@@ -65,19 +71,26 @@ public class SpringBootPlatformHttpRequestTimeoutTest {
             return http.build();
         }
 
+        @Bean("TestHeaderFilterStrategy")
+        public HttpHeaderFilterStrategy testHeaderFilterStrategy() {
+            return new HttpHeaderFilterStrategy() {
+                @Override
+                protected void initialize() {
+                    super.initialize();
+                    getInFilter().add("k1");
+                }
+            };
+        }
 
         @Bean
-        public RouteBuilder platformHttpRouteBuilder() {
+        public RouteBuilder routeBuilder() {
             return new RouteBuilder() {
                 @Override
                 public void configure() {
-                    from("platform-http:/slow-get").id("slow-route")
-                            .process(exchange -> Thread.sleep(1000))
-                            .setBody().constant("get");
+                    
from("platform-http:/header-filter-strategy?httpMethodRestrict=GET&headerFilterStrategy=#TestHeaderFilterStrategy")
+                            
.setBody(simple("k1=${header.k1}\nk2=${header.k2}"));
                 }
             };
         }
     }
-
-
 }
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
index 789f85c8352..32166810821 100644
--- 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpRequestTimeoutTest.java
@@ -39,7 +39,7 @@ import org.springframework.http.HttpStatusCode;
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 
classes = { CamelAutoConfiguration.class,
         SpringBootPlatformHttpRequestTimeoutTest.TestConfiguration.class,
         PlatformHttpComponentAutoConfiguration.class, 
SpringBootPlatformHttpAutoConfiguration.class, },
-        properties = {"camel.component.platform-http.request-timeout=500"})
+        properties = {"camel.component.platform-http.request-timeout=100"})
 @AutoConfigureMockMvc
 @AutoConfigureRestTestClient
 public class SpringBootPlatformHttpRequestTimeoutTest {
diff --git 
a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpResponseCodeTest.java
 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpResponseCodeTest.java
new file mode 100644
index 00000000000..21a5ca9db6a
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpResponseCodeTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.platform.http.springboot;
+
+import io.restassured.RestAssured;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit6.CamelSpringBootTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.SecurityFilterChain;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.equalTo;
+
+@EnableAutoConfiguration
+@CamelSpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 
classes = { CamelAutoConfiguration.class,
+        SpringBootPlatformHttpResponseCodeTest.class,
+        SpringBootPlatformHttpResponseCodeTest.TestConfiguration.class,
+        PlatformHttpComponentAutoConfiguration.class, 
SpringBootPlatformHttpAutoConfiguration.class })
+public class SpringBootPlatformHttpResponseCodeTest {
+
+    @LocalServerPort
+    private Integer port;
+
+    @BeforeEach
+    void setUp() {
+        RestAssured.port = port;
+    }
+
+    @Test
+    void responseCodeViaHeader() {
+        given()
+                .get("/response-code-299")
+                .then()
+                .statusCode(299);
+    }
+
+    @Test
+    void code204Null() {
+        given()
+                .get("/null-body")
+                .then()
+                .statusCode(204);
+    }
+
+    @Test
+    void code204EmptyString() {
+        given()
+                .get("/empty-string-body")
+                .then()
+                .statusCode(204);
+    }
+
+    @Test
+    void code204SomeString() {
+        given()
+                .get("/some-string")
+                .then()
+                .statusCode(200)
+                .body(equalTo("No Content"));
+    }
+
+    @Test
+    void code200EmptyString() {
+        given()
+                .get("/empty-string-200")
+                .then()
+                .statusCode(200)
+                .body(equalTo(""));
+    }
+
+    @Configuration
+    public static class TestConfiguration {
+
+        @Bean
+        public SecurityFilterChain securityFilterChain(HttpSecurity http) 
throws Exception {
+            http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
+                .csrf(csrf -> csrf.disable());
+            return http.build();
+        }
+
+        @Bean
+        public RouteBuilder routeBuilder() {
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    
from("platform-http:/response-code-299?httpMethodRestrict=GET")
+                            
.setHeader(Exchange.HTTP_RESPONSE_CODE).constant(299);
+
+                    from("platform-http:/null-body")
+                            .setBody().constant(null);
+
+                    from("platform-http:/empty-string-body")
+                            .setBody().constant("");
+
+                    from("platform-http:/some-string")
+                            .setBody().constant("No Content");
+
+                    from("platform-http:/empty-string-200")
+                            .setHeader(Exchange.HTTP_RESPONSE_CODE, 
constant(200))
+                            .setBody().constant("");
+                }
+            };
+        }
+    }
+}
diff --git 
a/components-starter/camel-platform-http-starter/src/test/resources/org/apache/camel/component/platform/http/springboot/example.pdf
 
b/components-starter/camel-platform-http-starter/src/test/resources/org/apache/camel/component/platform/http/springboot/example.pdf
new file mode 100644
index 00000000000..2ed6fe99a57
Binary files /dev/null and 
b/components-starter/camel-platform-http-starter/src/test/resources/org/apache/camel/component/platform/http/springboot/example.pdf
 differ


Reply via email to