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.git


The following commit(s) were added to refs/heads/main by this push:
     new 892be63447f7 chore: fix default charset in Undertow consumer when 
Content-Type has no charset
892be63447f7 is described below

commit 892be63447f76093a3658b480aaa4fd971527c77
Author: Croway <[email protected]>
AuthorDate: Tue Apr 7 11:19:16 2026 +0200

    chore: fix default charset in Undertow consumer when Content-Type has no 
charset
    
    Undertow's getRequestCharset() defaults to ISO-8859-1 when no charset
    is specified in the Content-Type header. This causes UTF-8 encoded
    request bodies to be decoded incorrectly. Only set the exchange charset
    property when explicitly specified, letting Camel default to UTF-8.
---
 .../camel/component/undertow/UndertowConsumer.java | 15 +++-
 .../RestUndertowHttpPostJsonPojoCharsetTest.java   | 87 ++++++++++++++++++++++
 2 files changed, 100 insertions(+), 2 deletions(-)

diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
index 8140a0099537..17f48556925b 100644
--- 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
@@ -364,8 +364,19 @@ public class UndertowConsumer extends DefaultConsumer 
implements HttpHandler, Su
             getEndpoint().getSecurityProvider().addHeader((key, value) -> 
in.setHeader(key, value), httpExchange);
         }
 
-        exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, 
httpExchange.getRequestCharset());
-        in.setHeader(UndertowConstants.HTTP_CHARACTER_ENCODING, 
httpExchange.getRequestCharset());
+        // Only set charset if explicitly specified in the Content-Type header.
+        // Undertow's getRequestCharset() defaults to ISO-8859-1 when no 
charset is present,
+        // but Camel (and JSON/modern APIs) expect UTF-8 as the default.
+        // By not setting the property when charset is absent, Camel's type 
conversion
+        // system will use its own default (UTF-8), matching the behavior of 
DefaultHttpBinding.
+        String contentType = 
httpExchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE);
+        String charset = contentType != null
+                ? Headers.extractQuotedValueFromHeader(contentType, "charset")
+                : null;
+        if (charset != null) {
+            exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, charset);
+            in.setHeader(UndertowConstants.HTTP_CHARACTER_ENCODING, charset);
+        }
 
         exchange.setIn(in);
         return exchange;
diff --git 
a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPostJsonPojoCharsetTest.java
 
b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPostJsonPojoCharsetTest.java
new file mode 100644
index 000000000000..9152cd56172c
--- /dev/null
+++ 
b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPostJsonPojoCharsetTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.undertow.rest;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.undertow.BaseUndertowTest;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Test that UTF-8 characters in JSON body are handled correctly even when the 
request Content-Type does not explicitly
+ * specify a charset (e.g. "application/json" without "; charset=UTF-8").
+ */
+public class RestUndertowHttpPostJsonPojoCharsetTest extends BaseUndertowTest {
+
+    @Test
+    public void testPostPojoWithUtf8BodyNoExplicitCharset() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:input");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(UserPojo.class);
+
+        // JSON body with non-ASCII UTF-8 characters
+        String body = "{\"id\": 123, \"name\": \"Dönäld Dück\"}";
+
+        String url = "http://localhost:"; + getPort() + "/users/new";
+        HttpPost httpPost = new HttpPost(url);
+        // Send UTF-8 encoded bytes with Content-Type: application/json (NO 
charset parameter).
+        // Using ContentType.create() instead of ContentType.APPLICATION_JSON 
because the latter
+        // includes "charset=UTF-8" which would mask the bug we are testing.
+        byte[] utf8Bytes = body.getBytes(StandardCharsets.UTF_8);
+        httpPost.setEntity(new ByteArrayEntity(utf8Bytes, 
ContentType.create("application/json")));
+
+        try (CloseableHttpClient httpClient = HttpClients.createDefault();
+             CloseableHttpResponse response = httpClient.execute(httpPost)) {
+            assertEquals(200, response.getCode());
+        }
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        UserPojo user = 
mock.getReceivedExchanges().get(0).getIn().getBody(UserPojo.class);
+        assertNotNull(user);
+        assertEquals(123, user.getId());
+        assertEquals("Dönäld Dück", user.getName());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
restConfiguration().component("undertow").host("localhost").port(getPort())
+                        .bindingMode(RestBindingMode.auto);
+
+                rest("/users/")
+                        .post("new").type(UserPojo.class)
+                        .to("mock:input");
+            }
+        };
+    }
+
+}

Reply via email to