Merged branch 'jetty-9.4.x' into 'master'.

This commit is contained in:
Simone Bordet 2016-12-20 11:55:39 +01:00
commit b5d2b73f07
5 changed files with 413 additions and 376 deletions

View File

@ -17,19 +17,19 @@
[[what-jetty-version]]
=== What Version Do I Use?
Jetty 9 is the most recent version of Jetty and has a great many improvements over previous versions.
One improvement is this documentation which focuses on Jetty 9.
Jetty 9 is the most recent version of Jetty and has a great many improvements over previous versions.
This documentation which focuses on Jetty 9.
While many people continue to use older versions of Jetty, we generally recommend using Jetty 9 as it represents the version of Jetty that we will actively maintain and improve over the next few years.
.Jetty Versions
[width="100%",cols="12%,9%,15%,6%,21%,10%,6%,21%",options="header",]
|=======================================================================
|Version |Year |Home |JVM |Protocols |Servlet |JSP |Status
|9.4 |2016 |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable
|9.3 |2015 |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable
|9.2 |2014 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Stable
|8.2 |2009- |Eclipse/Codehaus |1.7 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable
|8.1 |2009- |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable
|7 |2008- |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Venerable
|8 |2009-2014 |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Deprecated
|7 |2008-2014 |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Deprecated
|6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated
|5 |2003-2009 |Sourceforge |1.2-1.5 |HTTP/1.1 RFC2616 |2.4 |2.0 |Deprecated
|4 |2001-2006 |Sourceforge |1.2, J2ME |HTTP/1.1 RFC2616 |2.3 |1.2 |Ancient

View File

@ -23,4 +23,5 @@ include::troubleshooting-zip-exceptions.adoc[]
include::troubleshooting-locked-files.adoc[]
include::preventing-memory-leaks.adoc[]
include::slow-deployment.adoc[]
include::security-reports.adoc[]
include::security-reports.adoc[]
include::watchservice.adoc[]

View File

@ -0,0 +1,35 @@
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ========================================================================
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
[[watchservice]]
=== Java WatchService
The JVM link:https://docs.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html[`WatchService`] is in place to monitor objects like a directory for changes, and then update it's contents and notify the application of those changes.
This service is useful for features like link:#hot-deployment[Hot Deployment].
When a change is detected, the `WatchService` will enter a "quiet time" where it is waiting for the change (or changes) to be made and completed before notifying the application of the change.
Example:
A new war file is copied into `/webapps`.
The `WatchService` can (depending on implementation) see that the file was created (which is registered as an event!, and that its growing in size (another event).
With the quiet time, each of the events are gated behind that timeout before the aggregated events are sent to the application.
While some operating systems such as Windows have a native value for this quiet time, not all do, notably OSX.
At the core this is a limitation of the JVM's FileSystem-specific implementation, but one that has been raised to the link:https://bugs.openjdk.java.net/browse/JDK-7133447[attention of the project.]
==== Remedy
To help offset the delay in systems like OSX, Jetty defaults the value for non-native implementations to a link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java#L1431[time of 5000ms.]
Using values lower than 5000ms is not recommended and has shown to frequently fail.

View File

@ -92,8 +92,7 @@ public class SslConnection extends AbstractConnection
private final boolean _decryptedDirectBuffers = false;
private boolean _renegotiationAllowed;
private boolean _closedOutbound;
private abstract class RunnableTask implements Runnable, Invocable
{
private final String _operation;
@ -109,7 +108,7 @@ public class SslConnection extends AbstractConnection
return String.format("SSL:%s:%s:%s",SslConnection.this,_operation,getInvocationType());
}
}
private final Runnable _runCompleteWrite = new RunnableTask("runCompleteWrite")
{
@Override
@ -117,14 +116,14 @@ public class SslConnection extends AbstractConnection
{
_decryptedEndPoint.getWriteFlusher().completeWrite();
}
@Override
public InvocationType getInvocationType()
{
return getDecryptedEndPoint().getWriteFlusher().getCallbackInvocationType();
}
};
private final Runnable _runFillable = new RunnableTask("runFillable")
{
@Override
@ -132,15 +131,15 @@ public class SslConnection extends AbstractConnection
{
_decryptedEndPoint.getFillInterest().fillable();
}
@Override
public InvocationType getInvocationType()
{
return getDecryptedEndPoint().getFillInterest().getCallbackInvocationType();
}
};
Callback _sslReadCallback = new Callback()
private final Callback _sslReadCallback = new Callback()
{
@Override
public void succeeded()
@ -309,12 +308,12 @@ public class SslConnection extends AbstractConnection
int di=b==null?-1:b.remaining();
return String.format("%s@%x{%s,eio=%d/%d,di=%d}=>%s",
getClass().getSimpleName(),
getClass().getSimpleName(),
hashCode(),
_sslEngine.getHandshakeStatus(),
ei,eo,di,
((AbstractConnection)_decryptedEndPoint.getConnection()).toConnectionString());
}
}
public class DecryptedEndPoint extends AbstractEndPoint
{
@ -353,35 +352,31 @@ public class SslConnection extends AbstractConnection
// This means that a write of data has failed. Writes are done
// only if there is an active writeflusher or a read needed to write
// data. In either case the appropriate callback is passed on.
boolean fail_filler = false;
boolean fail_filler;
synchronized (DecryptedEndPoint.this)
{
if (LOG.isDebugEnabled())
LOG.debug("{} write.failed", SslConnection.this, x);
LOG.debug("{} write failed", SslConnection.this, x);
BufferUtil.clear(_encryptedOutput);
releaseEncryptedOutputBuffer();
_cannotAcceptMoreAppDataToFlush = false;
fail_filler = _fillRequiresFlushToProgress;
if (_fillRequiresFlushToProgress)
{
_fillRequiresFlushToProgress = false;
fail_filler = true;
}
}
final boolean filler_failed=fail_filler;
failedCallback(new Callback()
{
@Override
public void failed(Throwable x)
{
if (filler_failed)
if (fail_filler)
getFillInterest().onFail(x);
getWriteFlusher().onFail(x);
}
},x);
}, x);
}
@Override
@ -389,7 +384,7 @@ public class SslConnection extends AbstractConnection
{
return getWriteFlusher().getCallbackInvocationType();
}
@Override
public String toString()
{
@ -473,7 +468,7 @@ public class SslConnection extends AbstractConnection
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
{
// check if we are actually read blocked in order to write
_flushRequiresFillToProgress = true;
_flushRequiresFillToProgress = true;
need_fill_interest = !SslConnection.this.isFillInterested();
}
else
@ -488,7 +483,7 @@ public class SslConnection extends AbstractConnection
}
if (write)
getEndPoint().write(_writeCallback, _encryptedOutput);
getEndPoint().write(_writeCallback, _encryptedOutput);
else if (need_fill_interest)
ensureFillInterested();
else if (try_again)
@ -507,7 +502,6 @@ public class SslConnection extends AbstractConnection
getExecutor().execute(_runCompleteWrite);
}
}
}
@Override
@ -557,7 +551,7 @@ public class SslConnection extends AbstractConnection
getEndPoint().write(_writeCallback, _encryptedOutput);
else if (fillable)
getExecutor().execute(_runFillable);
else
else
ensureFillInterested();
}
@ -579,100 +573,191 @@ public class SslConnection extends AbstractConnection
}
@Override
public synchronized int fill(ByteBuffer buffer) throws IOException
public int fill(ByteBuffer buffer) throws IOException
{
try
{
// Do we already have some decrypted data?
if (BufferUtil.hasContent(_decryptedInput))
return BufferUtil.append(buffer,_decryptedInput);
// We will need a network buffer
if (_encryptedInput == null)
_encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
else
BufferUtil.compact(_encryptedInput);
// We also need an app buffer, but can use the passed buffer if it is big enough
ByteBuffer app_in;
if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
app_in = buffer;
else if (_decryptedInput == null)
app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers);
else
app_in = _decryptedInput;
// loop filling and unwrapping until we have something
while (true)
synchronized (this)
{
// Let's try reading some encrypted data... even if we have some already.
int net_filled = getEndPoint().fill(_encryptedInput);
decryption: while (true)
try
{
// Let's unwrap even if we have no net data because in that
// case we want to fall through to the handshake handling
int pos = BufferUtil.flipToFill(app_in);
SSLEngineResult unwrapResult;
try
{
unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
}
finally
{
BufferUtil.flipToFlush(app_in, pos);
}
if (LOG.isDebugEnabled())
{
LOG.debug("{} net={} unwrap {}", SslConnection.this, net_filled, unwrapResult.toString().replace('\n',' '));
LOG.debug("{} filled {}",SslConnection.this,BufferUtil.toHexSummary(buffer));
}
// Do we already have some decrypted data?
if (BufferUtil.hasContent(_decryptedInput))
return BufferUtil.append(buffer,_decryptedInput);
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
Status unwrapResultStatus = unwrapResult.getStatus();
// We will need a network buffer
if (_encryptedInput == null)
_encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
else
BufferUtil.compact(_encryptedInput);
// Extra check on unwrapResultStatus == OK with zero bytes consumed
// or produced is due to an SSL client on Android (see bug #454773).
_underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW ||
unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed() == 0 && unwrapResult.bytesProduced() == 0;
// We also need an app buffer, but can use the passed buffer if it is big enough
ByteBuffer app_in;
if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
app_in = buffer;
else if (_decryptedInput == null)
app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers);
else
app_in = _decryptedInput;
if (_underFlown)
// loop filling and unwrapping until we have something
while (true)
{
if (net_filled < 0)
closeInbound();
if (net_filled <= 0)
return net_filled;
}
// Let's try reading some encrypted data... even if we have some already.
int net_filled = getEndPoint().fill(_encryptedInput);
switch (unwrapResultStatus)
{
case CLOSED:
decryption: while (true)
{
switch (handshakeStatus)
// Let's unwrap even if we have no net data because in that
// case we want to fall through to the handshake handling
int pos = BufferUtil.flipToFill(app_in);
SSLEngineResult unwrapResult;
try
{
case NOT_HANDSHAKING:
unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
}
finally
{
BufferUtil.flipToFlush(app_in, pos);
}
if (LOG.isDebugEnabled())
{
LOG.debug("{} net={} unwrap {}", SslConnection.this, net_filled, unwrapResult.toString().replace('\n',' '));
LOG.debug("{} filled {}",SslConnection.this,BufferUtil.toHexSummary(buffer));
}
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
Status unwrapResultStatus = unwrapResult.getStatus();
// Extra check on unwrapResultStatus == OK with zero bytes consumed
// or produced is due to an SSL client on Android (see bug #454773).
_underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW ||
unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed() == 0 && unwrapResult.bytesProduced() == 0;
if (_underFlown)
{
if (net_filled < 0)
closeInbound();
if (net_filled <= 0)
return net_filled;
}
switch (unwrapResultStatus)
{
case CLOSED:
{
// We were not handshaking, so just tell the app we are closed
return -1;
switch (handshakeStatus)
{
case NOT_HANDSHAKING:
{
// We were not handshaking, so just tell the app we are closed
return -1;
}
case NEED_TASK:
{
_sslEngine.getDelegatedTask().run();
continue;
}
case NEED_WRAP:
{
// We need to send some handshake data (probably the close handshake).
// We return -1 so that the application can drive the close by flushing
// or shutting down the output.
return -1;
}
case NEED_UNWRAP:
{
// We expected to read more, but we got closed.
// Return -1 to indicate to the application to drive the close.
return -1;
}
default:
{
throw new IllegalStateException();
}
}
}
case NEED_TASK:
case BUFFER_UNDERFLOW:
case OK:
{
_sslEngine.getDelegatedTask().run();
continue;
}
case NEED_WRAP:
{
// We need to send some handshake data (probably the close handshake).
// We return -1 so that the application can drive the close by flushing
// or shutting down the output.
return -1;
}
case NEED_UNWRAP:
{
// We expected to read more, but we got closed.
// Return -1 to indicate to the application to drive the close.
return -1;
if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "client" : "resumed server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
notifyHandshakeSucceeded(_sslEngine);
}
// Check whether renegotiation is allowed
if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
{
if (LOG.isDebugEnabled())
LOG.debug("{} renegotiation denied", SslConnection.this);
closeInbound();
return -1;
}
// If bytes were produced, don't bother with the handshake status;
// pass the decrypted data to the application, which will perform
// another call to fill() or flush().
if (unwrapResult.bytesProduced() > 0)
{
if (app_in == buffer)
return unwrapResult.bytesProduced();
return BufferUtil.append(buffer,_decryptedInput);
}
switch (handshakeStatus)
{
case NOT_HANDSHAKING:
{
if (_underFlown)
break decryption;
continue;
}
case NEED_TASK:
{
_sslEngine.getDelegatedTask().run();
continue;
}
case NEED_WRAP:
{
// If we are called from flush()
// return to let it do the wrapping.
if (_flushRequiresFillToProgress)
return 0;
_fillRequiresFlushToProgress = true;
flush(BufferUtil.EMPTY_BUFFER);
if (BufferUtil.isEmpty(_encryptedOutput))
{
// The flush wrote all the encrypted bytes so continue to fill.
_fillRequiresFlushToProgress = false;
if (_underFlown)
break decryption;
continue;
}
else
{
// The flush did not complete, return from fill()
// and let the write completion mechanism to kick in.
return 0;
}
}
case NEED_UNWRAP:
{
if (_underFlown)
break decryption;
continue;
}
default:
{
throw new IllegalStateException();
}
}
}
default:
{
@ -680,136 +765,49 @@ public class SslConnection extends AbstractConnection
}
}
}
case BUFFER_UNDERFLOW:
case OK:
{
if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "client" : "resumed server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
notifyHandshakeSucceeded(_sslEngine);
}
// Check whether renegotiation is allowed
if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
{
if (LOG.isDebugEnabled())
LOG.debug("{} renegotiation denied", SslConnection.this);
closeInbound();
return -1;
}
// If bytes were produced, don't bother with the handshake status;
// pass the decrypted data to the application, which will perform
// another call to fill() or flush().
if (unwrapResult.bytesProduced() > 0)
{
if (app_in == buffer)
return unwrapResult.bytesProduced();
return BufferUtil.append(buffer,_decryptedInput);
}
switch (handshakeStatus)
{
case NOT_HANDSHAKING:
{
if (_underFlown)
break decryption;
continue;
}
case NEED_TASK:
{
_sslEngine.getDelegatedTask().run();
continue;
}
case NEED_WRAP:
{
// If we are called from flush()
// return to let it do the wrapping.
if (_flushRequiresFillToProgress)
return 0;
_fillRequiresFlushToProgress = true;
flush(BufferUtil.EMPTY_BUFFER);
if (BufferUtil.isEmpty(_encryptedOutput))
{
// The flush wrote all the encrypted bytes so continue to fill.
_fillRequiresFlushToProgress = false;
if (_underFlown)
break decryption;
continue;
}
else
{
// The flush did not complete, return from fill()
// and let the write completion mechanism to kick in.
return 0;
}
}
case NEED_UNWRAP:
{
if (_underFlown)
break decryption;
continue;
}
default:
{
throw new IllegalStateException();
}
}
}
default:
{
throw new IllegalStateException();
}
}
}
catch (SSLHandshakeException x)
{
notifyHandshakeFailed(_sslEngine, x);
throw x;
}
catch (SSLException x)
{
if (!_handshaken)
{
x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x);
notifyHandshakeFailed(_sslEngine, x);
}
throw x;
}
finally
{
// If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
if (_flushRequiresFillToProgress)
{
_flushRequiresFillToProgress = false;
getExecutor().execute(_runCompleteWrite);
}
if (_encryptedInput != null && !_encryptedInput.hasRemaining())
{
_bufferPool.release(_encryptedInput);
_encryptedInput = null;
}
if (_decryptedInput != null && !_decryptedInput.hasRemaining())
{
_bufferPool.release(_decryptedInput);
_decryptedInput = null;
}
}
}
}
catch (SSLHandshakeException x)
{
notifyHandshakeFailed(_sslEngine, x);
close(x);
throw x;
}
catch (SSLException x)
{
if (!_handshaken)
{
x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x);
notifyHandshakeFailed(_sslEngine, x);
}
close(x);
throw x;
}
catch (Throwable x)
{
close(x);
throw x;
}
finally
{
// If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
if (_flushRequiresFillToProgress)
{
_flushRequiresFillToProgress = false;
getExecutor().execute(_runCompleteWrite);
}
if (_encryptedInput != null && !_encryptedInput.hasRemaining())
{
_bufferPool.release(_encryptedInput);
_encryptedInput = null;
}
if (_decryptedInput != null && !_decryptedInput.hasRemaining())
{
_bufferPool.release(_decryptedInput);
_decryptedInput = null;
}
}
}
private void closeInbound()
@ -825,7 +823,7 @@ public class SslConnection extends AbstractConnection
}
@Override
public synchronized boolean flush(ByteBuffer... appOuts) throws IOException
public boolean flush(ByteBuffer... appOuts) throws IOException
{
// The contract for flush does not require that all appOuts bytes are written
// or even that any appOut bytes are written! If the connection is write block
@ -842,159 +840,164 @@ public class SslConnection extends AbstractConnection
try
{
if (_cannotAcceptMoreAppDataToFlush)
synchronized (this)
{
if (_sslEngine.isOutboundDone())
throw new EofException(new ClosedChannelException());
return false;
}
// We will need a network buffer
if (_encryptedOutput == null)
_encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
while (true)
{
// We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
BufferUtil.compact(_encryptedOutput);
int pos = BufferUtil.flipToFill(_encryptedOutput);
SSLEngineResult wrapResult;
try
{
wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
if (_cannotAcceptMoreAppDataToFlush)
{
if (_sslEngine.isOutboundDone())
throw new EofException(new ClosedChannelException());
return false;
}
// We will need a network buffer
if (_encryptedOutput == null)
_encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
while (true)
{
// We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
BufferUtil.compact(_encryptedOutput);
int pos = BufferUtil.flipToFill(_encryptedOutput);
SSLEngineResult wrapResult;
try
{
wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
}
finally
{
BufferUtil.flipToFlush(_encryptedOutput, pos);
}
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {}", SslConnection.this, wrapResult.toString().replace('\n',' '));
Status wrapResultStatus = wrapResult.getStatus();
boolean allConsumed=true;
for (ByteBuffer b : appOuts)
if (BufferUtil.hasContent(b))
allConsumed=false;
// and deal with the results returned from the sslEngineWrap
switch (wrapResultStatus)
{
case CLOSED:
{
// The SSL engine has close, but there may be close handshake that needs to be written
if (BufferUtil.hasContent(_encryptedOutput))
{
_cannotAcceptMoreAppDataToFlush = true;
getEndPoint().flush(_encryptedOutput);
getEndPoint().shutdownOutput();
// If we failed to flush the close handshake then we will just pretend that
// the write has progressed normally and let a subsequent call to flush
// (or WriteFlusher#onIncompleteFlushed) to finish writing the close handshake.
// The caller will find out about the close on a subsequent flush or fill.
if (BufferUtil.hasContent(_encryptedOutput))
return false;
}
// otherwise we have written, and the caller will close the underlying connection
else
{
getEndPoint().shutdownOutput();
}
return allConsumed;
}
case BUFFER_UNDERFLOW:
{
throw new IllegalStateException();
}
default:
{
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput));
if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "resumed client" : "server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
notifyHandshakeSucceeded(_sslEngine);
}
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
// Check whether renegotiation is allowed
if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
{
if (LOG.isDebugEnabled())
LOG.debug("{} renegotiation denied", SslConnection.this);
getEndPoint().shutdownOutput();
return allConsumed;
}
// if we have net bytes, let's try to flush them
if (BufferUtil.hasContent(_encryptedOutput))
if (!getEndPoint().flush(_encryptedOutput))
getEndPoint().flush(_encryptedOutput); // one retry
// But we also might have more to do for the handshaking state.
switch (handshakeStatus)
{
case NOT_HANDSHAKING:
// If we have not consumed all and had just finished handshaking, then we may
// have just flushed the last handshake in the encrypted buffers, so we should
// try again.
if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput))
continue;
// Return true if we consumed all the bytes and encrypted are all flushed
return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
case NEED_TASK:
// run the task and continue
_sslEngine.getDelegatedTask().run();
continue;
case NEED_WRAP:
// Hey we just wrapped! Oh well who knows what the sslEngine is thinking, so continue and we will wrap again
continue;
case NEED_UNWRAP:
// Ah we need to fill some data so we can write.
// So if we were not called from fill and the app is not reading anyway
if (!_fillRequiresFlushToProgress && !getFillInterest().isInterested())
{
// Tell the onFillable method that there might be a write to complete
_flushRequiresFillToProgress = true;
fill(BufferUtil.EMPTY_BUFFER);
// Check if after the fill() we need to wrap again
if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)
continue;
}
return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
case FINISHED:
throw new IllegalStateException();
}
}
}
}
}
catch (SSLHandshakeException x)
{
notifyHandshakeFailed(_sslEngine, x);
throw x;
}
finally
{
BufferUtil.flipToFlush(_encryptedOutput, pos);
}
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {}", SslConnection.this, wrapResult.toString().replace('\n',' '));
Status wrapResultStatus = wrapResult.getStatus();
boolean allConsumed=true;
for (ByteBuffer b : appOuts)
if (BufferUtil.hasContent(b))
allConsumed=false;
// and deal with the results returned from the sslEngineWrap
switch (wrapResultStatus)
{
case CLOSED:
{
// The SSL engine has close, but there may be close handshake that needs to be written
if (BufferUtil.hasContent(_encryptedOutput))
{
_cannotAcceptMoreAppDataToFlush = true;
getEndPoint().flush(_encryptedOutput);
getEndPoint().shutdownOutput();
// If we failed to flush the close handshake then we will just pretend that
// the write has progressed normally and let a subsequent call to flush
// (or WriteFlusher#onIncompleteFlushed) to finish writing the close handshake.
// The caller will find out about the close on a subsequent flush or fill.
if (BufferUtil.hasContent(_encryptedOutput))
return false;
}
// otherwise we have written, and the caller will close the underlying connection
else
{
getEndPoint().shutdownOutput();
}
return allConsumed;
}
case BUFFER_UNDERFLOW:
{
throw new IllegalStateException();
}
default:
{
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput));
if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "resumed client" : "server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
notifyHandshakeSucceeded(_sslEngine);
}
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
// Check whether renegotiation is allowed
if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
{
if (LOG.isDebugEnabled())
LOG.debug("{} renegotiation denied", SslConnection.this);
getEndPoint().shutdownOutput();
return allConsumed;
}
// if we have net bytes, let's try to flush them
if (BufferUtil.hasContent(_encryptedOutput))
if (!getEndPoint().flush(_encryptedOutput))
getEndPoint().flush(_encryptedOutput); // one retry
// But we also might have more to do for the handshaking state.
switch (handshakeStatus)
{
case NOT_HANDSHAKING:
// If we have not consumed all and had just finished handshaking, then we may
// have just flushed the last handshake in the encrypted buffers, so we should
// try again.
if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput))
continue;
// Return true if we consumed all the bytes and encrypted are all flushed
return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
case NEED_TASK:
// run the task and continue
_sslEngine.getDelegatedTask().run();
continue;
case NEED_WRAP:
// Hey we just wrapped! Oh well who knows what the sslEngine is thinking, so continue and we will wrap again
continue;
case NEED_UNWRAP:
// Ah we need to fill some data so we can write.
// So if we were not called from fill and the app is not reading anyway
if (!_fillRequiresFlushToProgress && !getFillInterest().isInterested())
{
// Tell the onFillable method that there might be a write to complete
_flushRequiresFillToProgress = true;
fill(BufferUtil.EMPTY_BUFFER);
// Check if after the fill() we need to wrap again
if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)
continue;
}
return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
case FINISHED:
throw new IllegalStateException();
}
releaseEncryptedOutputBuffer();
}
}
}
}
catch (SSLHandshakeException x)
{
notifyHandshakeFailed(_sslEngine, x);
close(x);
throw x;
}
catch (Throwable x)
{
close(x);
throw x;
}
finally
{
releaseEncryptedOutputBuffer();
}
}
private void releaseEncryptedOutputBuffer()
@ -1035,9 +1038,8 @@ public class SslConnection extends AbstractConnection
// TODO review close logic here
if (ishut)
close = true;
}
if (flush)
flush(BufferUtil.EMPTY_BUFFER); // Send the TLS close message.
if (close)
@ -1051,7 +1053,7 @@ public class SslConnection extends AbstractConnection
getEndPoint().close();
}
}
private void ensureFillInterested()
{
if (LOG.isDebugEnabled())
@ -1128,5 +1130,4 @@ public class SslConnection extends AbstractConnection
return super.toString()+"->"+getEndPoint().toString();
}
}
}

View File

@ -8,7 +8,7 @@ logback
[depend]
server
logback-core
logback-impl
resources
[provide]