diff --git a/core/src/main/java/feign/Response.java b/core/src/main/java/feign/Response.java index 62f1b655e..855680f98 100644 --- a/core/src/main/java/feign/Response.java +++ b/core/src/main/java/feign/Response.java @@ -158,8 +158,8 @@ public int status() { /** * Nullable and not set when using http/2 - * - * See https://github.com/http2/http2-spec/issues/202 + * See <a href="https://github.com/http2/http2-spec/issues/202">...</a> + * See <a href="https://github.com/http2/http2-spec/issues/202">...</a> */ public String reason() { return reason; @@ -195,6 +195,11 @@ public ProtocolVersion protocolVersion() { return protocolVersion; } + /** + * Returns a charset object based on the requests content type. Defaults to UTF-8 + * See <a href="https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.3">rfc7231 - Accept-Charset</a> + * See <a href="https://datatracker.ietf.org/doc/html/rfc7231#section-3.1.1.1">rfc7231 - Media Type</a> + */ public Charset charset() { Collection<String> contentTypeHeaders = headers().get("Content-Type"); @@ -205,7 +210,8 @@ public Charset charset() { if (contentTypeParmeters.length > 1) { String[] charsetParts = contentTypeParmeters[1].split("="); if (charsetParts.length == 2 && "charset".equalsIgnoreCase(charsetParts[0].trim())) { - return Charset.forName(charsetParts[1]); + String charsetString = charsetParts[1].replaceAll("\"", ""); + return Charset.forName(charsetString); } } } @@ -314,7 +320,7 @@ public Reader asReader() { } @Override - public Reader asReader(Charset charset) throws IOException { + public Reader asReader(Charset charset) { checkNotNull(charset, "charset should not be null"); return new InputStreamReader(inputStream, charset); } @@ -360,24 +366,24 @@ public boolean isRepeatable() { } @Override - public InputStream asInputStream() throws IOException { + public InputStream asInputStream() { return new ByteArrayInputStream(data); } @SuppressWarnings("deprecation") @Override - public Reader asReader() throws IOException { + public Reader asReader() { return new InputStreamReader(asInputStream(), UTF_8); } @Override - public Reader asReader(Charset charset) throws IOException { + public Reader asReader(Charset charset) { checkNotNull(charset, "charset should not be null"); return new InputStreamReader(asInputStream(), charset); } @Override - public void close() throws IOException {} + public void close() {} } diff --git a/core/src/test/java/feign/ResponseTest.java b/core/src/test/java/feign/ResponseTest.java index eea7e95cd..7ba39c175 100644 --- a/core/src/test/java/feign/ResponseTest.java +++ b/core/src/test/java/feign/ResponseTest.java @@ -14,6 +14,8 @@ package feign; import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -59,6 +61,20 @@ void canAccessHeadersCaseInsensitively() { }); } + @Test + void charsetSupportsMediaTypesWithQuotedCharset() { + Map<String, Collection<String>> headersMap = new LinkedHashMap<>(); + List<String> valueList = Collections.singletonList("application/json; charset=\"utf-8\""); + headersMap.put("Content-Type", valueList); + Response response = Response.builder() + .status(200) + .headers(headersMap) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .body(new byte[0]) + .build(); + assertThat(response.charset()).isEqualTo(Util.UTF_8); + } + @Test void headerValuesWithSameNameOnlyVaryingInCaseAreMerged() { Map<String, Collection<String>> headersMap = new LinkedHashMap<>();