Merged branch 'jetty-9.4.x' into 'jetty-10.0.x'.
This commit is contained in:
commit
1cb09db75a
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpStatus;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -53,6 +54,7 @@ public class ProxyServerTest extends AbstractEmbeddedTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@Tag("external")
|
||||
@Test
|
||||
public void testGetProxiedRFC() throws Exception
|
||||
{
|
||||
|
|
|
@ -410,6 +410,9 @@ public abstract class HttpReceiver
|
|||
if (exchange == null)
|
||||
return false;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Response failure " + exchange.getResponse(), failure);
|
||||
|
||||
// Mark atomically the response as completed, with respect
|
||||
// to concurrency between response success and response failure.
|
||||
if (exchange.responseComplete(failure))
|
||||
|
@ -514,7 +517,7 @@ public abstract class HttpReceiver
|
|||
|
||||
HttpResponse response = exchange.getResponse();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Response failure {} {} on {}: {}", response, exchange, getHttpChannel(), failure);
|
||||
LOG.debug("Response abort {} {} on {}: {}", response, exchange, getHttpChannel(), failure);
|
||||
List<Response.ResponseListener> listeners = exchange.getConversation().getResponseListeners();
|
||||
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
|
||||
notifier.notifyFailure(listeners, response, failure);
|
||||
|
|
|
@ -344,6 +344,9 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
if (exchange == null)
|
||||
return;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Request failure " + exchange.getRequest(), failure);
|
||||
|
||||
// Mark atomically the request as completed, with respect
|
||||
// to concurrency between request success and request failure.
|
||||
if (exchange.requestComplete(failure))
|
||||
|
@ -559,7 +562,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
|
||||
Request request = exchange.getRequest();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Request failure {} {} on {}: {}", request, exchange, getHttpChannel(), failure);
|
||||
LOG.debug("Request abort {} {} on {}: {}", request, exchange, getHttpChannel(), failure);
|
||||
HttpDestination destination = getHttpChannel().getHttpDestination();
|
||||
destination.getRequestNotifier().notifyFailure(request, failure);
|
||||
|
||||
|
|
|
@ -288,7 +288,6 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
public void failed(Throwable x)
|
||||
{
|
||||
release();
|
||||
callback.failed(x);
|
||||
super.failed(x);
|
||||
}
|
||||
|
||||
|
@ -299,6 +298,13 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
callback.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCompleteFailure(Throwable cause)
|
||||
{
|
||||
super.onCompleteFailure(cause);
|
||||
callback.failed(cause);
|
||||
}
|
||||
|
||||
private void release()
|
||||
{
|
||||
ByteBufferPool bufferPool = httpClient.getByteBufferPool();
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -48,7 +47,6 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
* This test class runs tests to make sure that hostname verification (http://www.ietf.org/rfc/rfc2818.txt
|
||||
* section 3.1) is configurable in SslContextFactory and works as expected.
|
||||
*/
|
||||
@Disabled
|
||||
public class HostnameVerificationTest
|
||||
{
|
||||
private SslContextFactory.Client clientSslContextFactory = new SslContextFactory.Client();
|
||||
|
@ -100,18 +98,15 @@ public class HostnameVerificationTest
|
|||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test is supposed to verify that hostname verification works as described in:
|
||||
* http://www.ietf.org/rfc/rfc2818.txt section 3.1. It uses a certificate with a common name different to localhost
|
||||
* and sends a request to localhost. This should fail with an SSLHandshakeException.
|
||||
*
|
||||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
public void simpleGetWithHostnameVerificationEnabledTest() throws Exception
|
||||
public void simpleGetWithHostnameVerificationEnabledTest()
|
||||
{
|
||||
clientSslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
String uri = "https://localhost:" + connector.getLocalPort() + "/";
|
||||
|
@ -119,8 +114,16 @@ public class HostnameVerificationTest
|
|||
ExecutionException x = assertThrows(ExecutionException.class, () -> client.GET(uri));
|
||||
Throwable cause = x.getCause();
|
||||
assertThat(cause, Matchers.instanceOf(SSLHandshakeException.class));
|
||||
Throwable root = cause.getCause().getCause();
|
||||
assertThat(root, Matchers.instanceOf(CertificateException.class));
|
||||
|
||||
// Search for the CertificateException.
|
||||
Throwable certificateException = cause.getCause();
|
||||
while (certificateException != null)
|
||||
{
|
||||
if (certificateException instanceof CertificateException)
|
||||
break;
|
||||
certificateException = certificateException.getCause();
|
||||
}
|
||||
assertThat(certificateException, Matchers.instanceOf(CertificateException.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -146,7 +146,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
@Override
|
||||
public InvocationType getInvocationType()
|
||||
{
|
||||
return getDecryptedEndPoint().getFillInterest().getCallbackInvocationType();
|
||||
return _decryptedEndPoint.getFillInterest().getCallbackInvocationType();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -364,6 +364,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
public class DecryptedEndPoint extends AbstractEndPoint
|
||||
{
|
||||
private final Callback _incompleteWriteCallback = new IncompleteWriteCallback();
|
||||
private Throwable _failure;
|
||||
|
||||
public DecryptedEndPoint()
|
||||
{
|
||||
|
@ -451,14 +452,10 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
LOG.debug("onFillableFail {}", SslConnection.this, failure);
|
||||
|
||||
_fillState = FillState.IDLE;
|
||||
switch (_flushState)
|
||||
if (_flushState == FlushState.WAIT_FOR_FILL)
|
||||
{
|
||||
case WAIT_FOR_FILL:
|
||||
_flushState = FlushState.IDLE;
|
||||
fail = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
_flushState = FlushState.IDLE;
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,12 +526,14 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
case NEED_WRAP:
|
||||
if (_flushState == FlushState.IDLE && flush(BufferUtil.EMPTY_BUFFER))
|
||||
{
|
||||
Throwable failure = _failure;
|
||||
if (failure != null)
|
||||
rethrow(failure);
|
||||
if (_sslEngine.isInboundDone())
|
||||
// TODO this is probably a JVM bug, work around it by -1
|
||||
return -1;
|
||||
return filled = -1;
|
||||
continue;
|
||||
}
|
||||
// handle in needsFillInterest
|
||||
// Handle in needsFillInterest().
|
||||
return filled = 0;
|
||||
|
||||
default:
|
||||
|
@ -598,6 +597,9 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
switch (unwrap)
|
||||
{
|
||||
case CLOSED:
|
||||
Throwable failure = _failure;
|
||||
if (failure != null)
|
||||
rethrow(failure);
|
||||
return filled = -1;
|
||||
|
||||
case BUFFER_UNDERFLOW:
|
||||
|
@ -606,7 +608,14 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
_underflown = true;
|
||||
if (netFilled < 0 && _sslEngine.getUseClientMode())
|
||||
{
|
||||
closeInbound();
|
||||
Throwable closeFailure = closeInbound();
|
||||
if (_flushState == FlushState.WAIT_FOR_FILL)
|
||||
{
|
||||
Throwable handshakeFailure = new SSLHandshakeException("Abruptly closed by peer");
|
||||
if (closeFailure != null)
|
||||
handshakeFailure.initCause(closeFailure);
|
||||
throw handshakeFailure;
|
||||
}
|
||||
return filled = -1;
|
||||
}
|
||||
return filled = netFilled;
|
||||
|
@ -639,15 +648,14 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
handshakeFailed(x);
|
||||
|
||||
Throwable failure = handleException(x, "fill");
|
||||
handshakeFailed(failure);
|
||||
if (_flushState == FlushState.WAIT_FOR_FILL)
|
||||
{
|
||||
_flushState = FlushState.IDLE;
|
||||
getExecutor().execute(() -> _decryptedEndPoint.getWriteFlusher().onFail(x));
|
||||
getExecutor().execute(() -> _decryptedEndPoint.getWriteFlusher().onFail(failure));
|
||||
}
|
||||
|
||||
throw x;
|
||||
throw failure;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -676,10 +684,10 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(SslConnection.this.toString(), x);
|
||||
close(x);
|
||||
throw x;
|
||||
rethrow(x);
|
||||
// Never reached.
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -694,15 +702,18 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
synchronized (_decryptedEndPoint)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug(">needFillInterest uf={} {}", _underflown, SslConnection.this);
|
||||
LOG.debug("ei={} di={}", BufferUtil.toDetailString(_encryptedInput), BufferUtil.toDetailString(_decryptedInput));
|
||||
}
|
||||
LOG.debug(">needFillInterest s={}/{} uf={} ei={} di={} {}",
|
||||
_flushState,
|
||||
_fillState,
|
||||
_underflown,
|
||||
BufferUtil.toDetailString(_encryptedInput),
|
||||
BufferUtil.toDetailString(_decryptedInput),
|
||||
SslConnection.this);
|
||||
|
||||
if (_fillState != FillState.IDLE)
|
||||
return;
|
||||
|
||||
// Fillable if we have decrypted Input OR encrypted input that has not yet been underflown.
|
||||
// Fillable if we have decrypted input OR enough encrypted input.
|
||||
fillable = BufferUtil.hasContent(_decryptedInput) || (BufferUtil.hasContent(_encryptedInput) && !_underflown);
|
||||
|
||||
HandshakeStatus status = _sslEngine.getHandshakeStatus();
|
||||
|
@ -799,23 +810,25 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
}
|
||||
|
||||
private void closeInbound() throws SSLException
|
||||
private Throwable closeInbound() throws SSLException
|
||||
{
|
||||
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
|
||||
try
|
||||
{
|
||||
_sslEngine.closeInbound();
|
||||
return null;
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING && !isAllowMissingCloseMessage())
|
||||
throw x;
|
||||
else
|
||||
LOG.ignore(x);
|
||||
LOG.ignore(x);
|
||||
return x;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -966,8 +979,9 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
handshakeFailed(x);
|
||||
throw x;
|
||||
Throwable failure = handleException(x, "flush");
|
||||
handshakeFailed(failure);
|
||||
throw failure;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -979,10 +993,10 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(SslConnection.this.toString(), x);
|
||||
close(x);
|
||||
throw x;
|
||||
rethrow(x);
|
||||
// Never reached.
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1092,7 +1106,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
boolean ishut = endp.isInputShutdown();
|
||||
boolean oshut = endp.isOutputShutdown();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("shutdownOutput: {} oshut={}, ishut={} {}", SslConnection.this, oshut, ishut);
|
||||
LOG.debug("shutdownOutput: {} oshut={}, ishut={}", SslConnection.this, oshut, ishut);
|
||||
|
||||
closeOutbound();
|
||||
|
||||
|
@ -1110,15 +1124,11 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
{
|
||||
if (!flush(BufferUtil.EMPTY_BUFFER) && !close)
|
||||
{
|
||||
Thread.yield();
|
||||
// if we still can't flush, but we are not closing the endpoint,
|
||||
// If we still can't flush, but we are not closing the endpoint,
|
||||
// let's just flush the encrypted output in the background.
|
||||
// and continue as if we are closed. The assumption here is that
|
||||
// the encrypted buffer will contain the entire close handshake
|
||||
// and that a call to flush(EMPTY_BUFFER) is not needed.
|
||||
endp.write(Callback.from(() ->
|
||||
{
|
||||
}, t -> endp.close()), _encryptedOutput);
|
||||
ByteBuffer write = _encryptedOutput;
|
||||
if (BufferUtil.hasContent(write))
|
||||
endp.write(Callback.from(Callback.NOOP::succeeded, t -> endp.close()), write);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1284,6 +1294,37 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
return TLS_1_3.equals(protocol);
|
||||
}
|
||||
|
||||
private Throwable handleException(Throwable x, String context)
|
||||
{
|
||||
synchronized (_decryptedEndPoint)
|
||||
{
|
||||
if (_failure == null)
|
||||
{
|
||||
_failure = x;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(this + " stored " + context + " exception", x);
|
||||
}
|
||||
else if (x != _failure)
|
||||
{
|
||||
_failure.addSuppressed(x);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(this + " suppressed " + context + " exception", x);
|
||||
}
|
||||
return _failure;
|
||||
}
|
||||
}
|
||||
|
||||
private void rethrow(Throwable x) throws IOException
|
||||
{
|
||||
if (x instanceof RuntimeException)
|
||||
throw (RuntimeException)x;
|
||||
if (x instanceof Error)
|
||||
throw (Error)x;
|
||||
if (x instanceof IOException)
|
||||
throw (IOException)x;
|
||||
throw new IOException(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=INFO
|
||||
#org.eclipse.jetty.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.io.AbstractConnection.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.io.ManagedSelector.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.io.ssl.SslConnection.LEVEL=DEBUG
|
||||
|
|
Loading…
Reference in New Issue