From 27f6aa624af9b927d425ca6ebb4fe1bf71dd41d4 Mon Sep 17 00:00:00 2001 From: kubav182 Date: Mon, 16 Sep 2024 15:42:48 +0200 Subject: [PATCH] Fixed extracting charset from response. (#2545) 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 Co-authored-by: Jakub Venglar --- 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<>();