mirror of
https://github.com/jetty/jetty.project.git
synced 2025-02-28 19:09:10 +00:00
Improved failsafe close handling for half closed endpoints
This commit is contained in:
parent
aa394123cb
commit
61b2e7f75e
@ -44,6 +44,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
|
||||
return AbstractEndPoint.this.needsFill();
|
||||
}
|
||||
};
|
||||
|
||||
private final WriteFlusher _writeFlusher = new WriteFlusher(this)
|
||||
{
|
||||
@Override
|
||||
@ -142,9 +143,22 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
|
||||
@Override
|
||||
protected void onIdleExpired(TimeoutException timeout)
|
||||
{
|
||||
// Note: Rely on fillInterest to notify onReadTimeout to close connection.
|
||||
_fillInterest.onFail(timeout);
|
||||
_writeFlusher.onFail(timeout);
|
||||
boolean output_shutdown=isOutputShutdown();
|
||||
boolean input_shutdown=isInputShutdown();
|
||||
boolean fillFailed = _fillInterest.onFail(timeout);
|
||||
boolean writeFailed = _writeFlusher.onFail(timeout);
|
||||
|
||||
// If the endpoint is half closed and there was no onFail handling, the close here
|
||||
// This handles the situation where the connection has completed its close handling
|
||||
// and the endpoint is half closed, but the other party does not complete the close.
|
||||
// This perhaps should not check for half closed, however the servlet spec case allows
|
||||
// for a dispatched servlet or suspended request to extend beyond the connections idle
|
||||
// time. So if this test would always close an idle endpoint that is not handled, then
|
||||
// we would need a mode to ignore timeouts for some HTTP states
|
||||
if (isOpen() && (output_shutdown || input_shutdown) && !(fillFailed || writeFailed))
|
||||
close();
|
||||
else
|
||||
LOG.debug("Ignored idle endpoint {}",this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,12 +93,17 @@ public abstract class FillInterest
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Call to signal a failure to a registered interest
|
||||
* @return true if the cause was passed to a {@link Callback} instance
|
||||
*/
|
||||
public void onFail(Throwable cause)
|
||||
public boolean onFail(Throwable cause)
|
||||
{
|
||||
Callback callback=_interested.get();
|
||||
if (callback!=null && _interested.compareAndSet(callback,null))
|
||||
{
|
||||
callback.failed(cause);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -253,10 +253,14 @@ abstract public class WriteFlusher
|
||||
return _buffers;
|
||||
}
|
||||
|
||||
protected void fail(Throwable cause)
|
||||
protected boolean fail(Throwable cause)
|
||||
{
|
||||
if (_callback!=null)
|
||||
{
|
||||
_callback.failed(cause);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void complete()
|
||||
@ -430,7 +434,12 @@ abstract public class WriteFlusher
|
||||
}
|
||||
}
|
||||
|
||||
public void onFail(Throwable cause)
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Notify the flusher of a failure
|
||||
* @param cause The cause of the failure
|
||||
* @return true if the flusher passed the failure to a {@link Callback} instance
|
||||
*/
|
||||
public boolean onFail(Throwable cause)
|
||||
{
|
||||
// Keep trying to handle the failure until we get to IDLE or FAILED state
|
||||
while(true)
|
||||
@ -442,7 +451,7 @@ abstract public class WriteFlusher
|
||||
case FAILED:
|
||||
if (DEBUG)
|
||||
LOG.debug("ignored: {} {}", this, cause);
|
||||
return;
|
||||
return false;
|
||||
|
||||
case PENDING:
|
||||
if (DEBUG)
|
||||
@ -450,10 +459,7 @@ abstract public class WriteFlusher
|
||||
|
||||
PendingState pending = (PendingState)current;
|
||||
if (updateState(pending,__IDLE))
|
||||
{
|
||||
pending.fail(cause);
|
||||
return;
|
||||
}
|
||||
return pending.fail(cause);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -461,7 +467,7 @@ abstract public class WriteFlusher
|
||||
LOG.debug("failed: {} {}", this, cause);
|
||||
|
||||
if (updateState(current,new FailedState(cause)))
|
||||
return;
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@ -37,8 +35,6 @@ import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
import org.eclipse.jetty.util.thread.TimerScheduler;
|
||||
import org.junit.After;
|
||||
@ -132,6 +128,7 @@ public class ByteArrayEndPointTest
|
||||
|
||||
assertEquals(true,endp.flush(BufferUtil.EMPTY_BUFFER,BufferUtil.toBuffer(" and"),BufferUtil.toBuffer(" more")));
|
||||
assertEquals("some output some more and more",endp.getOutputString());
|
||||
endp.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -150,6 +147,7 @@ public class ByteArrayEndPointTest
|
||||
|
||||
assertEquals(true,endp.flush(data));
|
||||
assertEquals("data.",BufferUtil.toString(endp.takeOutput()));
|
||||
endp.close();
|
||||
}
|
||||
|
||||
|
||||
@ -237,6 +235,7 @@ public class ByteArrayEndPointTest
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals(null, fcb.get());
|
||||
assertEquals(" more.", endp.getOutputString());
|
||||
endp.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user