Issue #3746 - fix WriteFlusher ClassCastException if Callback throws (#3778)

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan 2019-06-13 15:51:22 +10:00 committed by GitHub
parent 370a85b921
commit c94753ece3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 11 deletions

View File

@ -307,9 +307,36 @@ abstract public class WriteFlusher
private void fail(Callback callback, Throwable... suppressed)
{
FailedState failed = (FailedState)_state.get();
Throwable cause;
loop:
while (true)
{
State state = _state.get();
switch (state.getType())
{
case FAILED:
{
FailedState failed = (FailedState)state;
cause = failed.getCause();
break loop;
}
case IDLE:
for (Throwable t : suppressed)
LOG.warn(t);
return;
default:
Throwable t = new IllegalStateException();
if (!_state.compareAndSet(state, new FailedState(t)))
continue;
cause = t;
break loop;
}
}
Throwable cause = failed.getCause();
for (Throwable t : suppressed)
{
if (t != cause)

View File

@ -18,14 +18,6 @@
package org.eclipse.jetty.io;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
@ -43,10 +35,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class WriteFlusherTest
{
@Test
@ -159,6 +159,43 @@ public class WriteFlusherTest
assertTrue(flusher.isIdle());
}
@Test
public void testCallbackThrows() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint(new byte[0], 100);
AtomicBoolean incompleteFlush = new AtomicBoolean(false);
WriteFlusher flusher = new WriteFlusher(endPoint)
{
@Override
protected void onIncompleteFlush()
{
incompleteFlush.set(true);
}
};
FutureCallback callback = new FutureCallback()
{
@Override
public void succeeded()
{
super.succeeded();
throw new IllegalStateException();
}
};
try (StacklessLogging stacklessLogging = new StacklessLogging(WriteFlusher.class))
{
flusher.write(callback, BufferUtil.toBuffer("How now brown cow!"));
callback.get(100, TimeUnit.MILLISECONDS);
}
assertEquals("How now brown cow!", endPoint.takeOutputString());
assertTrue(callback.isDone());
assertFalse(incompleteFlush.get());
assertTrue(flusher.isIdle());
}
@Test
public void testCloseWhileBlocking() throws Exception
{