jakartaee / rest

Jakarta RESTful Web Services
Other
351 stars 114 forks source link

TCK Challenge: JAXRSClientIT#closeTest fixes #1196

Closed jbescos closed 6 months ago

jbescos commented 7 months ago

This method in RepeatedCasterResource:

  @GET
  @Path("cast")
  @Produces(MediaType.SERVER_SENT_EVENTS)
  public void send(@Context SseEventSink sink, @Context Sse sse) {
    new Thread() {
      public void run() {
        synchronized (isOpen) {
          isOpen = !sink.isClosed();
        }
        while (!sink.isClosed() && cast) {
          sink.send(sse.newEvent(String.valueOf(cnt++)));
          try {
            Thread.sleep(500L);
          } catch (InterruptedException e1) {
            cast = false;
          }
          synchronized (isOpen) {
            isOpen = !sink.isClosed();
            System.out.println("ISOPEN " + isOpen);
          }
        }
        cast = false;
      };
    }.start();
  }

The line sink.send(sse.newEvent(String.valueOf(cnt++))); can throw exception, at least in Jersey: https://github.com/eclipse-ee4j/jersey/blob/d8458a64cb26568ab6bdbf4ac57c2f7b4d774f77/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java#L300

When that happens, the exception is not caught and the variable isOpen is not correctly updated.

I suggest to catch it. I am going to create a PR to show it.

There is also a possible ConcurrentModificationException in JAXRSClientIT#closeTest in line 636:

    source.register(holder::add);
    source.open();
    sleepUntilHolderGetsFilled(holder);
    assertNotNull(holder.get(), "Message was not received");
    for (InboundSseEvent e : holder)
      logMsg("Received message no", e.readData());

holder is iterated and it could be receiving an event during that time.

@jansupol to check whether my request makes sense.

PR: https://github.com/jakartaee/rest/pull/1197

Exception:

java.io.UncheckedIOException: java.net.SocketException: Broken pipe
    at io.helidon.common.buffers.FixedBufferData.writeTo(FixedBufferData.java:74)
    at io.helidon.common.socket.PlainSocket.write(PlainSocket.java:136)
    at io.helidon.common.socket.SocketWriter.writeNow(SocketWriter.java:77)
    at io.helidon.common.socket.SocketWriterDirect.write(SocketWriterDirect.java:43)
    at io.helidon.webserver.http1.Http1ServerResponse$BlockingOutputStream.writeChunked(Http1ServerResponse.java:665)
    at io.helidon.webserver.http1.Http1ServerResponse$BlockingOutputStream.write(Http1ServerResponse.java:591)
    at io.helidon.webserver.http1.Http1ServerResponse$BlockingOutputStream.write(Http1ServerResponse.java:439)
    at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:125)
    at java.base/java.io.BufferedOutputStream.implWrite(BufferedOutputStream.java:222)
    at java.base/java.io.BufferedOutputStream.write(BufferedOutputStream.java:206)
    at java.base/java.io.FilterOutputStream.write(FilterOutputStream.java:110)
    at io.helidon.microprofile.server.JaxRsService$NoFlushOutputStream.write(JaxRsService.java:402)
    at org.glassfish.jersey.message.internal.CommittingOutputStream.write(CommittingOutputStream.java:185)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$UnCloseableOutputStream.write(WriterInterceptorExecutor.java:271)
    at org.glassfish.jersey.media.sse.OutboundEventWriter$1.write(OutboundEventWriter.java:132)
    at java.base/java.io.OutputStream.write(OutputStream.java:167)
    at java.base/sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:309)
    at java.base/sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:405)
    at java.base/sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:410)
    at java.base/sun.nio.cs.StreamEncoder.lockedFlush(StreamEncoder.java:214)
    at java.base/sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:201)
    at java.base/java.io.OutputStreamWriter.flush(OutputStreamWriter.java:262)
    at org.glassfish.jersey.message.internal.ReaderWriter.writeToAsString(ReaderWriter.java:250)
    at org.glassfish.jersey.message.internal.StringMessageProvider.writeTo(StringMessageProvider.java:76)
    at org.glassfish.jersey.message.internal.StringMessageProvider.writeTo(StringMessageProvider.java:36)
    at org.glassfish.jersey.media.sse.OutboundEventWriter.writeTo(OutboundEventWriter.java:118)
    at org.glassfish.jersey.media.sse.OutboundEventWriter.writeTo(OutboundEventWriter.java:44)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:242)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:227)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:139)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1116)
    at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:232)
    at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:199)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:219)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:314)
    at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:199)
    at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:185)
    at org.glassfish.jersey.media.sse.internal.JerseyEventSink.send(JerseyEventSink.java:140)
    at ee.jakarta.tck.ws.rs.jaxrs21.ee.sse.sseeventsource.RepeatedCasterResource$1.run(RepeatedCasterResource.java:57)
Caused by: java.net.SocketException: Broken pipe
    at java.base/sun.nio.ch.SocketDispatcher.write0(Native Method)
    at java.base/sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:62)
    at java.base/sun.nio.ch.NioSocketImpl.tryWrite(NioSocketImpl.java:394)
    at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:410)
    at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440)
    at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:819)
    at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1195)
    at io.helidon.common.buffers.FixedBufferData.writeTo(FixedBufferData.java:71)
    ... 39 more
jbescos commented 6 months ago

Rejecting this. There are some fixes that I will do in Helidon and in Jersey.