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

apupier pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 8b451798f592a413a3757dc22551234f2f5764e2
Author: smjain <[email protected]>
AuthorDate: Wed Sep 30 16:15:22 2026 +0530

    CAMEL-25217: camel-platform-http-vertx - write a String response in the 
charset of the Content-Type
    
    A String response body was written with RoutingContext.end(String), which
    Vert.x always encodes as UTF-8, while the response Content-Type copied from
    the message can declare another charset (set by the route, or kept from an
    ISO-8859-1 request that the consumer read in its charset). The client then
    decoded UTF-8 bytes in the declared charset.
    
    A String body is now encoded in the charset of the response Content-Type
    when it declares a supported one. Without a charset, or with UTF-8, the
    bytes are the same as before; other body types are unchanged.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../http/vertx/VertxPlatformHttpSupport.java       |  31 ++++++-
 .../VertxPlatformHttpResponseCharsetTest.java      | 102 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |   9 ++
 3 files changed, 141 insertions(+), 1 deletion(-)

diff --git 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
index 80226cc58244..6a7a86a78dc7 100644
--- 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
+++ 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
@@ -18,6 +18,8 @@ package org.apache.camel.component.platform.http.vertx;
 
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.List;
@@ -43,6 +45,7 @@ import org.apache.camel.support.ExceptionHelper;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.ObjectHelper;
 import org.apache.camel.support.http.HttpUtil;
+import org.apache.camel.util.IOHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -186,7 +189,13 @@ public final class VertxPlatformHttpSupport {
                 ctx.end();
                 promise.complete();
             } else if (body instanceof String string) {
-                ctx.end(string);
+                // write the text in the charset declared by the response 
Content-Type (vert.x writes a String as UTF-8)
+                String charset = responseCharset(ctx);
+                if (charset != null) {
+                    ctx.end(Buffer.buffer(string, charset));
+                } else {
+                    ctx.end(string);
+                }
                 promise.complete();
             } else if (body instanceof InputStream inputstream) {
                 writeResponseAs(promise, ctx, inputstream);
@@ -205,6 +214,26 @@ public final class VertxPlatformHttpSupport {
         return promise.future();
     }
 
+    /**
+     * The charset of the response Content-Type header (UTF-8 when it declares 
none), or null when there is no
+     * Content-Type header or its charset is not supported.
+     */
+    private static String responseCharset(RoutingContext ctx) {
+        String contentType = ctx.response().headers().get("Content-Type");
+        if (contentType == null) {
+            return null;
+        }
+        String charset = IOHelper.getCharsetNameFromContentType(contentType);
+        if (charset == null || charset.isEmpty()) {
+            return null;
+        }
+        try {
+            return Charset.isSupported(charset) ? charset : null;
+        } catch (IllegalCharsetNameException e) {
+            return null;
+        }
+    }
+
     private static void writeResponseAsFallback(Promise<Void> promise, 
Exchange camelExchange, Object body, RoutingContext ctx)
             throws NoTypeConversionAvailableException {
         final TypeConverter tc = camelExchange.getContext().getTypeConverter();
diff --git 
a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpResponseCharsetTest.java
 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpResponseCharsetTest.java
new file mode 100644
index 000000000000..91ab21efd78e
--- /dev/null
+++ 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpResponseCharsetTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.vertx;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+/**
+ * A String response body must be written in the charset that the response 
Content-Type declares.
+ */
+public class VertxPlatformHttpResponseCharsetTest {
+
+    private static final String TEXT = "Grüße aus Köln";
+
+    private CamelContext context;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        context = VertxPlatformHttpEngineTest.createCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("platform-http:/latin1")
+                        .setHeader(Exchange.CONTENT_TYPE, 
constant("text/plain; charset=ISO-8859-1"))
+                        .setBody(constant(TEXT));
+
+                from("platform-http:/echo")
+                        .convertBodyTo(String.class);
+
+                from("platform-http:/default")
+                        .setHeader(Exchange.CONTENT_TYPE, 
constant("text/plain"))
+                        .setBody(constant(TEXT));
+            }
+        });
+        VertxPlatformHttpEngineTest.startCamelContext(context);
+    }
+
+    @AfterEach
+    void tearDown() {
+        context.stop();
+    }
+
+    @Test
+    void testStringBodyWrittenInDeclaredCharset() {
+        byte[] body = given()
+                .get("/latin1")
+                .then()
+                .statusCode(200)
+                .header("Content-Type", "text/plain; charset=ISO-8859-1")
+                .extract().asByteArray();
+
+        assertArrayEquals(TEXT.getBytes(StandardCharsets.ISO_8859_1), body);
+    }
+
+    @Test
+    void testEchoInRequestCharset() {
+        byte[] request = TEXT.getBytes(StandardCharsets.ISO_8859_1);
+        byte[] body = given()
+                .contentType("text/plain; charset=ISO-8859-1")
+                .body(request)
+                .post("/echo")
+                .then()
+                .statusCode(200)
+                .extract().asByteArray();
+
+        assertArrayEquals(request, body);
+    }
+
+    @Test
+    void testStringBodyWithoutCharsetIsUtf8() {
+        byte[] body = given()
+                .get("/default")
+                .then()
+                .statusCode(200)
+                .extract().asByteArray();
+
+        assertArrayEquals(TEXT.getBytes(StandardCharsets.UTF_8), body);
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 18fb318551ea..82b1d0069e18 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -707,6 +707,15 @@ Before, the first five fell back to the charset of the 
exchange (UTF-8 by defaul
 unmarshal sets `CamelCharsetName` to it. A message whose MSH-18 names one of 
these charsets but that is actually
 encoded in another one (such as UTF-8) is now decoded in the charset it names.
 
+=== camel-platform-http-vertx - String response in the charset of the 
Content-Type
+
+A `String` response body was always written as UTF-8, even when the response 
`Content-Type` declared another
+charset (for example `text/plain; charset=ISO-8859-1`, set by the route or 
kept from the request). It is now written
+in the charset that the `Content-Type` declares, so the bytes match the 
header. Responses without a charset in the
+`Content-Type`, or with UTF-8, are written as before, and so are bodies that 
are not a `String`. A client that ignored
+the declared charset and read such a response as UTF-8 must now use the 
declared charset, and characters that the
+declared charset cannot represent are written as `?`.
+
 === Components and Language removal
 
 ==== camel-csimple, camel-csimple-joor and csimple-maven-plugin

Reply via email to