summaryrefslogtreecommitdiffstats
path: root/jdisc_http_service
diff options
context:
space:
mode:
authorHarald Musum <musum@verizonmedia.com>2020-03-04 17:23:22 +0100
committerGitHub <noreply@github.com>2020-03-04 17:23:22 +0100
commitbd03747a91e9c3d7231273bf412a8db2d8c57f5b (patch)
treefabe73c2d2578fa275c5b9e927bd3fe79b0dcfc0 /jdisc_http_service
parentf73a1ac2acf5dcb685e8f765c6d3c783cd8e7818 (diff)
Revert "Bjorncs/ssl handshake metric"
Diffstat (limited to 'jdisc_http_service')
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java16
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java6
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java83
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java142
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleHttpClient.java74
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java8
6 files changed, 61 insertions, 268 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
index 2796ee2d271..01d6fa02d6e 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
@@ -42,7 +42,7 @@ public class ConnectorFactory {
public ServerConnector createConnector(final Metric metric, final Server server, final ServerSocketChannel ch) {
ServerConnector connector = new JDiscServerConnector(
- connectorConfig, metric, server, ch, createConnectionFactories(metric).toArray(ConnectionFactory[]::new));
+ connectorConfig, metric, server, ch, createConnectionFactories().toArray(ConnectionFactory[]::new));
connector.setPort(connectorConfig.listenPort());
connector.setName(connectorConfig.name());
connector.setAcceptQueueSize(connectorConfig.acceptQueueSize());
@@ -51,14 +51,14 @@ public class ConnectorFactory {
return connector;
}
- private List<ConnectionFactory> createConnectionFactories(Metric metric) {
+ private List<ConnectionFactory> createConnectionFactories() {
HttpConnectionFactory httpConnectionFactory = newHttpConnectionFactory();
if (connectorConfig.healthCheckProxy().enable()) {
return List.of(httpConnectionFactory);
} else if (connectorConfig.ssl().enabled()) {
- return List.of(newSslConnectionFactory(metric), httpConnectionFactory);
+ return List.of(newSslConnectionFactory(), httpConnectionFactory);
} else if (TransportSecurityUtils.isTransportSecurityEnabled()) {
- SslConnectionFactory sslConnectionsFactory = newSslConnectionFactory(metric);
+ SslConnectionFactory sslConnectionsFactory = newSslConnectionFactory();
switch (TransportSecurityUtils.getInsecureMixedMode()) {
case TLS_CLIENT_MIXED_SERVER:
case PLAINTEXT_CLIENT_MIXED_SERVER:
@@ -88,11 +88,9 @@ public class ConnectorFactory {
return new HttpConnectionFactory(httpConfig);
}
- private SslConnectionFactory newSslConnectionFactory(Metric metric) {
- SslContextFactory ctxFactory = sslContextFactoryProvider.getInstance(connectorConfig.name(), connectorConfig.listenPort());
- SslConnectionFactory connectionFactory = new SslConnectionFactory(ctxFactory, HttpVersion.HTTP_1_1.asString());
- connectionFactory.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort()));
- return connectionFactory;
+ private SslConnectionFactory newSslConnectionFactory() {
+ SslContextFactory factory = sslContextFactoryProvider.getInstance(connectorConfig.name(), connectorConfig.listenPort());
+ return new SslConnectionFactory(factory, HttpVersion.HTTP_1_1.asString());
}
private OptionalSslConnectionFactory newOptionalSslConnectionFactory(SslConnectionFactory sslConnectionsFactory) {
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
index 5c658d7b3df..140feb75026 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
@@ -114,12 +114,6 @@ public class JettyHttpServer extends AbstractServerProvider {
String URI_LENGTH = "jdisc.http.request.uri_length";
String CONTENT_SIZE = "jdisc.http.request.content_size";
-
- String SSL_HANDSHAKE_FAILURE_MISSING_CLIENT_CERT = "jdisc.http.ssl.handshake_failure.missing_client_cert";
- String SSL_HANDSHAKE_FAILURE_INVALID_CLIENT_CERT = "jdisc.http.ssl.handshake_failure.invalid_client_cert";
- String SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_PROTOCOLS = "jdisc.http.ssl.handshake_failure.incompatible_protocols";
- String SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_CIPHERS = "jdisc.http.ssl.handshake_failure.incompatible_ciphers";
- String SSL_HANDSHAKE_FAILURE_UNKNOWN = "jdisc.http.ssl.handshake_failure.unknown";
}
private final static Logger log = Logger.getLogger(JettyHttpServer.class.getName());
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java
deleted file mode 100644
index 84f4fd118cc..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.yahoo.jdisc.Metric;
-import com.yahoo.jdisc.http.server.jetty.JettyHttpServer.Metrics;
-import org.eclipse.jetty.io.ssl.SslHandshakeListener;
-
-import javax.net.ssl.SSLHandshakeException;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.regex.Pattern;
-
-/**
- * A {@link SslHandshakeListener} that reports metrics for SSL handshake failures.
- *
- * @author bjorncs
- */
-class SslHandshakeFailedListener implements SslHandshakeListener {
-
- private final static Logger log = Logger.getLogger(SslHandshakeFailedListener.class.getName());
-
- private final Metric metric;
- private final String connectorName;
- private final int listenPort;
-
- SslHandshakeFailedListener(Metric metric, String connectorName, int listenPort) {
- this.metric = metric;
- this.connectorName = connectorName;
- this.listenPort = listenPort;
- }
-
- @Override
- public void handshakeFailed(Event event, Throwable throwable) {
- log.log(Level.FINE, throwable, () -> "Ssl handshake failed: " + throwable.getMessage());
- String metricName = SslHandshakeFailure.fromSslHandshakeException((SSLHandshakeException) throwable)
- .map(SslHandshakeFailure::metricName)
- .orElse(Metrics.SSL_HANDSHAKE_FAILURE_UNKNOWN);
- metric.add(metricName, 1L, metric.createContext(createDimensions()));
- }
-
- private Map<String, Object> createDimensions() {
- return Map.of(Metrics.NAME_DIMENSION, connectorName, Metrics.PORT_DIMENSION, listenPort);
- }
-
- private enum SslHandshakeFailure {
- INCOMPATIBLE_PROTOCOLS(
- Metrics.SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_PROTOCOLS,
- "(Client requested protocol \\S+? is not enabled or supported in server context" +
- "|The client supported protocol versions \\[\\S+?\\] are not accepted by server preferences \\[\\S+?\\])"),
- INCOMPATIBLE_CIPHERS(
- Metrics.SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_CIPHERS,
- "no cipher suites in common"),
- MISSING_CLIENT_CERT(
- Metrics.SSL_HANDSHAKE_FAILURE_MISSING_CLIENT_CERT,
- "Empty server certificate chain"),
- INVALID_CLIENT_CERT(
- Metrics.SSL_HANDSHAKE_FAILURE_INVALID_CLIENT_CERT,
- "PKIX path (building|validation) failed: .+");
-
- private final String metricName;
- private final Predicate<String> messageMatcher;
-
- SslHandshakeFailure(String metricName, String messagePattern) {
- this.metricName = metricName;
- this.messageMatcher = Pattern.compile(messagePattern).asMatchPredicate();
- }
-
- String metricName() { return metricName; }
-
- static Optional<SslHandshakeFailure> fromSslHandshakeException(SSLHandshakeException exception) {
- String message = exception.getMessage();
- for (SslHandshakeFailure failure : values()) {
- if (failure.messageMatcher.test(message)) {
- return Optional.of(failure);
- }
- }
- return Optional.empty();
- }
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
index 7ecf1b00fc1..31ecf3ca2fc 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
@@ -5,12 +5,10 @@ import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.container.logging.AccessLogEntry;
-import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.References;
import com.yahoo.jdisc.Request;
import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.application.BindingSetSelector;
-import com.yahoo.jdisc.application.MetricConsumer;
import com.yahoo.jdisc.handler.AbstractRequestHandler;
import com.yahoo.jdisc.handler.CompletionHandler;
import com.yahoo.jdisc.handler.ContentChannel;
@@ -23,8 +21,6 @@ import com.yahoo.jdisc.http.Cookie;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.http.HttpResponse;
import com.yahoo.jdisc.http.ServerConfig;
-import com.yahoo.jdisc.http.server.jetty.JettyHttpServer.Metrics;
-import com.yahoo.jdisc.http.server.jetty.TestDrivers.TlsClientAuth;
import com.yahoo.jdisc.service.BindingSetNotFoundException;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.SslContextBuilder;
@@ -38,8 +34,6 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.math.BigInteger;
@@ -60,8 +54,6 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import java.util.regex.Pattern;
import static com.yahoo.jdisc.Response.Status.GATEWAY_TIMEOUT;
@@ -89,21 +81,15 @@ import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Oyvind Bakksjo
* @author Simon Thoresen Hult
- * @author bjorncs
*/
public class HttpServerTest {
- private static final Logger log = Logger.getLogger(HttpServerTest.class.getName());
-
@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();
@@ -492,7 +478,7 @@ public class HttpServerTest {
Path certificateFile = tmpFolder.newFile().toPath();
generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- final TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile, TlsClientAuth.WANT);
+ final TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile);
driver.client().get("/status.html")
.expectStatusCode(is(OK));
assertThat(driver.close(), is(true));
@@ -503,7 +489,7 @@ public class HttpServerTest {
Path privateKeyFile = tmpFolder.newFile().toPath();
Path certificateFile = tmpFolder.newFile().toPath();
generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile, TlsClientAuth.WANT);
+ TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile);
SSLContext trustStoreOnlyCtx = new SslContextBuilder()
.withTrustStore(certificateFile)
@@ -521,7 +507,7 @@ public class HttpServerTest {
Path privateKeyFile = tmpFolder.newFile().toPath();
Path certificateFile = tmpFolder.newFile().toPath();
generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile, TlsClientAuth.WANT);
+ TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler(), certificateFile, privateKeyFile);
SSLContext trustStoreOnlyCtx = new SslContextBuilder()
.withTrustStore(certificateFile)
@@ -573,114 +559,6 @@ public class HttpServerTest {
assertThat(driver.close(), is(true));
}
- @Test
- public void requireThatMetricIsIncrementedWhenClientIsMissingCertificateOnHandshake() throws IOException {
- Path privateKeyFile = tmpFolder.newFile().toPath();
- Path certificateFile = tmpFolder.newFile().toPath();
- generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- var metricConsumer = new MetricConsumerMock();
- TestDriver driver = createSslTestDriver(certificateFile, privateKeyFile, metricConsumer);
-
- SSLContext clientCtx = new SslContextBuilder()
- .withTrustStore(certificateFile)
- .build();
- assertHttpsRequestTriggersSslHandshakeException(
- driver, clientCtx, null, null, "Received fatal alert: bad_certificate");
- verify(metricConsumer.mockitoMock())
- .add(Metrics.SSL_HANDSHAKE_FAILURE_MISSING_CLIENT_CERT, 1L, MetricConsumerMock.STATIC_CONTEXT);
- assertThat(driver.close(), is(true));
- }
-
- @Test
- public void requireThatMetricIsIncrementedWhenClientUsesIncompatibleTlsVersion() throws IOException {
- Path privateKeyFile = tmpFolder.newFile().toPath();
- Path certificateFile = tmpFolder.newFile().toPath();
- generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- var metricConsumer = new MetricConsumerMock();
- TestDriver driver = createSslTestDriver(certificateFile, privateKeyFile, metricConsumer);
-
- SSLContext clientCtx = new SslContextBuilder()
- .withTrustStore(certificateFile)
- .withKeyStore(privateKeyFile, certificateFile)
- .build();
-
- assertHttpsRequestTriggersSslHandshakeException(
- driver, clientCtx, "TLSv1.1", null, "Received fatal alert: protocol_version");
- verify(metricConsumer.mockitoMock())
- .add(Metrics.SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_PROTOCOLS, 1L, MetricConsumerMock.STATIC_CONTEXT);
- assertThat(driver.close(), is(true));
- }
-
- @Test
- public void requireThatMetricIsIncrementedWhenClientUsesIncompatibleCiphers() throws IOException {
- Path privateKeyFile = tmpFolder.newFile().toPath();
- Path certificateFile = tmpFolder.newFile().toPath();
- generatePrivateKeyAndCertificate(privateKeyFile, certificateFile);
- var metricConsumer = new MetricConsumerMock();
- TestDriver driver = createSslTestDriver(certificateFile, privateKeyFile, metricConsumer);
-
- SSLContext clientCtx = new SslContextBuilder()
- .withTrustStore(certificateFile)
- .withKeyStore(privateKeyFile, certificateFile)
- .build();
-
- assertHttpsRequestTriggersSslHandshakeException(
- driver, clientCtx, null, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "Received fatal alert: handshake_failure");
- verify(metricConsumer.mockitoMock())
- .add(Metrics.SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_CIPHERS, 1L, MetricConsumerMock.STATIC_CONTEXT);
- assertThat(driver.close(), is(true));
- }
-
- @Test
- public void requireThatMetricIsIncrementedWhenClientUsesInvalidCertificateInHandshake() throws IOException {
- Path serverPrivateKeyFile = tmpFolder.newFile().toPath();
- Path serverCertificateFile = tmpFolder.newFile().toPath();
- generatePrivateKeyAndCertificate(serverPrivateKeyFile, serverCertificateFile);
- var metricConsumer = new MetricConsumerMock();
- TestDriver driver = createSslTestDriver(serverCertificateFile, serverPrivateKeyFile, metricConsumer);
-
- Path clientPrivateKeyFile = tmpFolder.newFile().toPath();
- Path clientCertificateFile = tmpFolder.newFile().toPath();
- generatePrivateKeyAndCertificate(clientPrivateKeyFile, clientCertificateFile);
-
- SSLContext clientCtx = new SslContextBuilder()
- .withKeyStore(clientPrivateKeyFile, clientCertificateFile)
- .withTrustStore(serverCertificateFile)
- .build();
-
- assertHttpsRequestTriggersSslHandshakeException(
- driver, clientCtx, null, null, "Received fatal alert: certificate_unknown");
- verify(metricConsumer.mockitoMock())
- .add(Metrics.SSL_HANDSHAKE_FAILURE_INVALID_CLIENT_CERT, 1L, MetricConsumerMock.STATIC_CONTEXT);
- assertThat(driver.close(), is(true));
- }
-
- private static TestDriver createSslTestDriver(
- Path serverCertificateFile, Path serverPrivateKeyFile, MetricConsumerMock metricConsumer) throws IOException {
- return TestDrivers.newInstanceWithSsl(
- new EchoRequestHandler(), serverCertificateFile, serverPrivateKeyFile, TlsClientAuth.NEED, metricConsumer.asGuiceModule());
- }
-
- private static void assertHttpsRequestTriggersSslHandshakeException(
- TestDriver testDriver,
- SSLContext sslContext,
- String protocolOverride,
- String cipherOverride,
- String expectedExceptionSubstring) throws IOException {
- List<String> protocols = protocolOverride != null ? List.of(protocolOverride) : null;
- List<String> ciphers = cipherOverride != null ? List.of(cipherOverride) : null;
- try (var client = new SimpleHttpClient(sslContext, protocols, ciphers, testDriver.server().getListenPort(), false)) {
- client.get("/status.html");
- fail("SSLHandshakeException expected");
- } catch (SSLHandshakeException e) {
- assertThat(e.getMessage(), containsString(expectedExceptionSubstring));
- } catch (SSLException e) {
- // Jetty may sometime close the connection before the apache client has fully consumed the TLS handshake frame
- log.log(Level.WARNING, "Client failed to get a proper TLS handshake response: " + e.getMessage(), e);
- assertThat(e.getMessage(), containsString("readHandshakeRecord")); // Only ignore this specific ssl exception
- }
- }
-
private static void generatePrivateKeyAndCertificate(Path privateKeyFile, Path certificateFile) throws IOException {
KeyPair keyPair = KeyUtils.generateKeypair(RSA, 2048);
Files.writeString(privateKeyFile, KeyUtils.toPem(keyPair.getPrivate()));
@@ -871,18 +749,4 @@ public class HttpServerTest {
return lhs.getName().compareTo(rhs.getName());
}
}
-
- private static class MetricConsumerMock {
- static final Metric.Context STATIC_CONTEXT = new Metric.Context() {};
-
- private final MetricConsumer mockitoMock = mock(MetricConsumer.class);
-
- MetricConsumerMock() {
- when(mockitoMock.createContext(anyMap())).thenReturn(STATIC_CONTEXT);
- }
-
- MetricConsumer mockitoMock() { return mockitoMock; }
- Module asGuiceModule() { return binder -> binder.bind(MetricConsumer.class).toInstance(mockitoMock); }
- }
-
}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleHttpClient.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleHttpClient.java
index 8035734a76c..b0f570317d6 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleHttpClient.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleHttpClient.java
@@ -1,11 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.http.server.jetty;
+import com.yahoo.jdisc.http.HttpHeaders;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.GzipCompressingEntity;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
@@ -18,7 +19,6 @@ import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.FormBodyPart;
import org.apache.http.entity.mime.MultipartEntityBuilder;
-import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
@@ -26,11 +26,16 @@ import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import javax.net.ssl.SSLContext;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.List;
+import java.util.regex.Pattern;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
@@ -41,20 +46,14 @@ import static org.hamcrest.MatcherAssert.assertThat;
* A simple http client for testing
*
* @author Simon Thoresen Hult
- * @author bjorncs
*/
-public class SimpleHttpClient implements AutoCloseable {
+public class SimpleHttpClient {
- private final CloseableHttpClient delegate;
+ private final HttpClient delegate;
private final String scheme;
private final int listenPort;
- public SimpleHttpClient(SSLContext sslContext, int listenPort, boolean useCompression) {
- this(sslContext, null, null, listenPort, useCompression);
- }
-
- public SimpleHttpClient(SSLContext sslContext, List<String> enabledProtocols, List<String> enabledCiphers,
- int listenPort, boolean useCompression) {
+ public SimpleHttpClient(final SSLContext sslContext, final int listenPort, final boolean useCompression) {
HttpClientBuilder builder = HttpClientBuilder.create();
if (!useCompression) {
builder.disableContentCompression();
@@ -62,8 +61,6 @@ public class SimpleHttpClient implements AutoCloseable {
if (sslContext != null) {
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(
sslContext,
- toArray(enabledProtocols),
- toArray(enabledCiphers),
new DefaultHostnameVerifier());
builder.setSSLSocketFactory(sslConnectionFactory);
@@ -79,10 +76,6 @@ public class SimpleHttpClient implements AutoCloseable {
this.listenPort = listenPort;
}
- private static String[] toArray(List<String> list) {
- return list != null ? list.toArray(new String[0]) : null;
- }
-
public URI newUri(final String path) {
return URI.create(scheme + "://localhost:" + listenPort + path);
}
@@ -107,9 +100,40 @@ public class SimpleHttpClient implements AutoCloseable {
return newGet(path).execute();
}
- @Override
- public void close() throws IOException {
- delegate.close();
+ public String raw(final String request) throws IOException {
+ final Socket socket = new Socket("localhost", listenPort);
+ final OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8);
+ out.write(request);
+ out.flush();
+
+ final ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ final InputStream in = socket.getInputStream();
+ final int[] TERMINATOR = { '\r', '\n', '\r', '\n' };
+ for (int pos = 0; pos < TERMINATOR.length; ++pos) {
+ final int b = in.read();
+ if (b < 0) {
+ throw new EOFException();
+ }
+ if (b != TERMINATOR[pos]) {
+ pos = -1;
+ }
+ buf.write(b);
+ }
+ final String response = buf.toString(StandardCharsets.UTF_8.name());
+ final java.util.regex.Matcher matcher = Pattern.compile(HttpHeaders.Names.CONTENT_LENGTH + ": (.+)\r\n").matcher(response);
+ if (matcher.find()) {
+ final int len = Integer.valueOf(matcher.group(1));
+ for (int i = 0; i < len; ++i) {
+ final int b = in.read();
+ if (b < 0) {
+ throw new EOFException();
+ }
+ buf.write(b);
+ }
+ }
+
+ socket.close();
+ return buf.toString(StandardCharsets.UTF_8.name());
}
public class RequestExecutor {
@@ -153,9 +177,7 @@ public class SimpleHttpClient implements AutoCloseable {
if (entity != null) {
((HttpPost)request).setEntity(entity);
}
- try (CloseableHttpResponse response = delegate.execute(request)){
- return new ResponseValidator(response);
- }
+ return new ResponseValidator(delegate.execute(request));
}
}
@@ -196,5 +218,9 @@ public class SimpleHttpClient implements AutoCloseable {
return this;
}
+ public ResponseValidator expectTrailer(final String trailerName, final Matcher<String> matcher) {
+ // TODO: check trailer, not header
+ return expectHeader(trailerName, matcher);
+ }
}
}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java
index 4908da2ba75..e0933ac485e 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java
@@ -20,7 +20,6 @@ import java.nio.file.Path;
/**
* @author Simon Thoresen Hult
- * @author bjorncs
*/
public class TestDrivers {
@@ -46,12 +45,9 @@ public class TestDrivers {
));
}
- public enum TlsClientAuth { NEED, WANT }
-
public static TestDriver newInstanceWithSsl(final RequestHandler requestHandler,
Path certificateFile,
Path privateKeyFile,
- TlsClientAuth tlsClientAuth,
final Module... guiceModules) throws IOException {
return TestDriver.newInstance(
JettyHttpServer.class,
@@ -65,9 +61,7 @@ public class TestDrivers {
.pathWhitelist("/status.html"))
.ssl(new ConnectorConfig.Ssl.Builder()
.enabled(true)
- .clientAuth(tlsClientAuth == TlsClientAuth.NEED
- ? ConnectorConfig.Ssl.ClientAuth.Enum.NEED_AUTH
- : ConnectorConfig.Ssl.ClientAuth.Enum.WANT_AUTH)
+ .clientAuth(ConnectorConfig.Ssl.ClientAuth.Enum.WANT_AUTH)
.privateKeyFile(privateKeyFile.toString())
.certificateFile(certificateFile.toString())
.caCertificateFile(certificateFile.toString())),