Merge branch 'jetty-9.3.x' into jetty-9.4.x

This commit is contained in:
Jesse McConnell 2016-05-31 20:38:31 -05:00
commit b4c958e68c
7 changed files with 151 additions and 132 deletions

View File

@ -27,7 +27,6 @@ Web Applications can be bundled into a single Web Archive (WAR file) or as a dir
`/WEB-INF/`::
Special Servlet API defined directory used to store anything related to the Web Application that are not part of the public access of the Web Application.
If there is content that is accessed by a Web Application internally, but that should also never be accessed directly by a web browser, this is the directory it would placed in.
`/WEB-INF/web.xml`::

View File

@ -52,15 +52,15 @@ META-INF/web-fragment.xml
===== Anatomy of a Configuration Class
A Configuration class is called 5 times in different phases of the WebAppContext's lifecycle:
A Configuration class is called 5 times in different phases of the `WebAppContext's` lifecycle:
preConfigure::
As the WebAppContext is starting up this phase is executed.
The Configuration should discover any of the resources it will need during the subsequent phases.
As the `WebAppContext` is starting up this phase is executed.
The `Configuration` should discover any of the resources it will need during the subsequent phases.
configure::
This phase is where the work of the class is done, usually using the resources discovered during the preConfigure phase.
This phase is where the work of the class is done, usually using the resources discovered during the `preConfigure` phase.
postConfigure::
This phase allows the Configuration to clear down any resources that may have been created during the previous 2 phases that are not needed for the lifetime of the `WebAppContext`.
This phase allows the `Configuration` to clear down any resources that may have been created during the previous 2 phases that are not needed for the lifetime of the `WebAppContext`.
deconfigure::
This phase occurs whenever a `WebAppContext` is being stopped and allows the Configuration to undo any resources/metadata that it created.
A `WebAppContext` should be able to be cleanly start/stopped multiple times without resources being held.
@ -68,8 +68,8 @@ destroy::
This phase is called when a `WebAppContext` is actually removed from service.
For example, the war file associated with it is deleted from the $JETTY_HOME/webapps directory.
Each phase is called on each Configuration class in the order in which the `Configuration` class is listed.
Using the default Configuration classes as an example, preConfigure() will be called on `WebInfConfiguration`, `WebXmlConfiguration`, `MetaInfConfiguration`, `FragmentConfiguration` and then `JettyWebXmlConfiguration`.
Each phase is called on each `Configuration` class in the order in which the `Configuration` class is listed.
Using the default `Configuration` classes as an example, `preConfigure()` will be called on `WebInfConfiguration`, `WebXmlConfiguration`, `MetaInfConfiguration`, `FragmentConfiguration` and then `JettyWebXmlConfiguration`.
The cycle begins again for the `configure()` phase and again for the `postConfigure()` phases.
The cycle is repeated _in reverse order_ for the `deconfigure()` and eventually the `destroy()` phases.
@ -96,10 +96,10 @@ To achieve that, we use 2 extra Configurations:
[cols=",",]
|=======================================================================
|link:{JDURL}/org/eclipse/jetty/plus/webapp/EnvConfiguration.html[org.eclipse.jetty.plus.webapp.EnvConfiguration]
|Creates java:comp/env for the webapp, applies a WEB-INF/jetty-env.xml file
|Creates `java:comp/env` for the webapp, applies a `WEB-INF/jetty-env.xml` file
|link:{JDURL}/org/eclipse/jetty/plus/webapp/PlusConfiguration.html[org.eclipse.jetty.plus.webapp.PlusConfiguration]
|Processes JNDI related aspects of WEB-INF/web.xml and hooks up naming entries
|Processes JNDI related aspects of `WEB-INF/web.xml` and hooks up naming entries
|=======================================================================
These configurations must be added in _exactly_ the order shown above and should be inserted _immediately before_ the link:{JDURL}/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.html[org.eclipse.jetty.webapp.JettyWebXmlConfiguration] class in the list of configurations.
@ -117,7 +117,7 @@ We need just one extra Configuration class to help provide servlet annotation sc
@WebListener etc
|=======================================================================
The above configuration class must be _inserted immediately before_ the link:{JDURL}/org/eclipse/jetty/webapp/JettWebXmlConfiguration.html[org.eclipse.jetty.webapp.JettyWebXmlConfiguration] class in the list of configurations.
The above configuration class must be _inserted immediately before_ the link:{JDURL}/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.html[org.eclipse.jetty.webapp.JettyWebXmlConfiguration] class in the list of configurations.
To fully support annotations, you need to do a couple of other things, details of which can be found below.
===== How to Set the List of Configurations
@ -204,7 +204,7 @@ They will then be applied to each `WebAppContext` deployed by the deployer:
Instead of having to enumerate the list in its entirety, you can simply nominate classes that you want to add, and indicate whereabouts in the list you want them inserted.
Let's look at an example of using this method to add in Configuration support for JNDI - as usual you can either do this in an xml file, or via equivalent code.
This example uses an xml file, in fact it is the $JETTY_HOME/etc/jetty-plus.xml file from the Jetty distribution:
This example uses an xml file, in fact it is the `$JETTY_HOME/etc/jetty-plus.xml` file from the Jetty distribution:
[source,xml]
----
@ -235,9 +235,9 @@ This example uses an xml file, in fact it is the $JETTY_HOME/etc/jetty-plus.xml
The link:{JDURL}/org/eclipse/jetty/webapp/Configuration.html[org.eclipse.jetty.webapp.Configuration.ClassList] class provides these methods for insertion:
addAfter::
Inserts the supplied list of Configuration class names after the given Configuration class name.
Inserts the supplied list of `Configuration` class names after the given Configuration class name.
addBefore::
Inserts the supplied list of Configuration class names before the given Configuration class name.
Inserts the supplied list of `Configuration` class names before the given Configuration class name.
[[webapp-context-attributes]]
==== Other Configuration
@ -280,7 +280,7 @@ Similarly to the previous link:#context_attributes[context attribute], this attr
However, this attribute controls which jars from the _webapp's_ classpath (usually `WEB-INF/lib`) are processed.
This can be particularly useful when you have dozens of jars in `WEB-INF/lib`, but you know that only a few need to be scanned.
Here's an example in a xml file of a pattern that matches any jar that starts with "spring-":
Here's an example in a xml file of a pattern that matches any jar that starts with `spring-`:
[source,xml]
----

View File

@ -187,8 +187,8 @@ If you need to configure something within a web application, often you do so by
However, both the servlet standard and some Jetty features allow for other configuration to be applied to a web
application externally from the WAR:
* You configure datasources and security realms in the server and inject them into a web application either explicitly or by name matching.
* Jetty allows one or more override deployment descriptors, in `web.xml` format, to be set on a context (via code or IoC XML) to amend the configuration set by the default and standard ` web.xml`.
* You configure data sources and security realms in the server and inject them into a web application either explicitly or by name matching.
* Jetty allows one or more override deployment descriptors, in `web.xml` format, to be set on a context (via code or IoC XML) to amend the configuration set by the default and standard `web.xml`.
* The normal Jetty Java API may be called by code or IoC XML to amend the configuration of a web application.
===== Setting the Context Path
@ -232,7 +232,7 @@ An example of setting the context path is included with the Jetty distribution i
===== Setting an Authentication Realm
The authentication method and realm name for a standard web application may be set in the ` web.xml` deployment descriptor with elements like:
The authentication method and realm name for a standard web application may be set in the `web.xml` deployment descriptor with elements like:
[source,xml]
----

View File

@ -23,6 +23,9 @@ The following sections provide information about Jetty security issues.
[width="99%",cols="11%,19%,14%,9%,14%,14%,19%",options="header",]
|=======================================================================
|yyyy/mm/dd |ID |Exploitable |Severity |Affects |Fixed Version |Comment
|2016/05/31 |CVE-2016-4800 |high |high |>= 9.3.0, < = 9.3.8 |9.3.9
|http://www.ocert.org/advisories/ocert-2016-001.html[Alias vulnerability allowing access to protected resources within a webapp on Windows.]
|2015/02/24 |CVE-2015-2080 |high |high |>=9.2.3 <9.2.9 |9.2.9
|http://blog.gdssecurity.com/labs/2015/2/25/jetleak-vulnerability-remote-leakage-of-shared-buffers-in-je.html[JetLeak exposure of past buffers during HttpParser error]
@ -34,7 +37,7 @@ https://bugs.eclipse.org/bugs/show_bug.cgi?id=418014[418014] |Alias checking dis
|https://bugs.eclipse.org/bugs/show_bug.cgi?id=413684[413684] |low
|medium |>=7.6.9 <9.0.5 |7.6.13,8.1.13,9.0.5
https://bugs.eclipse.org/bugs/show_bug.cgi?id=413684[413684]
|Constraints bypassed if unix symlink alias checker used on windows
|Constraints bypassed if Unix symlink alias checker used on Windows.
|2011/12/29
|http://www.ocert.org/advisories/ocert-2011-003.html[CERT2011-003] http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-4461[CVE-2011-4461]
@ -49,11 +52,11 @@ around by turning off SSL renegotiation in Jetty. If using JVM > 1.6u19
setAllowRenegotiate(true) may be called on connectors.
|2009/06/18 |http://jira.codehaus.org/browse/JETTY-1042[Jetty-1042] |low
|high |<=6.1.18, <=7.0.0.M4 |6.1.19, 7.0.0.Rc0 |Cookie leak between
|high |< = 6.1.18, < = 7.0.0.M4 |6.1.19, 7.0.0.Rc0 |Cookie leak between
requests sharing a connection.
|2009/04/30 |http://www.kb.cert.org/vuls/id/402580[CERT402580] |medium
|high |<=6.1.16, <=7.0.0.M2 a|
|high |< = 6.1.16, < = 7.0.0.M2 a|
5.1.15, 6.1.18, 7.0.0.M2
http://jira.codehaus.org/browse/JETTY-1004[Jetty-1004]

View File

@ -94,7 +94,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
this.incomingHandler = websocket;
this.connection.getIOState().addListener(this);
this.policy = containerScope.getPolicy();
addBean(this.connection);
addBean(this.websocket);
}
@ -103,13 +103,13 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
public void close()
{
/* This is assumed to always be a NORMAL closure, no reason phrase */
connection.close(StatusCode.NORMAL, null);
close(StatusCode.NORMAL, null);
}
@Override
public void close(CloseStatus closeStatus)
{
this.close(closeStatus.getCode(),closeStatus.getPhrase());
close(closeStatus.getCode(),closeStatus.getPhrase());
}
@Override
@ -134,7 +134,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
{
executor.execute(runnable);
}
@Override
protected void doStart() throws Exception
{
@ -143,27 +143,23 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
super.doStart();
}
@Override
protected void doStop() throws Exception
{
if(LOG.isDebugEnabled())
LOG.debug("stopping - {}",this);
if (getConnection() != null)
try
{
try
{
getConnection().close(StatusCode.SHUTDOWN,"Shutdown");
}
catch (Throwable t)
{
LOG.debug("During Connection Shutdown",t);
}
close(StatusCode.SHUTDOWN,"Shutdown");
}
catch (Throwable t)
{
LOG.debug("During Connection Shutdown",t);
}
super.doStop();
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
@ -223,7 +219,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
{
return this.connection.getBufferPool();
}
public ClassLoader getClassLoader()
{
return this.getClass().getClassLoader();
@ -321,7 +317,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
{
return this.upgradeResponse;
}
@Override
public WebSocketSession getWebSocketSession()
@ -409,12 +405,12 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
{
incomingError(cause);
}
@Override
public void onClosed(Connection connection)
{
}
@Override
public void onOpened(Connection connection)
{
@ -460,7 +456,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
break;
}
}
/**
* Open/Activate the session
*/
@ -474,17 +470,17 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
// already opened
return;
}
try(ThreadClassLoaderScope scope = new ThreadClassLoaderScope(classLoader))
try(ThreadClassLoaderScope scope = new ThreadClassLoaderScope(classLoader))
{
// Upgrade success
connection.getIOState().onConnected();
// Connect remote
remote = new WebSocketRemoteEndpoint(connection,outgoingHandler,getBatchMode());
if(LOG_OPEN.isDebugEnabled())
LOG_OPEN.debug("[{}] {}.open() remote={}",policy.getBehavior(),this.getClass().getSimpleName(),remote);
// Open WebSocket
websocket.openSession(this);
@ -514,7 +510,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
close(statusCode,t.getMessage());
}
}
public void setExtensionFactory(ExtensionFactory extensionFactory)
{
this.extensionFactory = extensionFactory;

View File

@ -58,8 +58,10 @@ import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
/**
* Provides the implementation of {@link LogicalConnection} within the framework of the new {@link org.eclipse.jetty.io.Connection} framework of {@code jetty-io}.
*/
public abstract class AbstractWebSocketConnection extends AbstractConnection implements LogicalConnection, Connection.UpgradeTo, ConnectionStateListener, Dumpable
public abstract class AbstractWebSocketConnection extends AbstractConnection implements LogicalConnection, Connection.UpgradeTo, ConnectionStateListener, Dumpable
{
private final AtomicBoolean closed = new AtomicBoolean();
private class Flusher extends FrameFlusher
{
private Flusher(ByteBufferPool bufferPool, Generator generator, EndPoint endpoint)
@ -190,7 +192,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
return countOnFillableEvents.get();
}
}
private static enum ReadMode
{
PARSE,
@ -256,10 +258,9 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
@Override
public void close()
{
if(LOG_CLOSE.isDebugEnabled())
LOG_CLOSE.debug(".close()");
CloseInfo close = new CloseInfo();
this.outgoingFrame(close.asFrame(),new OnCloseLocalCallback(close),BatchMode.OFF);
if (LOG_CLOSE.isDebugEnabled())
LOG_CLOSE.debug("close()");
close(new CloseInfo());
}
/**
@ -267,7 +268,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
* <p> fillInterested();
* This can result in a close handshake over the network, or a simple local abnormal close
*
*
* @param statusCode
* the WebSocket status code.
* @param reason
@ -278,9 +279,14 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
public void close(int statusCode, String reason)
{
if (LOG_CLOSE.isDebugEnabled())
LOG_CLOSE.debug("close({},{})",statusCode,reason);
CloseInfo close = new CloseInfo(statusCode,reason);
this.outgoingFrame(close.asFrame(),new OnCloseLocalCallback(close),BatchMode.OFF);
LOG_CLOSE.debug("close({},{})", statusCode, reason);
close(new CloseInfo(statusCode, reason));
}
private void close(CloseInfo closeInfo)
{
if (closed.compareAndSet(false, true))
outgoingFrame(closeInfo.asFrame(), new OnCloseLocalCallback(closeInfo), BatchMode.OFF);
}
@Override
@ -341,7 +347,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
* Get the list of extensions in use.
* <p>
* This list is negotiated during the WebSocket Upgrade Request/Response handshake.
*
*
* @return the list of negotiated extensions in use.
*/
public List<ExtensionConfig> getExtensions()
@ -353,7 +359,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
{
return generator;
}
@Override
public String getId()
{
@ -408,7 +414,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
@Override
public boolean isOpen()
{
return getIOState().isOpen() && getEndPoint().isOpen();
return !closed.get();
}
@Override
@ -437,7 +443,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
{
if (LOG_CLOSE.isDebugEnabled())
LOG_CLOSE.debug("{} Connection State Change: {}",policy.getBehavior(),state);
switch (state)
{
case OPEN:
@ -493,9 +499,9 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
if (LOG.isDebugEnabled())
LOG.debug("{} onFillable()",policy.getBehavior());
stats.countOnFillableEvents.incrementAndGet();
ByteBuffer buffer = bufferPool.acquire(getInputBufferSize(),true);
try
{
isFilling = true;
@ -503,7 +509,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
if(readMode == ReadMode.PARSE)
{
readMode = readParse(buffer);
}
}
else
{
readMode = readDiscard(buffer);
@ -524,8 +530,6 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
}
}
@Override
protected void onFillInterestedFailed(Throwable cause)
{
@ -548,12 +552,12 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
}
prefillBuffer = prefilled;
}
private void notifyError(Throwable t)
{
getParser().getIncomingFramesHandler().incomingError(t);
}
@Override
public void onOpen()
{
@ -646,7 +650,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
return ReadMode.DISCARD;
}
}
private ReadMode readParse(ByteBuffer buffer)
{
EndPoint endPoint = getEndPoint();
@ -667,7 +671,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
// Done reading, wait for next onFillable
return ReadMode.PARSE;
}
if (LOG.isDebugEnabled())
{
LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
@ -695,7 +699,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
return ReadMode.DISCARD;
}
}
@Override
public void resume()
{
@ -709,7 +713,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
* Get the list of extensions in use.
* <p>
* This list is negotiated during the WebSocket Upgrade Request/Response handshake.
*
*
* @param extensions
* the list of negotiated extensions in use.
*/
@ -764,7 +768,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
{
final int prime = 31;
int result = 1;
EndPoint endp = getEndPoint();
if(endp != null)
{

View File

@ -44,7 +44,7 @@ public class IOState
/**
* The source of a close handshake. (ie: who initiated it).
*/
private static enum CloseHandshakeSource
private enum CloseHandshakeSource
{
/** No close handshake initiated (yet) */
NONE,
@ -53,7 +53,7 @@ public class IOState
/** Remote side initiated the close handshake */
REMOTE,
/** An abnormal close situation (disconnect, timeout, etc...) */
ABNORMAL;
ABNORMAL
}
public static interface ConnectionStateListener
@ -65,17 +65,17 @@ public class IOState
private ConnectionState state;
private final List<ConnectionStateListener> listeners = new CopyOnWriteArrayList<>();
/**
/**
* Is input on websocket available (for reading frames).
* Used to determine close handshake completion, and track half-close states
*/
private boolean inputAvailable;
/**
/**
* Is output on websocket available (for writing frames).
* Used to determine close handshake completion, and track half-closed states.
*/
private boolean outputAvailable;
/**
/**
* Initiator of the close handshake.
* Used to determine who initiated a close handshake for reply reasons.
*/
@ -150,7 +150,7 @@ public class IOState
public boolean isClosed()
{
synchronized (state)
synchronized (this)
{
return (state == ConnectionState.CLOSED);
}
@ -163,7 +163,7 @@ public class IOState
public boolean isOpen()
{
return (getConnectionState() != ConnectionState.CLOSED);
return !isClosed();
}
public boolean isOutputAvailable()
@ -221,67 +221,87 @@ public class IOState
/**
* A close handshake has been issued from the local endpoint
* @param close the close information
* @param closeInfo the close information
*/
public void onCloseLocal(CloseInfo close)
public void onCloseLocal(CloseInfo closeInfo)
{
boolean open = false;
synchronized (this)
{
ConnectionState initialState = this.state;
if (LOG.isDebugEnabled())
LOG.debug("onCloseLocal({}) : {}", closeInfo, initialState);
if (initialState == ConnectionState.CLOSED)
{
// already closed
if (LOG.isDebugEnabled())
LOG.debug("already closed");
return;
}
if (initialState == ConnectionState.CONNECTED)
{
// fast close. a local close request from end-user onConnect/onOpen method
if (LOG.isDebugEnabled())
LOG.debug("FastClose in CONNECTED detected");
open = true;
}
}
if (open)
openAndCloseLocal(closeInfo);
else
closeLocal(closeInfo);
}
private void openAndCloseLocal(CloseInfo closeInfo)
{
// Force the state open (to allow read/write to endpoint)
onOpened();
if (LOG.isDebugEnabled())
LOG.debug("FastClose continuing with Closure");
closeLocal(closeInfo);
}
private void closeLocal(CloseInfo closeInfo)
{
ConnectionState event = null;
ConnectionState abnormalEvent = null;
ConnectionState initialState = this.state;
if (LOG.isDebugEnabled())
LOG.debug("onCloseLocal({}) : {}",close,initialState);
if (initialState == ConnectionState.CLOSED)
{
// already closed
LOG.debug("already closed");
return;
}
if (initialState == ConnectionState.CONNECTED)
{
// fast close. a local close request from end-user onConnect/onOpen method
LOG.debug("FastClose in CONNECTED detected");
// Force the state open (to allow read/write to endpoint)
onOpened();
if (LOG.isDebugEnabled())
LOG.debug("FastClose continuing with Closure");
}
synchronized (this)
{
closeInfo = close;
// Turn off further output
if (LOG.isDebugEnabled())
LOG.debug("onCloseLocal(), input={}, output={}", inputAvailable, outputAvailable);
this.closeInfo = closeInfo;
// Turn off further output.
outputAvailable = false;
boolean in = inputAvailable;
boolean out = outputAvailable;
if (closeHandshakeSource == CloseHandshakeSource.NONE)
{
closeHandshakeSource = CloseHandshakeSource.LOCAL;
}
LOG.debug("onCloseLocal(), input={}, output={}",in,out);
if (!in && !out)
if (!inputAvailable)
{
LOG.debug("Close Handshake satisfied, disconnecting");
if (LOG.isDebugEnabled())
LOG.debug("Close Handshake satisfied, disconnecting");
cleanClose = true;
this.state = ConnectionState.CLOSED;
finalClose.compareAndSet(null,close);
finalClose.compareAndSet(null,closeInfo);
event = this.state;
}
else if (this.state == ConnectionState.OPEN)
{
// We are now entering CLOSING (or half-closed)
// We are now entering CLOSING (or half-closed).
this.state = ConnectionState.CLOSING;
event = this.state;
// if abnormal, we don't expect an answer.
if (close.isAbnormal())
// If abnormal, we don't expect an answer.
if (closeInfo.isAbnormal())
{
abnormalEvent = ConnectionState.CLOSED;
finalClose.compareAndSet(null,close);
finalClose.compareAndSet(null,closeInfo);
cleanClose = false;
outputAvailable = false;
inputAvailable = false;
@ -294,8 +314,7 @@ public class IOState
if (event != null)
{
notifyStateListeners(event);
if(abnormalEvent != null)
if (abnormalEvent != null)
{
notifyStateListeners(abnormalEvent);
}
@ -304,12 +323,12 @@ public class IOState
/**
* A close handshake has been received from the remote endpoint
* @param close the close information
* @param closeInfo the close information
*/
public void onCloseRemote(CloseInfo close)
public void onCloseRemote(CloseInfo closeInfo)
{
if (LOG.isDebugEnabled())
LOG.debug("onCloseRemote({})",close);
LOG.debug("onCloseRemote({})", closeInfo);
ConnectionState event = null;
synchronized (this)
{
@ -319,27 +338,25 @@ public class IOState
return;
}
closeInfo = close;
if (LOG.isDebugEnabled())
LOG.debug("onCloseRemote(), input={}, output={}", inputAvailable, outputAvailable);
this.closeInfo = closeInfo;
// turn off further input
inputAvailable = false;
boolean in = inputAvailable;
boolean out = outputAvailable;
if (closeHandshakeSource == CloseHandshakeSource.NONE)
{
closeHandshakeSource = CloseHandshakeSource.REMOTE;
}
if (LOG.isDebugEnabled())
LOG.debug("onCloseRemote(), input={}, output={}",in,out);
if (!in && !out)
if (!outputAvailable)
{
LOG.debug("Close Handshake satisfied, disconnecting");
cleanClose = true;
state = ConnectionState.CLOSED;
finalClose.compareAndSet(null,close);
finalClose.compareAndSet(null,closeInfo);
event = this.state;
}
else if (this.state == ConnectionState.OPEN)
@ -406,7 +423,7 @@ public class IOState
{
if(LOG.isDebugEnabled())
LOG.debug(" onOpened()");
ConnectionState event = null;
synchronized (this)
{