From 9e4f0cf0ab994c3ae7d7445a0fa9e9b83c7d4ce0 Mon Sep 17 00:00:00 2001 From: Jakub Venglar Date: Wed, 11 Sep 2024 12:35:17 +0200 Subject: [PATCH] Fixed extracting charset from response. While building FeignException, ignore quotes in regexp, ignore case and catch IllegalCharsetNameException to be sure it does not raise in other cases. These content types are all valid and results in utf-8: text/html;charset=utf-8 text/html;charset=UTF-8 Text/HTML;Charset="utf-8" text/html; charset="utf-8" Fixes #2540 --- core/src/main/java/feign/FeignException.java | 12 ++++++-- .../test/java/feign/FeignExceptionTest.java | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/feign/FeignException.java b/core/src/main/java/feign/FeignException.java index 1582a3f36..327095918 100644 --- a/core/src/main/java/feign/FeignException.java +++ b/core/src/main/java/feign/FeignException.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 The Feign Authors + * Copyright 2012-2024 The Feign Authors * * Licensed 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 @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -29,6 +30,7 @@ import java.util.regex.Pattern; import static feign.Util.*; import static java.lang.String.format; +import static java.util.regex.Pattern.CASE_INSENSITIVE; /** * Origin exception type for all Http Apis. @@ -519,14 +521,18 @@ private static Charset getResponseCharset(Map> header return null; } - Pattern pattern = Pattern.compile(".*charset=([^\\s|^;]+).*"); + Pattern pattern = Pattern.compile(".*charset=\"?([^\\s|^;|^\"]+).*", CASE_INSENSITIVE); Matcher matcher = pattern.matcher(strings.iterator().next()); if (!matcher.lookingAt()) { return null; } String group = matcher.group(1); - if (!Charset.isSupported(group)) { + try { + if (!Charset.isSupported(group)) { + return null; + } + } catch (IllegalCharsetNameException ex) { return null; } return Charset.forName(group); diff --git a/core/src/test/java/feign/FeignExceptionTest.java b/core/src/test/java/feign/FeignExceptionTest.java index ea49a77d1..1aef7d6d1 100644 --- a/core/src/test/java/feign/FeignExceptionTest.java +++ b/core/src/test/java/feign/FeignExceptionTest.java @@ -24,6 +24,8 @@ import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class FeignExceptionTest { @@ -76,6 +78,32 @@ void createFeignExceptionWithCorrectCharsetResponse() { .isEqualTo("[400] during [GET] to [/home] [methodKey]: [response]"); } + @ParameterizedTest + @ValueSource(strings = { + "application/json;charset=\"UTF-16BE\"", + "application/json; charset=UTF-16BE", + "application/json; charset=\"UTF-16BE\"", + "application/json;charset=UTF-16BE" + }) + void createFeignExceptionWithCorrectCharsetResponseButDifferentContentTypeFormats(String contentType) { + Map> map = new HashMap<>(); + map.put("connection", new ArrayList<>(Collections.singletonList("keep-alive"))); + map.put("content-length", new ArrayList<>(Collections.singletonList("100"))); + map.put("content-type", + new ArrayList<>(Collections.singletonList(contentType))); + + Request request = Request.create(Request.HttpMethod.GET, "/home", Collections.emptyMap(), + "data".getBytes(StandardCharsets.UTF_16BE), StandardCharsets.UTF_16BE, null); + + Response response = + Response.builder().status(400).body("response".getBytes(StandardCharsets.UTF_16BE)) + .headers(map).request(request).build(); + + FeignException exception = FeignException.errorStatus("methodKey", response); + assertThat(exception.getMessage()) + .isEqualTo("[400] during [GET] to [/home] [methodKey]: [response]"); + } + @Test void createFeignExceptionWithErrorCharsetResponse() { Map> map = new HashMap<>();