Merge 'jetty-9.4.x' of github.com:eclipse/jetty.project into jetty-9.4.x

This commit is contained in:
Joakim Erdfelt 2019-12-06 13:24:43 -06:00
commit 2ee079feb1
No known key found for this signature in database
GPG Key ID: 2D0E1FB8FE4B68B4
3 changed files with 110 additions and 11 deletions

View File

@ -30,6 +30,7 @@ import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
@ -195,6 +196,8 @@ public class Socks4Proxy extends ProxyConfiguration.Proxy
try try
{ {
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY); HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, destination.getHost());
context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, destination.getPort());
ClientConnectionFactory connectionFactory = this.connectionFactory; ClientConnectionFactory connectionFactory = this.connectionFactory;
if (destination.isSecure()) if (destination.isSecure())
connectionFactory = destination.newSslClientConnectionFactory(null, connectionFactory); connectionFactory = destination.newSslClientConnectionFactory(null, connectionFactory);

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
@ -25,7 +27,12 @@ import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -44,7 +51,10 @@ public class Socks4ProxyTest
server = ServerSocketChannel.open(); server = ServerSocketChannel.open();
server.bind(new InetSocketAddress("localhost", 0)); server.bind(new InetSocketAddress("localhost", 0));
client = new HttpClient(); QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client");
client = new HttpClient(new SslContextFactory.Client());
client.setExecutor(clientThreads);
client.start(); client.start();
} }
@ -61,7 +71,7 @@ public class Socks4ProxyTest
int proxyPort = server.socket().getLocalPort(); int proxyPort = server.socket().getLocalPort();
client.getProxyConfiguration().getProxies().add(new Socks4Proxy("localhost", proxyPort)); client.getProxyConfiguration().getProxies().add(new Socks4Proxy("localhost", proxyPort));
final CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
byte ip1 = 127; byte ip1 = 127;
byte ip2 = 0; byte ip2 = 0;
@ -111,7 +121,7 @@ public class Socks4ProxyTest
"Content-Length: 0\r\n" + "Content-Length: 0\r\n" +
"Connection: close\r\n" + "Connection: close\r\n" +
"\r\n"; "\r\n";
channel.write(ByteBuffer.wrap(response.getBytes("UTF-8"))); channel.write(ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8)));
assertTrue(latch.await(5, TimeUnit.SECONDS)); assertTrue(latch.await(5, TimeUnit.SECONDS));
} }
@ -123,7 +133,7 @@ public class Socks4ProxyTest
int proxyPort = server.socket().getLocalPort(); int proxyPort = server.socket().getLocalPort();
client.getProxyConfiguration().getProxies().add(new Socks4Proxy("localhost", proxyPort)); client.getProxyConfiguration().getProxies().add(new Socks4Proxy("localhost", proxyPort));
final CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
String serverHost = "127.0.0.13"; // Test expects an IP address. String serverHost = "127.0.0.13"; // Test expects an IP address.
int serverPort = proxyPort + 1; // Any port will do int serverPort = proxyPort + 1; // Any port will do
@ -169,7 +179,92 @@ public class Socks4ProxyTest
"Content-Length: 0\r\n" + "Content-Length: 0\r\n" +
"Connection: close\r\n" + "Connection: close\r\n" +
"\r\n"; "\r\n";
channel.write(ByteBuffer.wrap(response.getBytes("UTF-8"))); channel.write(ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8)));
assertTrue(latch.await(5, TimeUnit.SECONDS));
}
}
@Test
public void testSocks4ProxyWithTLSServer() throws Exception
{
String proxyHost = "localhost";
int proxyPort = server.socket().getLocalPort();
String serverHost = "127.0.0.13"; // Server host different from proxy host.
int serverPort = proxyPort + 1; // Any port will do.
SslContextFactory clientTLS = client.getSslContextFactory();
clientTLS.reload(ssl ->
{
// The client keystore contains the trustedCertEntry for the
// self-signed server certificate, so it acts as a truststore.
ssl.setTrustStorePath("src/test/resources/client_keystore.jks");
ssl.setTrustStorePassword("storepwd");
// Disable TLS hostname verification, but
// enable application hostname verification.
ssl.setEndpointIdentificationAlgorithm(null);
// The hostname must be that of the server, not of the proxy.
ssl.setHostnameVerifier((hostname, session) -> serverHost.equals(hostname));
});
client.getProxyConfiguration().getProxies().add(new Socks4Proxy(proxyHost, proxyPort));
CountDownLatch latch = new CountDownLatch(1);
client.newRequest(serverHost, serverPort)
.scheme(HttpScheme.HTTPS.asString())
.path("/path")
.send(result ->
{
if (result.isSucceeded())
latch.countDown();
else
result.getFailure().printStackTrace();
});
try (SocketChannel channel = server.accept())
{
int socks4MessageLength = 9;
ByteBuffer buffer = ByteBuffer.allocate(socks4MessageLength);
int read = channel.read(buffer);
assertEquals(socks4MessageLength, read);
// Socks4 response.
channel.write(ByteBuffer.wrap(new byte[]{0, 0x5A, 0, 0, 0, 0, 0, 0}));
// Wrap the socket with TLS.
SslContextFactory.Server serverTLS = new SslContextFactory.Server();
serverTLS.setKeyStorePath("src/test/resources/keystore.jks");
serverTLS.setKeyStorePassword("storepwd");
serverTLS.start();
SSLContext sslContext = serverTLS.getSslContext();
SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(channel.socket(), serverHost, serverPort, false);
sslSocket.setUseClientMode(false);
// Read the request.
int crlfs = 0;
InputStream input = sslSocket.getInputStream();
while (true)
{
read = input.read();
if (read < 0)
break;
if (read == '\r' || read == '\n')
++crlfs;
else
crlfs = 0;
if (crlfs == 4)
break;
}
// Send the response.
String response =
"HTTP/1.1 200 OK\r\n" +
"Content-Length: 0\r\n" +
"Connection: close\r\n" +
"\r\n";
OutputStream output = sslSocket.getOutputStream();
output.write(response.getBytes(StandardCharsets.UTF_8));
output.flush();
assertTrue(latch.await(5, TimeUnit.SECONDS)); assertTrue(latch.await(5, TimeUnit.SECONDS));
} }

View File

@ -28,6 +28,7 @@ import javax.servlet.UnavailableException;
import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.QuietException;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context; import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.ErrorHandler;
@ -406,8 +407,6 @@ public class HttpChannelState
*/ */
protected Action unhandle() protected Action unhandle()
{ {
boolean readInterested = false;
synchronized (this) synchronized (this)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -736,8 +735,10 @@ public class HttpChannelState
} }
else else
{ {
LOG.warn(failure.toString()); if (!(failure instanceof QuietException))
LOG.debug(failure); LOG.warn(failure.toString());
if (LOG.isDebugEnabled())
LOG.debug(failure);
} }
} }
@ -1340,7 +1341,7 @@ public class HttpChannelState
* but that a handling thread may need to produce (fill/parse) * but that a handling thread may need to produce (fill/parse)
* it. Typically called by the async read success callback. * it. Typically called by the async read success callback.
* *
* @return <code>true</code> if more content may be available * @return {@code true} if more content may be available
*/ */
public boolean onReadPossible() public boolean onReadPossible()
{ {
@ -1372,7 +1373,7 @@ public class HttpChannelState
* Called to signal that a read has read -1. * Called to signal that a read has read -1.
* Will wake if the read was called while in ASYNC_WAIT state * Will wake if the read was called while in ASYNC_WAIT state
* *
* @return <code>true</code> if woken * @return {@code true} if woken
*/ */
public boolean onReadEof() public boolean onReadEof()
{ {