Remove `@Disabled` from more `jetty-core/jetty-server` tests (#9162)

* Remove @Disabled from ConnectorTimeoutTests
* Remove @Disabled from SlowClientsTest
* Remove @Disabled from SslConnectionFactoryTest
* Remove @Disabled from DetectorConnectionTest
* Disabling quiche from checkstyle
* Removing ConnectorTimeoutTest BlockingTimeout tests
  + The concept of HttpConfiguration.blockingTimeout
     has been removed, these tests are no longer relevant
This commit is contained in:
Joakim Erdfelt 2023-01-19 10:31:51 -06:00 committed by GitHub
parent a37b8523e5
commit fc762aea7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 419 additions and 666 deletions

View File

@ -20,6 +20,12 @@
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- Excludes all quiche files -->
<!-- See https://checkstyle.org/config_filefilters.html -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="[/\\]org[/\\]eclipse[/\\]jetty[/\\]quic[/\\]quiche[/\\]"/>
</module>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="FileTabCharacter">

View File

@ -13,10 +13,8 @@
package org.eclipse.jetty.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
@ -27,20 +25,17 @@ import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLHandshakeException;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.ByteBufferAccumulator;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.handler.EchoHandler;
import org.eclipse.jetty.server.internal.HttpChannelState;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.NanoTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -48,12 +43,9 @@ import org.slf4j.LoggerFactory;
import static java.time.Duration.ofSeconds;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
@ -101,7 +93,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"GET / HTTP/1.0\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: keep-alive\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.flush();
IO.toString(is);
@ -132,13 +124,13 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
assertTimeoutPreemptively(ofSeconds(10), () ->
{
String content = "Wibble";
byte[] contentB = content.getBytes("utf-8");
byte[] contentB = content.getBytes(StandardCharsets.UTF_8);
os.write((
"POST /echo HTTP/1.1\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"content-type: text/plain; charset=utf-8\r\n" +
"content-length: " + contentB.length + "\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.write(contentB);
os.flush();
@ -185,7 +177,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"GET / HTTP/1.0\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: close\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.flush();
// Get the server side endpoint
@ -240,14 +232,14 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
InputStream is = client.getInputStream();
String content = "Wibble";
byte[] contentB = content.getBytes("utf-8");
byte[] contentB = content.getBytes(StandardCharsets.UTF_8);
os.write((
"POST /echo HTTP/1.1\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"content-type: text/plain; charset=utf-8\r\n" +
"content-length: " + contentB.length + "\r\n" +
"connection: close\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.write(contentB);
os.flush();
@ -273,212 +265,6 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
assertFalse(((Channel)transport).isOpen());
}
@Test
@Tag("Unstable")
@Disabled // TODO make more stable
public void testNoBlockingTimeoutRead() throws Exception
{
startServer(new EchoHandler());
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
InputStream is = client.getInputStream();
assertFalse(client.isClosed());
long start = NanoTime.now();
OutputStream os = client.getOutputStream();
os.write(("GET / HTTP/1.1\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Content-Type: text/plain\r\n" +
"Connection: close\r\n" +
"\r\n" +
"5\r\n" +
"LMNOP\r\n")
.getBytes("utf-8"));
os.flush();
try
{
Thread.sleep(250);
os.write("1".getBytes("utf-8"));
os.flush();
Thread.sleep(250);
os.write("0".getBytes("utf-8"));
os.flush();
Thread.sleep(250);
os.write("\r".getBytes("utf-8"));
os.flush();
Thread.sleep(250);
os.write("\n".getBytes("utf-8"));
os.flush();
Thread.sleep(250);
os.write("0123456789ABCDEF\r\n".getBytes("utf-8"));
os.write("0\r\n".getBytes("utf-8"));
os.write("\r\n".getBytes("utf-8"));
os.flush();
}
catch (Exception e)
{
e.printStackTrace();
}
long duration = NanoTime.millisSince(start);
assertThat(duration, greaterThan(500L));
assertTimeoutPreemptively(ofSeconds(10), () ->
{
// read the response
String response = IO.toString(is);
assertThat(response, startsWith("HTTP/1.1 200 OK"));
assertThat(response, containsString("LMNOP0123456789ABCDEF"));
});
}
@Test
@Tag("Unstable")
@Disabled // TODO make more stable
public void testBlockingTimeoutRead() throws Exception
{
startServer(new EchoHandler());
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
InputStream is = client.getInputStream();
assertFalse(client.isClosed());
OutputStream os = client.getOutputStream();
long start = NanoTime.now();
os.write(("GET / HTTP/1.1\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Content-Type: text/plain\r\n" +
"Connection: close\r\n" +
"\r\n" +
"5\r\n" +
"LMNOP\r\n")
.getBytes("utf-8"));
os.flush();
try (StacklessLogging stackless = new StacklessLogging(HttpChannelState.class))
{
Thread.sleep(300);
os.write("1".getBytes("utf-8"));
os.flush();
Thread.sleep(300);
os.write("0".getBytes("utf-8"));
os.flush();
Thread.sleep(300);
os.write("\r".getBytes("utf-8"));
os.flush();
Thread.sleep(300);
os.write("\n".getBytes("utf-8"));
os.flush();
Thread.sleep(300);
os.write("0123456789ABCDEF\r\n".getBytes("utf-8"));
os.write("0\r\n".getBytes("utf-8"));
os.write("\r\n".getBytes("utf-8"));
os.flush();
}
long duration = NanoTime.millisSince(start);
assertThat(duration, greaterThan(500L));
// read the response
String response = IO.toString(is);
assertThat(response, startsWith("HTTP/1.1 500 "));
assertThat(response, containsString("InterruptedIOException"));
}
@Test
@Tag("Unstable")
@Disabled // TODO make more stable
public void testNoBlockingTimeoutWrite() throws Exception
{
startServer(new HugeResponseHandler());
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
assertFalse(client.isClosed());
OutputStream os = client.getOutputStream();
BufferedReader is = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.ISO_8859_1), 2048);
os.write((
"GET / HTTP/1.0\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: keep-alive\r\n" +
"Connection: close\r\n" +
"\r\n").getBytes("utf-8"));
os.flush();
// read the header
String line = is.readLine();
assertThat(line, startsWith("HTTP/1.1 200 OK"));
while (line.length() != 0)
{
line = is.readLine();
}
for (int i = 0; i < (128 * 1024); i++)
{
if (i % 1028 == 0)
{
Thread.sleep(20);
}
line = is.readLine();
assertThat(line, notNullValue());
assertEquals(1022, line.length());
}
}
@Test
@Tag("Unstable")
@Disabled // TODO make more stable
public void testBlockingTimeoutWrite() throws Exception
{
startServer(new HugeResponseHandler());
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
assertFalse(client.isClosed());
OutputStream os = client.getOutputStream();
BufferedReader is = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.ISO_8859_1), 2048);
os.write((
"GET / HTTP/1.0\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: keep-alive\r\n" +
"Connection: close\r\n" +
"\r\n").getBytes("utf-8"));
os.flush();
// read the header
String line = is.readLine();
assertThat(line, startsWith("HTTP/1.1 200 OK"));
while (line.length() != 0)
{
line = is.readLine();
}
long start = NanoTime.now();
try (StacklessLogging stackless = new StacklessLogging(HttpChannelState.class, AbstractConnection.class))
{
for (int i = 0; i < (128 * 1024); i++)
{
if (i % 1028 == 0)
{
Thread.sleep(20);
}
line = is.readLine();
if (line == null)
break;
}
}
assertThat(NanoTime.millisSince(start), lessThan(20L * 128L));
}
@Test
public void testMaxIdleNoRequest() throws Exception
{
@ -490,7 +276,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
OutputStream os = client.getOutputStream();
long start = NanoTime.now();
os.write("GET ".getBytes("utf-8"));
os.write("GET ".getBytes(StandardCharsets.UTF_8));
os.flush();
Thread.sleep(sleepTime);
@ -559,7 +345,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"Content-Length: 20\r\n" +
"Content-Type: text/plain\r\n" +
"Connection: close\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.flush();
assertTimeoutPreemptively(ofSeconds(10), () ->
@ -583,41 +369,51 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
@Test
public void testMaxIdleDispatch() throws Exception
{
startServer(new EchoHandler());
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
InputStream is = client.getInputStream();
assertFalse(client.isClosed());
startServer(new EchoWholeHandler());
OutputStream os = client.getOutputStream();
long start = NanoTime.now();
os.write((
"GET / HTTP/1.1\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: keep-alive\r\n" +
"Content-Length: 20\r\n" +
"Content-Type: text/plain\r\n" +
"Connection: close\r\n" +
"\r\n" +
"1234567890").getBytes("utf-8"));
os.flush();
assertTimeoutPreemptively(ofSeconds(10), () ->
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
try
client.setSoTimeout(10000);
try (InputStream is = client.getInputStream();
OutputStream os = client.getOutputStream())
{
String response = IO.toString(is);
assertThat(response, containsString("500"));
assertEquals(-1, is.read());
assertFalse(client.isClosed());
long start = NanoTime.now();
byte[] requestBody = "1234567890".getBytes(StandardCharsets.UTF_8);
// We want a situation where the request says it has a body,
// but the request hasn't sent all of it.
int requestBodyLength = requestBody.length * 2;
String rawRequest = ("""
GET / HTTP/1.1\r
host: localhost:%d\r
connection: keep-alive\r
Content-Length: %d\r
Content-Type: text/plain\r
Connection: close\r
\r
""").formatted(_serverURI.getPort(), requestBodyLength);
os.write(rawRequest.getBytes(StandardCharsets.UTF_8));
os.write(requestBody);
os.flush();
assertTimeoutPreemptively(ofSeconds(10), () ->
{
// We expect a 500 response to occur due to the idle timeout triggering.
// See: ServerConnector.setIdleTimeout(long ms);
String response = IO.toString(is);
assertThat(response, containsString("500"));
assertEquals(-1, is.read());
});
long duration = NanoTime.millisSince(start);
assertThat(duration + 100, greaterThanOrEqualTo(MAX_IDLE_TIME));
assertThat(duration - 100, lessThan(maximumTestRuntime));
}
catch (Exception e)
{
e.printStackTrace();
}
});
long duration = NanoTime.millisSince(start);
assertThat(duration + 100, greaterThanOrEqualTo(MAX_IDLE_TIME));
assertThat(duration - 100, lessThan(maximumTestRuntime));
}
}
@Test
@ -633,7 +429,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
InputStream is = client.getInputStream();
String content = "Wibble\r\n";
byte[] contentB = content.getBytes("utf-8");
byte[] contentB = content.getBytes(StandardCharsets.UTF_8);
os.write((
"GET / HTTP/1.0\r\n" +
"host: localhost:" + _serverURI.getPort() + "\r\n" +
@ -641,7 +437,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"Content-Length: " + (contentB.length * 20) + "\r\n" +
"Content-Type: text/plain\r\n" +
"Connection: close\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.flush();
assertTimeoutPreemptively(ofSeconds(10), () ->
@ -680,7 +476,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: keep-alive\r\n" +
"Connection: close\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.flush();
assertTimeoutPreemptively(ofSeconds(10), () ->
@ -712,7 +508,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"host: localhost:" + _serverURI.getPort() + "\r\n" +
"connection: keep-alive\r\n" +
"Connection: close\r\n" +
"\r\n").getBytes("utf-8"));
"\r\n").getBytes(StandardCharsets.UTF_8));
os.flush();
assertTimeoutPreemptively(ofSeconds(10), () ->
@ -750,17 +546,26 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
protected static class HugeResponseHandler extends Handler.Abstract
{
private final int iterations;
public HugeResponseHandler(int iterations)
{
this.iterations = iterations;
}
@Override
public boolean process(Request request, Response response, Callback callback) throws Exception
{
response.setStatus(200);
byte[] buffer = new byte[128 * 1024 * 1024];
// Create a big single buffer
byte[] buffer = new byte[iterations * 1024 * 1024];
Arrays.fill(buffer, (byte)'x');
for (int i = 0; i < 128 * 1024; i++)
// Toss in an LF after every iteration
for (int i = 0; i < iterations * 1024; i++)
{
buffer[i * 1024 + 1022] = '\r';
buffer[i * 1024 + 1023] = '\n';
}
// Write it as a single buffer
response.write(true, ByteBuffer.wrap(buffer), callback);
return true;
}
@ -784,4 +589,73 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
return true;
}
}
/**
* A handler that will echo the request body to the response body, but only
* once the entire body content has been received.
*/
public static class EchoWholeHandler extends Handler.Abstract
{
@Override
public boolean process(Request request, Response response, Callback callback) throws Exception
{
long expectedContentLength = request.getHeaders().getLongField(HttpHeader.CONTENT_LENGTH);
if (expectedContentLength <= 0)
{
callback.succeeded();
return true;
}
request.demand(new WholeProcess(request, response, callback));
return true;
}
/**
* Accumulate the Request body until it's entirely received,
* then write the body back to the response body.
*/
private static class WholeProcess implements Runnable
{
Request request;
Response response;
Callback callback;
ByteBufferAccumulator bufferAccumulator;
public WholeProcess(Request request, Response response, Callback callback)
{
this.request = request;
this.response = response;
this.callback = callback;
this.bufferAccumulator = new ByteBufferAccumulator();
}
@Override
public void run()
{
while (true)
{
Content.Chunk chunk = request.read();
if (chunk == null)
{
request.demand(this);
return;
}
if (chunk instanceof Content.Chunk.Error error)
{
callback.failed(error.getCause());
return;
}
// copy buffer
bufferAccumulator.copyBuffer(chunk.getByteBuffer().slice());
chunk.release();
if (chunk.isLast())
{
// write accumulated buffers
response.write(true, bufferAccumulator.toByteBuffer(), callback);
return;
}
}
}
}
}
}

View File

@ -21,6 +21,7 @@ import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@ -32,14 +33,12 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.handler.DumpHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -91,9 +90,9 @@ public class DetectorConnectionTest
private String getResponseOverSsl(String request) throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.start();
@ -140,6 +139,7 @@ public class DetectorConnectionTest
socket.getOutputStream().write("OX".getBytes(StandardCharsets.US_ASCII));
socket.getOutputStream().close();
//noinspection ResultOfMethodCallIgnored
assertThrows(SocketException.class, () -> socket.getInputStream().read());
}
}
@ -160,6 +160,7 @@ public class DetectorConnectionTest
socket.getOutputStream().write(" ".getBytes(StandardCharsets.US_ASCII));
socket.getOutputStream().close();
//noinspection ResultOfMethodCallIgnored
assertThrows(SocketException.class, () -> socket.getInputStream().read());
}
}
@ -175,11 +176,12 @@ public class DetectorConnectionTest
try (Socket socket = new Socket(_server.getURI().getHost(), _server.getURI().getPort()))
{
socket.getOutputStream().write(TypeUtil.fromHexString("0D0A0D0A000D0A515549540A")); // proxy V2 Preamble
socket.getOutputStream().write(StringUtil.fromHexString("0D0A0D0A000D0A515549540A")); // proxy V2 Preamble
Thread.sleep(100); // make sure the onFillable callback gets called
socket.getOutputStream().write(TypeUtil.fromHexString("21")); // V2, PROXY
socket.getOutputStream().write(StringUtil.fromHexString("21")); // V2, PROXY
socket.getOutputStream().close();
//noinspection ResultOfMethodCallIgnored
assertThrows(SocketException.class, () -> socket.getInputStream().read());
}
}
@ -195,7 +197,7 @@ public class DetectorConnectionTest
try (Socket socket = new Socket(_server.getURI().getHost(), _server.getURI().getPort()))
{
socket.getOutputStream().write(TypeUtil.fromHexString(
socket.getOutputStream().write(StringUtil.fromHexString(
// proxy V2 Preamble
"0D0A0D0A000D0A515549540A" +
// V2, PROXY
@ -207,23 +209,23 @@ public class DetectorConnectionTest
"000C"
));
Thread.sleep(100); // make sure the onFillable callback gets called
socket.getOutputStream().write(TypeUtil.fromHexString(
socket.getOutputStream().write(StringUtil.fromHexString(
// uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port;
"C0A80001" // 8080
));
socket.getOutputStream().close();
//noinspection ResultOfMethodCallIgnored
assertThrows(SocketException.class, () -> socket.getInputStream().read());
}
}
@Test
@Disabled // TODO
public void testDetectingSslProxyToHttpNoSslWithProxy() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -233,18 +235,18 @@ public class DetectorConnectionTest
start(detector, http);
String request = "PROXY TCP 1.2.3.4 5.6.7.8 111 222\r\n" +
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
PROXY TCP 1.2.3.4 5.6.7.8 111 222\r
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(request);
assertThat(response, Matchers.containsString("HTTP/1.1 200"));
assertThat(response, Matchers.containsString("pathInContext=/path"));
assertThat(response, Matchers.containsString("servername=server"));
assertThat(response, Matchers.containsString("serverport=80"));
assertThat(response, Matchers.containsString("localname=5.6.7.8"));
assertThat(response, Matchers.containsString("local=5.6.7.8:222"));
assertThat(response, Matchers.containsString("remote=1.2.3.4:111"));
}
@ -252,9 +254,9 @@ public class DetectorConnectionTest
@Test
public void testDetectingSslProxyToHttpWithSslNoProxy() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -264,10 +266,12 @@ public class DetectorConnectionTest
start(detector, http);
String request = "GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponseOverSsl(request);
assertThat(response, Matchers.containsString("HTTP/1.1 200"));
@ -276,9 +280,9 @@ public class DetectorConnectionTest
@Test
public void testDetectingSslProxyToHttpWithSslWithProxy() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -288,11 +292,13 @@ public class DetectorConnectionTest
start(detector, http);
String request = "PROXY TCP 1.2.3.4 5.6.7.8 111 222\r\n" +
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
PROXY TCP 1.2.3.4 5.6.7.8 111 222\r
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponseOverSsl(request);
// SSL matched, so the upgrade was made to HTTP which does not understand the proxy request
@ -302,9 +308,9 @@ public class DetectorConnectionTest
@Test
public void testDetectionUnsuccessfulUpgradesToNextProtocol() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -314,10 +320,12 @@ public class DetectorConnectionTest
start(detector, http);
String request = "GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(request);
assertThat(response, Matchers.containsString("HTTP/1.1 200"));
@ -326,9 +334,9 @@ public class DetectorConnectionTest
@Test
public void testDetectorToNextDetector() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -339,11 +347,13 @@ public class DetectorConnectionTest
start(sslDetector, proxyDetector, http);
String request = "PROXY TCP 1.2.3.4 5.6.7.8 111 222\r\n" +
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
PROXY TCP 1.2.3.4 5.6.7.8 111 222\r
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponseOverSsl(request);
// SSL matched, so the upgrade was made to proxy which itself upgraded to HTTP
@ -377,10 +387,12 @@ public class DetectorConnectionTest
start(detector, http);
String request = "GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(request);
assertEquals("No upgrade for you", response);
@ -390,9 +402,9 @@ public class DetectorConnectionTest
@Test
public void testDetectorWithProxyThatHasNoNextProto() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -402,11 +414,13 @@ public class DetectorConnectionTest
start(detector, http);
String request = "PROXY TCP 1.2.3.4 5.6.7.8 111 222\r\n" +
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
PROXY TCP 1.2.3.4 5.6.7.8 111 222\r
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(request);
// ProxyConnectionFactory has no next protocol -> it cannot upgrade
@ -416,9 +430,9 @@ public class DetectorConnectionTest
@Test
public void testOptionalSsl() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
HttpConnectionFactory http = new HttpConnectionFactory();
@ -427,11 +441,12 @@ public class DetectorConnectionTest
start(detector, http);
String request =
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String clearTextResponse = getResponse(request);
String sslResponse = getResponseOverSsl(request);
@ -443,9 +458,9 @@ public class DetectorConnectionTest
@Test
public void testDetectorThatHasNoConfiguredNextProto() throws Exception
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString());
@ -453,11 +468,12 @@ public class DetectorConnectionTest
start(detector);
String request =
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(request);
assertThat(response, Matchers.nullValue());
@ -489,11 +505,11 @@ public class DetectorConnectionTest
"1F90"; // 8080
String httpReq = """
GET /path HTTP/1.1
Host: server:80
Connection: close
""";
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
try (StacklessLogging ignore = new StacklessLogging(DetectorConnectionFactory.class))
{
String response = getResponse(StringUtil.fromHexString(proxyReq), httpReq.getBytes(StandardCharsets.US_ASCII));
@ -558,12 +574,13 @@ public class DetectorConnectionTest
"3039" + // 12345
"1F90"; // 8080
String httpReq =
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String response = getResponse(TypeUtil.fromHexString(proxyReq), httpReq.getBytes(StandardCharsets.US_ASCII));
String httpReq = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(StringUtil.fromHexString(proxyReq), httpReq.getBytes(StandardCharsets.US_ASCII));
assertThat(response, Matchers.nullValue());
}
@ -604,11 +621,12 @@ public class DetectorConnectionTest
start(detector, noUpgradeTo);
String request =
"GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String request = """
GET /path HTTP/1.1\r
Host: server:80\r
Connection: close\r
\r
""";
String response = getResponse(request);
assertThat(response, Matchers.nullValue());
@ -617,9 +635,9 @@ public class DetectorConnectionTest
@Test
public void testGeneratedProtocolNames()
{
String keystore = MavenTestingUtils.getTestResourceFile("keystore.p12").getAbsolutePath();
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore);
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
ProxyConnectionFactory proxy = new ProxyConnectionFactory(HttpVersion.HTTP_1_1.asString());

View File

@ -14,13 +14,11 @@
package org.eclipse.jetty.server;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static java.time.Duration.ofSeconds;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
@Disabled // TODO
public class ServerConnectorTimeoutTest extends ConnectorTimeoutTest
{
@BeforeEach
@ -28,11 +26,11 @@ public class ServerConnectorTimeoutTest extends ConnectorTimeoutTest
{
ServerConnector connector = new ServerConnector(_server, 1, 1);
connector.setIdleTimeout(MAX_IDLE_TIME);
_server.addConnector(connector);
initServer(connector);
}
@Test
public void testStartStopStart() throws Exception
public void testStartStopStart()
{
assertTimeoutPreemptively(ofSeconds(10), () ->
{
@ -40,165 +38,4 @@ public class ServerConnectorTimeoutTest extends ConnectorTimeoutTest
_server.start();
});
}
/* TODO
@Test
public void testIdleTimeoutAfterSuspend() throws Exception
{
_server.stop();
SuspendHandler handler = new SuspendHandler();
SessionHandler session = new SessionHandler();
session.setHandler(handler);
_server.setHandler(session);
_server.start();
handler.setSuspendFor(100);
handler.setResumeAfter(25);
assertTimeoutPreemptively(ofSeconds(10), () ->
{
String process = process(null).toUpperCase(Locale.ENGLISH);
assertThat(process, containsString("RESUMED"));
});
}
@Test
public void testIdleTimeoutAfterTimeout() throws Exception
{
SuspendHandler handler = new SuspendHandler();
_server.stop();
SessionHandler session = new SessionHandler();
session.setHandler(handler);
_server.setHandler(session);
_server.start();
handler.setSuspendFor(50);
assertTimeoutPreemptively(ofSeconds(10), () ->
{
String process = process(null).toUpperCase(Locale.ENGLISH);
assertThat(process, containsString("TIMEOUT"));
});
}
@Test
public void testIdleTimeoutAfterComplete() throws Exception
{
SuspendHandler handler = new SuspendHandler();
_server.stop();
SessionHandler session = new SessionHandler();
session.setHandler(handler);
_server.setHandler(session);
_server.start();
handler.setSuspendFor(100);
handler.setCompleteAfter(25);
assertTimeoutPreemptively(ofSeconds(10), () ->
{
String process = process(null).toUpperCase(Locale.ENGLISH);
assertThat(process, containsString("COMPLETED"));
});
}
private String process(String content) throws IOException, InterruptedException
{
synchronized (this)
{
String request = "GET / HTTP/1.1\r\n" + "Host: localhost\r\n";
if (content == null)
request += "\r\n";
else
request += "Content-Length: " + content.length() + "\r\n" + "\r\n" + content;
return getResponse(request);
}
}
private String getResponse(String request) throws IOException, InterruptedException
{
try (Socket socket = new Socket((String)null, _connector.getLocalPort()))
{
socket.setSoTimeout((int)(10 * MAX_IDLE_TIME));
socket.getOutputStream().write(request.getBytes(StandardCharsets.UTF_8));
InputStream inputStream = socket.getInputStream();
long start = NanoTime.now();
String response = IO.toString(inputStream);
assertThat(NanoTime.millisSince(start), greaterThanOrEqualTo(MAX_IDLE_TIME - 100L));
return response;
}
}
@Test
public void testHttpWriteIdleTimeout() throws Exception
{
_httpConfiguration.setIdleTimeout(500);
configureServer(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
IO.copy(request.getInputStream(), response.getOutputStream());
}
});
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
assertFalse(client.isClosed());
final OutputStream os = client.getOutputStream();
final InputStream is = client.getInputStream();
final StringBuilder response = new StringBuilder();
CompletableFuture<Void> responseFuture = CompletableFuture.runAsync(() ->
{
try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8))
{
int c;
while ((c = reader.read()) != -1)
{
response.append((char)c);
}
}
catch (IOException e)
{
// Valid path (as connection is forcibly closed)
// t.printStackTrace(System.err);
}
});
CompletableFuture<Void> requestFuture = CompletableFuture.runAsync(() ->
{
try
{
os.write((
"POST /echo HTTP/1.0\r\n" +
"host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"content-type: text/plain; charset=utf-8\r\n" +
"content-length: 20\r\n" +
"\r\n").getBytes("utf-8"));
os.flush();
os.write("123456789\n".getBytes("utf-8"));
os.flush();
TimeUnit.SECONDS.sleep(1);
os.write("=========\n".getBytes("utf-8"));
os.flush();
}
catch (InterruptedException | IOException e)
{
// Valid path, as write of second half of content can fail
// e.printStackTrace(System.err);
}
});
try (StacklessLogging ignore = new StacklessLogging(HttpChannel.class))
{
requestFuture.get(2, TimeUnit.SECONDS);
responseFuture.get(3, TimeUnit.SECONDS);
assertThat(response.toString(), containsString(" 500 "));
assertThat(response.toString(), not(containsString("=========")));
}
}
*/
}

View File

@ -13,43 +13,37 @@
package org.eclipse.jetty.server.ssl;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.eclipse.jetty.server.ConnectorTimeoutTest;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@Disabled // TODO
public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
public class ServerConnectorSslTimeoutTest extends ConnectorTimeoutTest
{
static SSLContext __sslContext;
@Override
protected Socket newSocket(String host, int port) throws Exception
{
return __sslContext.getSocketFactory().createSocket(host, port);
}
@BeforeEach
public void init() throws Exception
{
String keystorePath = System.getProperty("basedir", ".") + "/src/test/resources/keystore.p12";
Path keystorePath = MavenPaths.findTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystorePath);
sslContextFactory.setKeyStorePath(keystorePath.toString());
sslContextFactory.setKeyStorePassword("storepwd");
ServerConnector connector = new ServerConnector(_server, 1, 1, sslContextFactory);
connector.setIdleTimeout(MAX_IDLE_TIME); //250 msec max idle
connector.setIdleTimeout(MAX_IDLE_TIME);
_server.addConnector(connector);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream stream = new FileInputStream(keystorePath))
try (InputStream stream = Files.newInputStream(keystorePath))
{
keystore.load(stream, "storepwd".toCharArray());
}
@ -58,4 +52,10 @@ public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
__sslContext = SSLContext.getInstance("SSL");
__sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
}
@Override
protected Socket newSocket(String host, int port) throws Exception
{
return __sslContext.getSocketFactory().createSocket(host, port);
}
}

View File

@ -13,144 +13,150 @@
package org.eclipse.jetty.server.ssl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.component.LifeCycle;
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.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.time.Duration.ofSeconds;
@Tag("Unstable")
@Disabled
public class SlowClientsTest
{
private static final Logger LOG = LoggerFactory.getLogger(SlowClientsTest.class);
private Server server;
private SslContextFactory.Server sslContextFactory;
@BeforeEach
public void initServer() throws Exception
{
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
server = new Server();
ServerConnector connector = new ServerConnector(server, 1, 1, sslContextFactory);
connector.setPort(0);
server.addConnector(connector);
}
@AfterEach
public void stopServer()
{
LifeCycle.stop(server);
}
public void startServer(Handler handler) throws Exception
{
server.setHandler(handler);
server.start();
}
public Socket newSocketToServer() throws IOException
{
URI serverURI = server.getURI();
SSLContext sslContext = sslContextFactory.getSslContext();
return sslContext.getSocketFactory().createSocket(serverURI.getHost(), serverURI.getPort());
}
@Test
public void testSlowClientsWithSmallThreadPool() throws Exception
{
File keystore = MavenTestingUtils.getTestResourceFile("keystore.p12");
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore.getAbsolutePath());
sslContextFactory.setKeyStorePassword("storepwd");
final int maxThreads = 6;
final int contentLength = 8 * 1024 * 1024; // 8MB
int maxThreads = 6;
int contentLength = 8 * 1024 * 1024;
QueuedThreadPool serverThreads = new QueuedThreadPool(maxThreads);
serverThreads.setDetailedDump(true);
Server server = new Server(serverThreads);
try
((QueuedThreadPool)server.getThreadPool()).setMaxThreads(maxThreads);
startServer(new Handler.Abstract()
{
ServerConnector connector = new ServerConnector(server, 1, 1, sslContextFactory);
connector.setPort(8888);
server.addConnector(connector);
server.setHandler(new Handler.Abstract.NonBlocking()
@Override
public boolean process(Request request, Response response, Callback callback)
{
@Override
public boolean process(Request request, Response response, Callback callback)
{
LOG.info("SERVING {}", request);
// Write some big content.
response.write(true, BufferUtil.toBuffer(new byte[contentLength]), new Callback()
{
@Override
public void succeeded()
{
callback.succeeded();
LOG.info("SERVED {}", request);
}
response.write(true, BufferUtil.toBuffer(contentLength), callback);
return true;
}
});
@Override
public void failed(Throwable x)
{
callback.failed(x);
}
}
);
return true;
}
});
server.start();
SSLContext sslContext = sslContextFactory.getSslContext();
Assertions.assertTimeoutPreemptively(ofSeconds(10), () ->
Assertions.assertTimeoutPreemptively(ofSeconds(10), () ->
{
// Twice as many clients as threads in thread pool.
CompletableFuture<?>[] futures = new CompletableFuture[2 * maxThreads];
ExecutorService executor = Executors.newFixedThreadPool(futures.length);
for (int i = 0; i < futures.length; i++)
{
CompletableFuture<?>[] futures = new CompletableFuture[2 * maxThreads];
ExecutorService executor = Executors.newFixedThreadPool(futures.length);
for (int i = 0; i < futures.length; i++)
int k = i;
futures[i] = CompletableFuture.runAsync(() ->
{
int k = i;
futures[i] = CompletableFuture.runAsync(() ->
try (Socket socket = newSocketToServer())
{
try (SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort()))
{
socket.setSoTimeout(contentLength / 1024);
OutputStream output = socket.getOutputStream();
String target = "/" + k;
String request = "GET " + target + " HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n" +
"\r\n";
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
socket.setSoTimeout(contentLength / 1024);
OutputStream output = socket.getOutputStream();
String target = "/" + k;
String rawRequest = """
GET %s HTTP/1.1\r
Host: localhost\r
Connection: close\r
\r
""".formatted(target);
output.write(rawRequest.getBytes(StandardCharsets.UTF_8));
output.flush();
while (serverThreads.getIdleThreads() > 0)
{
Thread.sleep(50);
}
int delayReadCount = 10;
InputStream input = socket.getInputStream();
while (true)
InputStream input = socket.getInputStream();
while (true)
{
int read = input.read();
if (read < 0)
break;
// simulate a slow client (for a bit).
// we are testing that the server thread pool doesn't misbehave
// in this scenario, where there are more clients active than server threads.
if (delayReadCount > 0)
{
int read = input.read();
if (read < 0)
break;
TimeUnit.MILLISECONDS.sleep(200);
delayReadCount--;
}
LOG.info("FINISHED {}", target);
}
catch (IOException x)
{
throw new UncheckedIOException(x);
}
catch (InterruptedException x)
{
throw new UncheckedIOException(new InterruptedIOException());
}
}, executor);
}
CompletableFuture.allOf(futures).join();
});
}
finally
{
server.stop();
}
LOG.info("FINISHED {}", target);
}
catch (IOException x)
{
throw new UncheckedIOException(x);
}
catch (InterruptedException x)
{
throw new UncheckedIOException(new InterruptedIOException());
}
}, executor);
}
CompletableFuture.allOf(futures).join();
});
}
}

View File

@ -13,11 +13,11 @@
package org.eclipse.jetty.server.ssl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
@ -29,6 +29,8 @@ import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.server.Handler;
@ -40,6 +42,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SocketCustomizationListener;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
@ -47,15 +50,15 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
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;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@Disabled // TODO Fix?
public class SslConnectionFactoryTest
{
private Server _server;
@ -65,11 +68,7 @@ public class SslConnectionFactoryTest
@BeforeEach
public void before() throws Exception
{
String keystorePath = "src/test/resources/keystore.p12";
File keystoreFile = new File(keystorePath);
if (!keystoreFile.exists())
throw new FileNotFoundException(keystoreFile.getAbsolutePath());
Path keystoreFile = MavenPaths.findTestResourceFile("keystore.p12");
_server = new Server();
HttpConfiguration httpConfig = new HttpConfiguration();
@ -78,7 +77,7 @@ public class SslConnectionFactoryTest
httpConfig.setOutputBufferSize(32768);
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
sslContextFactory.setKeyStorePath(keystoreFile.toString());
sslContextFactory.setKeyStorePassword("storepwd");
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString());
@ -116,15 +115,15 @@ public class SslConnectionFactoryTest
@Test
public void testConnect() throws Exception
{
String response = getResponse("127.0.0.1", null);
assertThat(response, Matchers.containsString("host=127.0.0.1"));
HttpTester.Response response = getResponse("127.0.0.1", null);
assertThat(response.getContent(), containsString("host=127.0.0.1"));
}
@Test
public void testSNIConnect() throws Exception
{
String response = getResponse("localhost", "localhost", "localhost");
assertThat(response, Matchers.containsString("host=localhost"));
HttpTester.Response response = getResponse("localhost", "localhost", "localhost");
assertThat(response.getContent(), containsString("host=localhost"));
}
@Test
@ -174,13 +173,13 @@ public class SslConnectionFactoryTest
}
});
String response = getResponse("127.0.0.1", null);
assertThat(response, Matchers.containsString("host=127.0.0.1"));
HttpTester.Response response = getResponse("127.0.0.1", null);
assertThat(response.getContent(), containsString("host=127.0.0.1"));
assertEquals("customize connector class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
assertEquals("customize ssl class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
assertEquals("customize connector class org.eclipse.jetty.server.HttpConnection,true", history.poll());
assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true", history.poll());
assertEquals("customize connector class org.eclipse.jetty.server.internal.HttpConnection,true", history.poll());
assertEquals("customize http class org.eclipse.jetty.server.internal.HttpConnection,true", history.poll());
assertEquals(0, history.size());
}
@ -192,45 +191,58 @@ public class SslConnectionFactoryTest
assertThrows(IllegalStateException.class, () -> _server.start());
}
private String getResponse(String host, String cn) throws Exception
private HttpTester.Response getResponse(String host, String cn) throws Exception
{
String response = getResponse(host, host, cn);
assertThat(response, Matchers.startsWith("HTTP/1.1 200 OK"));
assertThat(response, Matchers.containsString("url=/ctx/path"));
HttpTester.Response response = getResponse(host, host, cn);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
assertThat(response.getContent(), containsString("url=https://%s:%d/ctx/path".formatted(host, _port)));
return response;
}
private String getResponse(String sniHost, String reqHost, String cn) throws Exception
private HttpTester.Response getResponse(String sniHost, String reqHost, String cn) throws Exception
{
SslContextFactory clientContextFactory = new SslContextFactory.Client(true);
clientContextFactory.start();
SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port);
if (cn != null)
try (SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port))
{
SNIHostName serverName = new SNIHostName(sniHost);
List<SNIServerName> serverNames = new ArrayList<>();
serverNames.add(serverName);
if (cn != null)
{
SNIHostName serverName = new SNIHostName(sniHost);
List<SNIServerName> serverNames = new ArrayList<>();
serverNames.add(serverName);
SSLParameters params = sslSocket.getSSLParameters();
params.setServerNames(serverNames);
sslSocket.setSSLParameters(params);
SSLParameters params = sslSocket.getSSLParameters();
params.setServerNames(serverNames);
sslSocket.setSSLParameters(params);
}
sslSocket.startHandshake();
if (cn != null)
{
X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn=" + cn));
}
try (OutputStream os = sslSocket.getOutputStream();
InputStream in = sslSocket.getInputStream())
{
String rawRequest = """
GET /ctx/path HTTP/1.1\r
Host: %s:%d\r
Connection: close\r
\r
""".formatted(reqHost, _port);
os.write(rawRequest.getBytes(StandardCharsets.UTF_8));
String rawResponse = IO.toString(in);
return HttpTester.parseResponse(rawResponse);
}
}
sslSocket.startHandshake();
if (cn != null)
finally
{
X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn=" + cn));
clientContextFactory.stop();
}
sslSocket.getOutputStream().write(("GET /ctx/path HTTP/1.0\r\nHost: " + reqHost + ":" + _port + "\r\n\r\n").getBytes(StandardCharsets.ISO_8859_1));
String response = IO.toString(sslSocket.getInputStream());
sslSocket.close();
clientContextFactory.stop();
return response;
}
}