Skip to content

Commit

Permalink
Attempt to fix infinite await in Jersey output writer. (helidon-io#9460)
Browse files Browse the repository at this point in the history
The count down latch is now counted down in close method of the output stream, which should cover all the possible cases (unless close is not called, which would cause other major issues as well, so the case is not handled).

Signed-off-by: Tomas Langer <[email protected]>
  • Loading branch information
tomas-langer authored and barchetta committed Nov 4, 2024
1 parent 8e665f8 commit e772f51
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ public OutputStream writeResponseStatusAndHeaders(long contentLengthParam,
if (contentLength > 0) {
res.header(HeaderValues.create(HeaderNames.CONTENT_LENGTH, String.valueOf(contentLength)));
}
this.outputStream = res.outputStream();
// in case there is an exception during close operation, we would lose the information and wait indefinitely
this.outputStream = new ReleaseLatchStream(cdl, res.outputStream());
return outputStream;
}

Expand Down Expand Up @@ -364,6 +365,10 @@ public void commit() {
} catch (IOException e) {
cdl.countDown();
throw new UncheckedIOException(e);
} catch (Throwable e) {
// always release on commit, regardless of what happened
cdl.countDown();
throw e;
}
}

Expand All @@ -382,7 +387,7 @@ public boolean enableResponseBuffering() {
return true; // enable buffering in Jersey
}

public void await() {
void await() {
try {
cdl.await();
} catch (InterruptedException e) {
Expand All @@ -391,6 +396,45 @@ public void await() {
}
}

private static class ReleaseLatchStream extends OutputStream {
private final CountDownLatch cdl;
private final OutputStream delegate;

private ReleaseLatchStream(CountDownLatch cdl, OutputStream delegate) {
this.cdl = cdl;
this.delegate = delegate;
}

@Override
public void write(int b) throws IOException {
delegate.write(b);
}

@Override
public void write(byte[] b) throws IOException {
delegate.write(b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
delegate.write(b, off, len);
}

@Override
public void flush() throws IOException {
delegate.flush();
}

@Override
public void close() throws IOException {
try {
delegate.close();
} finally {
cdl.countDown();
}
}
}

private static class BaseUriRequestUri {
private final URI baseUri;
private final URI requestUri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -843,7 +844,7 @@ public void close() {
closingDelegate.closing(); // inform of imminent call to close for last flush
try {
delegate.close();
} catch (IOException e) {
} catch (IOException | UncheckedIOException e) {
throw new ServerConnectionException("Failed to close server output stream", e);
}
}
Expand All @@ -856,7 +857,7 @@ void commit() {
try {
flush();
closingDelegate.commit();
} catch (IOException e) {
} catch (IOException | UncheckedIOException e) {
throw new ServerConnectionException("Failed to flush server output stream", e);
}
}
Expand Down

0 comments on commit e772f51

Please sign in to comment.