snowdrop-zen / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
1 stars 0 forks source link

RESTEasy Reactive: headers already sent when writer throws exception #229

Closed snowdrop-bot closed 3 years ago

snowdrop-bot commented 3 years ago

When an exception happens in the writers, we've already set the response HTTP status code and headers, but we switch to the exception handler which tries to send the exception and doesn't notice the reponse is already committed, so we get an exception on the server side and the client gets nothing:

class FroMage {
    // private is what's causing the exception
    private String name;
    public FroMage(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Cheese: " + name;
    }
}

@Path("negotiated")
public class Endpoint {

    @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
    @GET
    public FroMage get(){
        return new FroMage("Morbier");
    }
}
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>
$ curl --header 'Accept: text/plain,application/json' --include http://localhost:8080/negotiated
2020-12-10 09:24:20,580 ERROR [org.jbo.res.rea.com.cor.AbstractResteasyReactiveContext] (vert.x-eventloop-thread-8) Request failed: java.lang.IllegalStateException: Response head already sent
    at io.vertx.core.http.impl.HttpServerResponseImpl.checkHeadWritten(HttpServerResponseImpl.java:638)
    at io.vertx.core.http.impl.HttpServerResponseImpl.setStatusCode(HttpServerResponseImpl.java:132)
    at org.jboss.resteasy.reactive.server.vertx.VertxResteasyReactiveRequestContext.setStatusCode(VertxResteasyReactiveRequestContext.java:220)
    at org.jboss.resteasy.reactive.server.core.ServerSerialisers.encodeResponseHeaders(ServerSerialisers.java:445)
    at org.jboss.resteasy.reactive.server.handlers.ResponseWriterHandler.handle(ResponseWriterHandler.java:35)
    at org.jboss.resteasy.reactive.server.handlers.ResponseWriterHandler.handle(ResponseWriterHandler.java:15)
    at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:108)
    at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:47)
    at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$5.handle(ResteasyReactiveRecorder.java:121)
    at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$5.handle(ResteasyReactiveRecorder.java:118)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1036)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:131)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$4.handle(VertxHttpRecorder.java:326)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$4.handle(VertxHttpRecorder.java:304)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1036)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:131)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
    at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:86)
    at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:75)
    at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:327)
    at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
    at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:834)

Note that the jackson exception that complains about FroMage not being registered, or not in fact having fields, is lost and not visible, but it's:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.acme.rest.FroMage and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
    at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4409)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3621)
    at io.quarkus.resteasy.reactive.jackson.runtime.serialisers.JacksonMessageBodyWriter.writeResponse(JacksonMessageBodyWriter.java:67)
    at org.jboss.resteasy.reactive.server.core.ServerSerialisers.invokeWriter(ServerSerialisers.java:175)
    at org.jboss.resteasy.reactive.server.core.ServerSerialisers.invokeWriter(ServerSerialisers.java:157)
    at org.jboss.resteasy.reactive.server.core.serialization.FixedEntityWriterArray.write(FixedEntityWriterArray.java:28)
    at org.jboss.resteasy.reactive.server.handlers.ResponseWriterHandler.handle(ResponseWriterHandler.java:32)
    at org.jboss.resteasy.reactive.server.handlers.ResponseWriterHandler.handle(ResponseWriterHandler.java:15)
    at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:108)
    at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:47)
    at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$5.handle(ResteasyReactiveRecorder.java:121)
    at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$5.handle(ResteasyReactiveRecorder.java:118)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1036)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:131)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$4.handle(VertxHttpRecorder.java:326)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$4.handle(VertxHttpRecorder.java:304)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1036)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:131)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
    at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:86)
    at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:75)
    at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:327)
    at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
...

https://github.com/quarkusio/quarkus/issues/13797


$upstream:13797$