Skip to content

Commit

Permalink
Harmonize the usage of charset in the Content-Type headers for RESTEa…
Browse files Browse the repository at this point in the history
…sy Reactive

The idea is that we know only append it for specific response media types.
Before this change, the charset was added depending on how the return type
of the Resource method

Relates to: #25295
  • Loading branch information
geoand committed May 16, 2022
1 parent 3f94ebd commit 49ec0e2
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void testApplicationJsonMediaType() {
Response response = base.request().get();
Assertions.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
String body = response.readEntity(String.class);
Assertions.assertEquals(response.getHeaderString("Content-Type"), "application/json");
Assertions.assertEquals(response.getHeaderString("Content-Type"), "application/json;charset=UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
package org.jboss.resteasy.reactive.server.core;

import java.nio.charset.StandardCharsets;
import java.util.Objects;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.reactive.server.spi.ContentType;

/**
* Wrapper around MediaType that saves the toString value, to avoid
* the expensive header delegate processing.
* It also harmonizes the use of charset
*/
public class EncodedMediaType implements ContentType {
final MediaType mediaType;
final String charset;
String encoded;
String charset;

public EncodedMediaType(MediaType mediaType) {
this.mediaType = mediaType;
this.charset = mediaType.getParameters().get("charset");
MediaType effectiveMediaType = mediaType;
String effectiveCharset;
String originalCharset = mediaType.getParameters().get("charset");
if (isStringMediaType(mediaType)) {
effectiveCharset = originalCharset;
if (effectiveCharset == null) {
effectiveCharset = StandardCharsets.UTF_8.name();
}
} else {
// it doesn't make sense to add charset to non string types
effectiveCharset = null;
}
this.charset = effectiveCharset;
if (!Objects.equals(originalCharset, effectiveCharset)) {
effectiveMediaType = mediaType.withCharset(effectiveCharset);
}
this.mediaType = effectiveMediaType;
}

// TODO: does this need to be more complex?
private boolean isStringMediaType(MediaType mediaType) {
String type = mediaType.getType();
String subtype = mediaType.getSubtype();
return (type.equals("application") && (subtype.contains("json") || subtype.contains("xml") || subtype.contains("yaml")))
|| type.equals("text");
}

@Override
Expand All @@ -37,9 +63,6 @@ public String getEncoded() {

@Override
public String getCharset() {
if (charset == null) {
return charset = mediaType.getParameters().get("charset");
}
return charset;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ public void write(ResteasyReactiveRequestContext context, Object entity) throws
serverSerializersMediaType = selectedMediaType;
context.setResponseContentType(selectedMediaType);
// this will be used as the fallback if Response does NOT contain a type
context.serverResponse().addResponseHeader(HttpHeaders.CONTENT_TYPE, selectedMediaType.toString());
context.serverResponse().addResponseHeader(HttpHeaders.CONTENT_TYPE,
context.getResponseContentType().toString());
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.jboss.resteasy.reactive.server.vertx.test.mediatype;

import static io.restassured.RestAssured.when;
import static org.junit.jupiter.api.Assertions.*;

import java.nio.charset.StandardCharsets;
import java.util.function.Supplier;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

public class CharsetTest {

@RegisterExtension
static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest()
.setArchiveProducer(new Supplier<>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(TestResource.class);
}
});

@Test
public void testText() {
String contentType = when().get("/test/text")
.then()
.statusCode(200)
.extract().header("Content-Type");
assertEquals("text/plain;charset=UTF-8", contentType);
}

@Test
public void testResponseText() {
String contentType = when().get("/test/response/text")
.then()
.statusCode(200)
.extract().header("Content-Type");
assertEquals("text/plain;charset=UTF-8", contentType);
}

@Test
public void testJson() {
String contentType = when().get("/test/json")
.then()
.statusCode(200)
.extract().header("Content-Type");
assertEquals("application/json;charset=UTF-8", contentType);
}

@Test
public void testImage() {
String contentType = when().get("/test/image")
.then()
.statusCode(200)
.extract().header("Content-Type");
assertEquals("image/png", contentType);
}

@Path("test")
public static class TestResource {

@Path("text")
@Produces("text/plain")
@GET
public String textPlain() {
return "text";
}

@Path("response/text")
@Produces("text/plain")
@GET
public Response responseTextPlain() {
return Response.ok("text").build();
}

@Path("json")
@Produces("application/json")
@GET
public String json() {
return "{\"foo\": \"bar\"}";
}

@Path("response/json")
@Produces("application/json")
@GET
public Response responseJson() {
return Response.ok("{\"foo\": \"bar\"}").build();
}

@Path("image")
@Produces("image/png")
@GET
public Response imagePng() {
return Response.ok("fake image".getBytes(StandardCharsets.UTF_8)).build();
}

@Path("response/image")
@Produces("image/png")
@GET
public byte[] responseImagePng() {
return "fake image".getBytes(StandardCharsets.UTF_8);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void testApplicationJsonMediaType() {
Response response = base.request().get();
Assertions.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
String body = response.readEntity(String.class);
Assertions.assertEquals(response.getHeaderString("Content-Type"), "application/json");
Assertions.assertEquals(response.getHeaderString("Content-Type"), "application/json;charset=UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down

0 comments on commit 49ec0e2

Please sign in to comment.