Skip to content

Commit

Permalink
Merge pull request quarkusio#26376 from geoand/quarkusio#26270
Browse files Browse the repository at this point in the history
Clear out OutputStream when a MessageBodyWriter throws an exception
  • Loading branch information
geoand authored Jun 27, 2022
2 parents 0e4c425 + effe3f9 commit 1594058
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ public static boolean invokeWriter(ResteasyReactiveRequestContext context, Objec
//the error handling will want to write out its own response
//and the pre commit listener will interfere with that
context.serverResponse().setPreCommitListener(null);
// also clear the stream in order to try to avoid writing out any data that
// might have been put on the stream before the exception occurred
context.setOutputStream(null);
if (e instanceof RuntimeException) {
throw new PreserveTargetException(e);
} else if (e instanceof IOException) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.jboss.resteasy.reactive.server.vertx.test.response;

import static io.restassured.RestAssured.when;
import static org.hamcrest.CoreMatchers.is;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo;
import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter;
import org.jboss.resteasy.reactive.server.spi.ServerRequestContext;
import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

public class ExceptionInWriterTest {

@RegisterExtension
static ResteasyReactiveUnitTest runner = new ResteasyReactiveUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(Greeting.class, GreetingResource.class,
GreetingWriter.class, GreetingException.class, GreetingExceptionMapper.class));

@Test
void nullHeaderTest() {
when()
.get("/greeting")
.then().statusCode(200)
.body(is("fallback"));
}

@Path("/greeting")
public static class GreetingResource {

@GET
public Greeting ok() {
return new Greeting("hello");
}
}

public static class Greeting {

private final String message;

public Greeting(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}

@Provider
@Produces(MediaType.TEXT_PLAIN)
public static class GreetingWriter implements ServerMessageBodyWriter<Greeting> {

@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}

@Override
public boolean isWriteable(Class<?> type, Type genericType, ResteasyReactiveResourceInfo target,
MediaType mediaType) {
return true;
}

@Override
public void writeTo(Greeting greeting, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {

doWrite(greeting, entityStream);
}

@Override
public void writeResponse(Greeting greeting, Type genericType, ServerRequestContext context)
throws WebApplicationException, IOException {
doWrite(greeting, context.getOrCreateOutputStream());
}

private void doWrite(Greeting greeting, OutputStream entityStream) throws IOException {
if ("hello".equals(greeting.getMessage())) { // when the greeting comes from the resource method
entityStream.write("should not exist in final output".getBytes(StandardCharsets.UTF_8));
GreetingException ioe = new GreetingException("dummy exception");
ioe.setStackTrace(new StackTraceElement[0]);
throw ioe;
} else {
entityStream.write(greeting.message.getBytes(StandardCharsets.UTF_8));
}
}
}

public static class GreetingException extends IOException {

public GreetingException(String message) {
super(message);
}
}

@Provider
public static class GreetingExceptionMapper implements ExceptionMapper<GreetingException> {

@Override
public Response toResponse(GreetingException exception) {
return Response.status(200).entity(new Greeting("fallback")).build();
}
}
}

0 comments on commit 1594058

Please sign in to comment.