http-client-branch: fixed TLS hostname checking issue, SSL session reuse, and changed HttpResponse to return SSLSession
--- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java Wed Feb 14 16:04:18 2018 +0000
@@ -47,7 +47,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
-import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
import jdk.internal.net.http.BufferingSubscriber;
import jdk.internal.net.http.LineSubscriberAdapter;
import jdk.internal.net.http.ResponseBodyHandlers.FileDownloadBodyHandler;
@@ -132,12 +132,12 @@
public abstract T body();
/**
- * Returns the {@link javax.net.ssl.SSLParameters} in effect for this
- * response. Returns {@code null} if this is not a HTTPS response.
+ * Returns an {@link Optional} containing the {@link javax.net.ssl.SSLSession} in effect
+ * for this response. Returns an empty {@code Optional} if this is not a HTTPS response.
*
- * @return the SSLParameters associated with the response
+ * @return an {@code Optional} containing the SSLSession associated with the response
*/
- public abstract SSLParameters sslParameters();
+ public abstract Optional<SSLSession> sslSession();
/**
* Returns the {@code URI} that the response was received from. This may be
--- a/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java Wed Feb 14 16:04:18 2018 +0000
@@ -69,14 +69,14 @@
AbstractAsyncSSLConnection(InetSocketAddress addr,
HttpClientImpl client,
- String serverName,
+ String serverName, int port,
String[] alpn) {
super(addr, client);
this.serverName = serverName;
SSLContext context = client.theSSLContext();
sslParameters = createSSLParameters(client, serverName, alpn);
Log.logParams(sslParameters);
- engine = createEngine(context, sslParameters);
+ engine = createEngine(context, serverName, port, sslParameters);
}
abstract HttpConnection plainConnection();
@@ -94,6 +94,7 @@
String[] alpn) {
SSLParameters sslp = client.sslParameters();
SSLParameters sslParameters = Utils.copySSLParameters(sslp);
+ sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
if (alpn != null) {
Log.logSSL("AbstractAsyncSSLConnection: Setting application protocols: {0}",
Arrays.toString(alpn));
@@ -107,9 +108,9 @@
return sslParameters;
}
- private static SSLEngine createEngine(SSLContext context,
+ private static SSLEngine createEngine(SSLContext context, String serverName, int port,
SSLParameters sslParameters) {
- SSLEngine engine = context.createSSLEngine();
+ SSLEngine engine = context.createSSLEngine(serverName, port);
engine.setUseClientMode(true);
engine.setSSLParameters(sslParameters);
return engine;
--- a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java Wed Feb 14 16:04:18 2018 +0000
@@ -46,7 +46,7 @@
AsyncSSLConnection(InetSocketAddress addr,
HttpClientImpl client,
String[] alpn) {
- super(addr, client, Utils.getServerName(addr), alpn);
+ super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
plainConnection = new PlainHttpConnection(addr, client);
writePublisher = new PlainHttpPublisher();
}
--- a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java Wed Feb 14 16:04:18 2018 +0000
@@ -49,7 +49,7 @@
InetSocketAddress proxy,
HttpHeaders proxyHeaders)
{
- super(addr, client, Utils.getServerName(addr), alpn);
+ super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders);
this.writePublisher = new PlainHttpPublisher();
}
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java Wed Feb 14 16:04:18 2018 +0000
@@ -310,8 +310,9 @@
if (t instanceof ProxyAuthenticationRequired) {
bodyIgnored = MinimalFuture.completedFuture(null);
Response proxyResponse = ((ProxyAuthenticationRequired)t).proxyResponse;
+ HttpConnection c = ex == null ? null : ex.connection();
Response syntheticResponse = new Response(request, this,
- proxyResponse.headers, proxyResponse.statusCode,
+ proxyResponse.headers, c, proxyResponse.statusCode,
proxyResponse.version, true);
return MinimalFuture.completedFuture(syntheticResponse);
} else if (t != null) {
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java Wed Feb 14 16:04:18 2018 +0000
@@ -107,6 +107,7 @@
response = new Response(request,
exchange.getExchange(),
headers,
+ connection,
responseCode,
HTTP_1_1);
return response;
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java Wed Feb 14 16:04:18 2018 +0000
@@ -31,7 +31,7 @@
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
-import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
@@ -48,7 +48,7 @@
final HttpRequest initialRequest;
final Optional<HttpResponse<T>> previousResponse;
final HttpHeaders headers;
- final SSLParameters sslParameters;
+ final Optional<SSLSession> sslSession;
final URI uri;
final HttpClient.Version version;
RawChannel rawchan;
@@ -67,7 +67,7 @@
this.previousResponse = Optional.ofNullable(previousResponse);
this.headers = response.headers();
//this.trailers = trailers;
- this.sslParameters = exch.client().sslParameters();
+ this.sslSession = Optional.ofNullable(response.getSSLSession());
this.uri = response.request().uri();
this.version = response.version();
this.connection = connection(exch);
@@ -113,8 +113,8 @@
}
@Override
- public SSLParameters sslParameters() {
- return sslParameters;
+ public Optional<SSLSession> sslSession() {
+ return sslSession;
}
@Override
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Response.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Response.java Wed Feb 14 16:04:18 2018 +0000
@@ -26,8 +26,13 @@
package jdk.internal.net.http;
import java.net.URI;
+import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
+import java.net.InetSocketAddress;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+import jdk.internal.net.http.common.Utils;
/**
* Response headers and status code.
@@ -39,19 +44,23 @@
final Exchange<?> exchange;
final HttpClient.Version version;
final boolean isConnectResponse;
+ final SSLSession sslSession;
+ final InetSocketAddress localAddress;
Response(HttpRequestImpl req,
Exchange<?> exchange,
HttpHeaders headers,
+ HttpConnection connection,
int statusCode,
HttpClient.Version version) {
- this(req, exchange, headers, statusCode, version,
+ this(req, exchange, headers, connection, statusCode, version,
"CONNECT".equalsIgnoreCase(req.method()));
}
Response(HttpRequestImpl req,
Exchange<?> exchange,
HttpHeaders headers,
+ HttpConnection connection,
int statusCode,
HttpClient.Version version,
boolean isConnectResponse) {
@@ -60,7 +69,21 @@
this.version = version;
this.exchange = exchange;
this.statusCode = statusCode;
+ InetSocketAddress a;
+ try {
+ a = (InetSocketAddress)connection.channel().getLocalAddress();
+ } catch (IOException e) {
+ a = null;
+ }
+ this.localAddress = a;
this.isConnectResponse = isConnectResponse;
+ if (connection != null && connection instanceof AbstractAsyncSSLConnection) {
+ AbstractAsyncSSLConnection cc = (AbstractAsyncSSLConnection)connection;
+ SSLEngine engine = cc.getEngine();
+ sslSession = Utils.immutableSession(engine.getSession());
+ } else {
+ sslSession = null;
+ }
}
HttpRequestImpl request() {
@@ -83,6 +106,10 @@
return statusCode;
}
+ SSLSession getSSLSession() {
+ return sslSession;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -95,6 +122,9 @@
.append(uristring)
.append(") ")
.append(statusCode());
+ sb.append(" ").append(version);
+ if (localAddress != null)
+ sb.append(" Local port: ").append(localAddress.getPort());
return sb.toString();
}
}
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java Wed Feb 14 16:04:18 2018 +0000
@@ -363,7 +363,7 @@
.orElseThrow(() -> new IOException("no statuscode in response"));
response = new Response(
- request, exchange, responseHeaders,
+ request, exchange, responseHeaders, connection(),
responseCode, HttpClient.Version.HTTP_2);
/* TODO: review if needs to be removed
@@ -1120,7 +1120,7 @@
}
this.response = new Response(
- pushReq, exchange, responseHeaders,
+ pushReq, exchange, responseHeaders, connection(),
responseCode, HttpClient.Version.HTTP_2);
/* TODO: review if needs to be removed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/ImmutableExtendedSSLSession.java Wed Feb 14 16:04:18 2018 +0000
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.net.http.common;
+
+import java.security.Principal;
+import java.util.List;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.ExtendedSSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SNIServerName;
+
+/**
+ * All mutating methods throw UnsupportedOperationException
+ */
+public class ImmutableExtendedSSLSession extends ExtendedSSLSession {
+ private final ExtendedSSLSession delegate;
+
+ ImmutableExtendedSSLSession(ExtendedSSLSession session) {
+ this.delegate = session;
+ }
+
+ public byte[] getId() {
+ return delegate.getId();
+ }
+
+ public SSLSessionContext getSessionContext() {
+ return delegate.getSessionContext();
+ }
+
+ public long getCreationTime() {
+ return delegate.getCreationTime();
+ }
+
+ public long getLastAccessedTime() {
+ return delegate.getLastAccessedTime();
+ }
+
+ public void invalidate() {
+ throw new UnsupportedOperationException("session is not mutable");
+ }
+
+ public boolean isValid() {
+ return delegate.isValid();
+ }
+
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException("session is not mutable");
+ }
+
+ public Object getValue(String name) {
+ return delegate.getValue(name);
+ }
+
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException("session is not mutable");
+ }
+
+ public String [] getValueNames() {
+ return delegate.getValueNames();
+ }
+
+ public java.security.cert.Certificate [] getPeerCertificates()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerCertificates();
+ }
+
+ public java.security.cert.Certificate [] getLocalCertificates() {
+ return delegate.getLocalCertificates();
+ }
+
+ @Deprecated
+ public javax.security.cert.X509Certificate [] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerCertificateChain();
+ }
+
+ public Principal getPeerPrincipal()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerPrincipal();
+ }
+
+ public Principal getLocalPrincipal() {
+ return delegate.getLocalPrincipal();
+ }
+
+ public String getCipherSuite() {
+ return delegate.getCipherSuite();
+ }
+
+ public String getProtocol() {
+ return delegate.getProtocol();
+ }
+
+ public String getPeerHost() {
+ return delegate.getPeerHost();
+ }
+
+ public int getPeerPort() {
+ return delegate.getPeerPort();
+ }
+
+ public int getPacketBufferSize() {
+ return delegate.getPacketBufferSize();
+ }
+
+ public int getApplicationBufferSize() {
+ return delegate.getApplicationBufferSize();
+ }
+
+ public String[] getLocalSupportedSignatureAlgorithms() {
+ return delegate.getLocalSupportedSignatureAlgorithms();
+ }
+
+ public String[] getPeerSupportedSignatureAlgorithms() {
+ return delegate.getPeerSupportedSignatureAlgorithms();
+ }
+
+ public List<SNIServerName> getRequestedServerNames() {
+ return delegate.getRequestedServerNames();
+ }
+
+ public List<byte[]> getStatusResponses() {
+ return delegate.getStatusResponses();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/ImmutableSSLSession.java Wed Feb 14 16:04:18 2018 +0000
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.net.http.common;
+
+import java.security.Principal;
+import java.util.List;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SNIServerName;
+
+/**
+ * All mutating methods throw UnsupportedOperationException
+ */
+public class ImmutableSSLSession implements SSLSession {
+ private final SSLSession delegate;
+
+ ImmutableSSLSession(SSLSession session) {
+ this.delegate = session;
+ }
+
+ public byte[] getId() {
+ return delegate.getId();
+ }
+
+ public SSLSessionContext getSessionContext() {
+ return delegate.getSessionContext();
+ }
+
+ public long getCreationTime() {
+ return delegate.getCreationTime();
+ }
+
+ public long getLastAccessedTime() {
+ return delegate.getLastAccessedTime();
+ }
+
+ public void invalidate() {
+ throw new UnsupportedOperationException("session is not mutable");
+ }
+
+ public boolean isValid() {
+ return delegate.isValid();
+ }
+
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException("session is not mutable");
+ }
+
+ public Object getValue(String name) {
+ return delegate.getValue(name);
+ }
+
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException("session is not mutable");
+ }
+
+ public String [] getValueNames() {
+ return delegate.getValueNames();
+ }
+
+ public java.security.cert.Certificate [] getPeerCertificates()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerCertificates();
+ }
+
+ public java.security.cert.Certificate [] getLocalCertificates() {
+ return delegate.getLocalCertificates();
+ }
+
+ @Deprecated
+ public javax.security.cert.X509Certificate [] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerCertificateChain();
+ }
+
+ public Principal getPeerPrincipal()
+ throws SSLPeerUnverifiedException {
+ return delegate.getPeerPrincipal();
+ }
+
+ public Principal getLocalPrincipal() {
+ return delegate.getLocalPrincipal();
+ }
+
+ public String getCipherSuite() {
+ return delegate.getCipherSuite();
+ }
+
+ public String getProtocol() {
+ return delegate.getProtocol();
+ }
+
+ public String getPeerHost() {
+ return delegate.getPeerHost();
+ }
+
+ public int getPeerPort() {
+ return delegate.getPeerPort();
+ }
+
+ public int getPacketBufferSize() {
+ return delegate.getPacketBufferSize();
+ }
+
+ public int getApplicationBufferSize() {
+ return delegate.getApplicationBufferSize();
+ }
+}
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Log.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Log.java Wed Feb 14 16:04:18 2018 +0000
@@ -272,6 +272,12 @@
}
}
+ if (p.getEndpointIdentificationAlgorithm() != null) {
+ sb.append("\n endpointIdAlg: {")
+ .append(params.size()).append("}");
+ params.add(p.getEndpointIdentificationAlgorithm());
+ }
+
if (p.getServerNames() != null) {
for (SNIServerName sname : p.getServerNames()) {
sb.append("\n server name: {")
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java Tue Feb 13 16:22:49 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java Wed Feb 14 16:04:18 2018 +0000
@@ -30,7 +30,6 @@
import sun.net.util.IPAddressUtil;
import sun.net.www.HeaderParser;
-import javax.net.ssl.SSLParameters;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
@@ -60,6 +59,9 @@
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.ExtendedSSLSession;
import static java.util.stream.Collectors.joining;
@@ -284,17 +286,48 @@
/**
* If the address was created with a domain name, then return
* the domain name string. If created with a literal IP address
- * then return null. We do this to avoid doing a reverse lookup
+ * then return null except if the literal is loopback.
+ * We do this to avoid doing a reverse lookup
* Used to populate the TLS SNI parameter. So, SNI is only set
- * when a domain name was supplied.
+ * when a domain name was supplied except in case of loopback
+ * where we return "localhost".
*/
public static String getServerName(InetSocketAddress addr) {
String host = addr.getHostString();
- if (IPAddressUtil.textToNumericFormatV4(host) != null)
- return null;
- if (IPAddressUtil.textToNumericFormatV6(host) != null)
- return null;
- return host;
+ byte[] literal = IPAddressUtil.textToNumericFormatV4(host);
+ if (literal == null) {
+ // not IPv4 literal
+ literal = IPAddressUtil.textToNumericFormatV6(host);
+ if (literal == null) {
+ // not IPv6 literal. Must be domain name
+ return host;
+ } else { // check if loopback
+ if (isLoopbackLiteral(literal))
+ return "localhost";
+ else
+ return null;
+ }
+ } else {
+ // check if IPv4 loopback
+ if (isLoopbackLiteral(literal))
+ return "localhost";
+ else
+ return null;
+ }
+ }
+
+ private static boolean isLoopbackLiteral(byte[] bytes) {
+ if (bytes.length == 4) {
+ return bytes[0] == 127;
+ } else if (bytes.length == 16) {
+ for (int i=0; i<14; i++)
+ if (bytes[i] != 0)
+ return false;
+ if (bytes[15] != 1)
+ return false;
+ return true;
+ } else
+ throw new InternalError();
}
/*
@@ -752,4 +785,14 @@
Level outLevel = on ? Level.ALL : Level.OFF;
return getHpackLogger(dbgTag, outLevel);
}
+
+ /**
+ * SSLSessions returned to user are wrapped in an immutable object
+ */
+ public static SSLSession immutableSession(SSLSession session) {
+ if (session instanceof ExtendedSSLSession)
+ return new ImmutableExtendedSSLSession((ExtendedSSLSession)session);
+ else
+ return new ImmutableSSLSession(session);
+ }
}
--- a/test/jdk/java/net/httpclient/ManyRequestsLegacy.java Tue Feb 13 16:22:49 2018 +0000
+++ b/test/jdk/java/net/httpclient/ManyRequestsLegacy.java Wed Feb 14 16:04:18 2018 +0000
@@ -139,12 +139,8 @@
@Override
public byte[] body() {return response;}
@Override
- public SSLParameters sslParameters() {
- try {
- return SSLContext.getDefault().getDefaultSSLParameters();
- } catch (NoSuchAlgorithmException ex) {
- throw new UnsupportedOperationException(ex);
- }
+ public Optional<SSLSession> sslSession() {
+ return Optional.empty(); // for now
}
@Override
public URI uri() { return request.uri();}
--- a/test/jdk/java/net/httpclient/SmokeTest.java Tue Feb 13 16:22:49 2018 +0000
+++ b/test/jdk/java/net/httpclient/SmokeTest.java Wed Feb 14 16:04:18 2018 +0000
@@ -32,7 +32,7 @@
* @compile ../../../com/sun/net/httpserver/LogFilter.java
* @compile ../../../com/sun/net/httpserver/EchoHandler.java
* @compile ../../../com/sun/net/httpserver/FileServerHandler.java
- * @run main/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=errors,trace SmokeTest
+ * @run main/othervm -Djdk.internal.httpclient.debugX=true -Djdk.httpclient.HttpClient.log=errors,ssl,trace SmokeTest
*/
import com.sun.net.httpserver.Headers;
@@ -753,7 +753,8 @@
s1.setExecutor(executor);
s2.setExecutor(executor);
ctx = new SimpleSSLContext().get();
- sslparams = ctx.getSupportedSSLParameters();
+ sslparams = ctx.getDefaultSSLParameters();
+ //sslparams.setProtocols(new String[]{"TLSv1.2"});
s2.setHttpsConfigurator(new Configurator(ctx));
s1.start();
s2.start();
@@ -874,7 +875,9 @@
}
public void configure (HttpsParameters params) {
- params.setSSLParameters (getSSLContext().getSupportedSSLParameters());
+ SSLParameters p = getSSLContext().getDefaultSSLParameters();
+ //p.setProtocols(new String[]{"TLSv1.2"});
+ params.setSSLParameters (p);
}
}
Binary file test/jdk/java/net/httpclient/http2/keystore.p12 has changed
--- a/test/jdk/java/net/httpclient/offline/FixedHttpResponse.java Tue Feb 13 16:22:49 2018 +0000
+++ b/test/jdk/java/net/httpclient/offline/FixedHttpResponse.java Wed Feb 14 16:04:18 2018 +0000
@@ -21,7 +21,7 @@
* questions.
*/
-import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
import java.net.URI;
import java.util.Optional;
import java.net.http.HttpClient;
@@ -38,7 +38,7 @@
private final HttpRequest request;
private final HttpHeaders headers;
private final T body;
- private final SSLParameters sslParameters;
+ private final SSLSession sslSession;
private final URI uri;
private final HttpClient.Version version;
@@ -46,14 +46,14 @@
HttpRequest request,
HttpHeaders headers,
T body,
- SSLParameters sslParameters,
+ SSLSession sslSession,
URI uri,
HttpClient.Version version) {
this.statusCode = statusCode;
this.request = request;
this.headers = headers;
this.body = body;
- this.sslParameters = sslParameters;
+ this.sslSession = sslSession;
this.uri = uri;
this.version = version;
}
@@ -84,8 +84,8 @@
}
@Override
- public SSLParameters sslParameters() {
- return sslParameters;
+ public Optional<SSLSession> sslSession() {
+ return Optional.ofNullable(sslSession);
}
@Override
--- a/test/jdk/java/net/httpclient/offline/FixedResponseHttpClient.java Tue Feb 13 16:22:49 2018 +0000
+++ b/test/jdk/java/net/httpclient/offline/FixedResponseHttpClient.java Wed Feb 14 16:04:18 2018 +0000
@@ -169,7 +169,7 @@
request,
responseHeaders,
body,
- this.sslParameters(),
+ null,
request.uri(),
request.version().orElse(Version.HTTP_2)));
else
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/ssltest/CertificateTest.java Wed Feb 14 16:04:18 2018 +0000
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpClient.Version;
+import java.net.http.HttpResponse.BodyHandler;
+import static java.net.http.HttpResponse.BodyHandler.asString;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+/*
+ * @test
+ * @build Server CertificateTest
+ * @run main/othervm CertificateTest good
+ * @run main/othervm CertificateTest bad
+ */
+
+/**
+ * The test runs twice. In both cases it uses a valid self-signed certificate
+ * that is installed in the trust store (so is trusted) and the same cert is supplied
+ * by the server for its own identity. Two servers on two different ports are used
+ * on the remote end.
+ *
+ * For the "good" run the cert contains the correct hostname of the target server
+ * and therefore should be accepted by the cert checking code in the client.
+ * For the "bad" run, the cert contains an invalid hostname, and should be rejected.
+ */
+public class CertificateTest {
+ static SSLContext ctx;
+ static SSLParameters params;
+ static boolean good;
+ static String trustStoreProp;
+ static String suffix;
+ static Server server;
+ static int port;
+
+ static String TESTSRC = System.getProperty("test.src");
+ public static void main(String[] args) throws Exception
+ {
+ try {
+ if (args[0].equals("good")) {
+ good = true;
+ trustStoreProp = TESTSRC + "/good.keystore";
+ } else {
+ good = false;
+ trustStoreProp = TESTSRC + "/bad.keystore";
+ }
+ server = new Server(trustStoreProp);
+ port = server.getPort();
+ System.setProperty("javax.net.ssl.trustStore", trustStoreProp);
+ System.setProperty("javax.net.ssl.trustStorePassword", "passphrase");
+ init();
+ test(args);
+ } finally {
+ server.stop();
+ }
+ }
+
+ static void init() throws Exception
+ {
+ ctx = SSLContext.getDefault();
+ params = ctx.getDefaultSSLParameters();
+ //params.setProtocols(new String[] { "TLSv1.2" });
+ }
+
+ static void test(String[] args) throws Exception
+ {
+ String uri_s = "https://127.0.0.1:" + Integer.toString(port) + "/foo";
+ String error = null;
+ Exception exception = null;
+ System.out.println("Making request to " + uri_s);
+ HttpClient client = HttpClient.newBuilder()
+ .sslContext(ctx)
+ .sslParameters(params)
+ .build();
+
+ HttpRequest request = HttpRequest.newBuilder(new URI(uri_s))
+ .version(HttpClient.Version.HTTP_1_1)
+ .GET()
+ .build();
+
+ try {
+ HttpResponse<String> response = client.send(request, asString());
+ System.out.printf("Status code %d received\n", response.statusCode());
+ if (good && response.statusCode() != 200)
+ error = "Test failed: good: status should be 200";
+ else if (!good)
+ error = "Test failed: bad: status should not be 200";
+ } catch (Exception e) {
+ System.err.println("Exception good = " + good);
+ exception = e;
+ if (good)
+ error = "Test failed: good: got exception";
+ }
+ if (error != null)
+ throw new RuntimeException(error, exception);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/ssltest/Server.java Wed Feb 14 16:04:18 2018 +0000
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.net.httpserver.*;
+import java.io.*;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.security.*;
+import java.util.*;
+import java.util.logging.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import javax.net.ssl.*;
+
+public class Server {
+
+ HttpsServer server;
+ final ExecutorService exec;
+ final int port;
+
+ // certfile: needs to be good or bad, ie. bad contains an otherwise valid
+ // cert but whose CN contains a different host. good must be correct
+
+ // assuming the TLS handshake succeeds, the server returns a 200 OK
+ // response with a short text string.
+ public Server(String certfile) throws Exception {
+ initLogger();
+ SSLContext ctx = getContext("TLSv1.2", certfile);
+ Configurator cfg = new Configurator(ctx);
+ server = HttpsServer.create(new InetSocketAddress(0), 10);
+ server.setHttpsConfigurator(cfg);
+ server.createContext("/", new MyHandler());
+ server.setExecutor((exec=Executors.newCachedThreadPool()));
+ port = server.getAddress().getPort();
+ System.out.println ("Listening on port " + port);
+ server.start();
+ }
+
+ int getPort() {
+ return port;
+ }
+
+ void stop() {
+ server.stop(1);
+ exec.shutdownNow();
+ }
+
+ SSLContext getContext(String protocol, String certfile) throws Exception {
+ char[] passphrase = "passphrase".toCharArray();
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(new FileInputStream(certfile), passphrase);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ kmf.init(ks, passphrase);
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ tmf.init(ks);
+
+ SSLContext ssl = SSLContext.getInstance(protocol);
+ ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ return ssl;
+ }
+
+ Logger logger;
+
+ void initLogger() {
+ logger = Logger.getLogger("com.sun.net.httpserver");
+ Handler h = new ConsoleHandler();
+ logger.setLevel(Level.ALL);
+ h.setLevel(Level.ALL);
+ logger.addHandler(h);
+ }
+
+ String responseBody = "Greetings from localhost";
+
+ class MyHandler implements HttpHandler {
+
+ @Override
+ public void handle(HttpExchange e) throws IOException {
+ System.out.println("Server: received " + e.getRequestURI());
+ InputStream is = e.getRequestBody();
+ byte[] buf = new byte[128];
+ while (is.read(buf) != -1);
+ is.close();
+ e.sendResponseHeaders(200, responseBody.length());
+ OutputStream os = e.getResponseBody();
+ os.write(responseBody.getBytes("ISO8859_1"));
+ os.close();
+ }
+ }
+
+ class Configurator extends HttpsConfigurator {
+ public Configurator(SSLContext ctx) throws Exception {
+ super(ctx);
+ }
+
+ public void configure(HttpsParameters params) {
+ SSLParameters p = getSSLContext().getDefaultSSLParameters();
+ for (String cipher : p.getCipherSuites())
+ System.out.println("Cipher: " + cipher);
+ System.err.println("PArams = " + p);
+ params.setSSLParameters(p);
+ }
+ }
+}
Binary file test/jdk/java/net/httpclient/ssltest/bad.keystore has changed
Binary file test/jdk/java/net/httpclient/ssltest/good.keystore has changed
--- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AuthenticationFilterTest.java Tue Feb 13 16:22:49 2018 +0000
+++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AuthenticationFilterTest.java Wed Feb 14 16:04:18 2018 +0000
@@ -209,7 +209,7 @@
HttpHeadersImpl headers = new HttpHeadersImpl();
headers.addHeader(authenticate(proxy!=null),
"Basic realm=\"earth\"");
- Response response = new Response(req, exchange, headers, unauthorized, v);
+ Response response = new Response(req, exchange, headers, null, unauthorized, v);
out.println("Simulating " + unauthorized
+ " response from " + uri);
HttpRequestImpl next = filter.response(response);
@@ -232,7 +232,7 @@
check(reqURI, next.getSystemHeaders(), proxy);
check(next.uri(), next.getSystemHeaders(), proxy);
out.println("Simulating successful response 200 from " + uri);
- response = new Response(next, exchange, new HttpHeadersImpl(), 200, v);
+ response = new Response(next, exchange, new HttpHeadersImpl(), null, 200, v);
next = filter.response(response);
assertTrue(next == null, "next should be null");
assertEquals(authenticator.COUNTER.get(), 1);
@@ -401,7 +401,7 @@
headers5.addHeader(authenticate(false),
"Basic realm=\"earth\"");
unauthorized = 401;
- Response response5 = new Response(req5, exchange5, headers5, unauthorized, v);
+ Response response5 = new Response(req5, exchange5, headers5, null, unauthorized, v);
out.println("Simulating " + unauthorized
+ " response from " + uri);
HttpRequestImpl next5 = filter.response(response5);
@@ -415,7 +415,7 @@
// now simulate a 200 response from the server
exchange5 = new Exchange<>(next5, multi5);
filter.request(next5, multi5);
- response5 = new Response(next5, exchange5, new HttpHeadersImpl(), 200, v);
+ response5 = new Response(next5, exchange5, new HttpHeadersImpl(), null, 200, v);
filter.response(response5);
assertEquals(authenticator.COUNTER.get(), 2);
Binary file test/jdk/lib/testlibrary/jdk/testlibrary/testkeys has changed