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
