Merge "Don't reuse an SSL socket if the socket factory has changed."
diff --git a/luni/src/main/java/libcore/net/http/HttpConnection.java b/luni/src/main/java/libcore/net/http/HttpConnection.java
index 779f80f..66dec4d 100644
--- a/luni/src/main/java/libcore/net/http/HttpConnection.java
+++ b/luni/src/main/java/libcore/net/http/HttpConnection.java
@@ -86,15 +86,15 @@
         this.socket = socketCandidate;
     }
 
-    public static HttpConnection connect(URI uri, Proxy proxy, boolean requiresTunnel,
-            int connectTimeout) throws IOException {
+    public static HttpConnection connect(URI uri, SSLSocketFactory sslSocketFactory,
+            Proxy proxy, boolean requiresTunnel, int connectTimeout) throws IOException {
         /*
          * Try an explicitly-specified proxy.
          */
         if (proxy != null) {
             Address address = (proxy.type() == Proxy.Type.DIRECT)
-                    ? new Address(uri)
-                    : new Address(uri, proxy, requiresTunnel);
+                    ? new Address(uri, sslSocketFactory)
+                    : new Address(uri, sslSocketFactory, proxy, requiresTunnel);
             return HttpConnectionPool.INSTANCE.get(address, connectTimeout);
         }
 
@@ -112,7 +112,8 @@
                     continue;
                 }
                 try {
-                    Address address = new Address(uri, selectedProxy, requiresTunnel);
+                    Address address = new Address(uri, sslSocketFactory,
+                            selectedProxy, requiresTunnel);
                     return HttpConnectionPool.INSTANCE.get(address, connectTimeout);
                 } catch (IOException e) {
                     // failed to connect, tell it to the selector
@@ -124,7 +125,7 @@
         /*
          * Try a direct connection. If this fails, this method will throw.
          */
-        return HttpConnectionPool.INSTANCE.get(new Address(uri), connectTimeout);
+        return HttpConnectionPool.INSTANCE.get(new Address(uri, sslSocketFactory), connectTimeout);
     }
 
     public void closeSocketAndStreams() {
@@ -258,7 +259,8 @@
     /**
      * This address has two parts: the address we connect to directly and the
      * origin address of the resource. These are the same unless a proxy is
-     * being used.
+     * being used. It also includes the SSL socket factory so that a socket will
+     * not be reused if its SSL configuration is different.
      */
     public static final class Address {
         private final Proxy proxy;
@@ -267,12 +269,14 @@
         private final int uriPort;
         private final String socketHost;
         private final int socketPort;
+        private final SSLSocketFactory sslSocketFactory;
 
-        public Address(URI uri) throws UnknownHostException {
+        public Address(URI uri, SSLSocketFactory sslSocketFactory) throws UnknownHostException {
             this.proxy = null;
             this.requiresTunnel = false;
             this.uriHost = uri.getHost();
             this.uriPort = uri.getEffectivePort();
+            this.sslSocketFactory = sslSocketFactory;
             this.socketHost = uriHost;
             this.socketPort = uriPort;
             if (uriHost == null) {
@@ -286,11 +290,13 @@
          *     proxy. When doing so, we must avoid buffering bytes intended for
          *     the higher-level protocol.
          */
-        public Address(URI uri, Proxy proxy, boolean requiresTunnel) throws UnknownHostException {
+        public Address(URI uri, SSLSocketFactory sslSocketFactory,
+                Proxy proxy, boolean requiresTunnel) throws UnknownHostException {
             this.proxy = proxy;
             this.requiresTunnel = requiresTunnel;
             this.uriHost = uri.getHost();
             this.uriPort = uri.getEffectivePort();
+            this.sslSocketFactory = sslSocketFactory;
 
             SocketAddress proxyAddress = proxy.address();
             if (!(proxyAddress instanceof InetSocketAddress)) {
@@ -315,6 +321,7 @@
                 return Objects.equal(this.proxy, that.proxy)
                         && this.uriHost.equals(that.uriHost)
                         && this.uriPort == that.uriPort
+                        && Objects.equal(this.sslSocketFactory, that.sslSocketFactory)
                         && this.requiresTunnel == that.requiresTunnel;
             }
             return false;
@@ -324,6 +331,7 @@
             int result = 17;
             result = 31 * result + uriHost.hashCode();
             result = 31 * result + uriPort;
+            result = 31 * result + (sslSocketFactory != null ? sslSocketFactory.hashCode() : 0);
             result = 31 * result + (proxy != null ? proxy.hashCode() : 0);
             result = 31 * result + (requiresTunnel ? 1 : 0);
             return result;
diff --git a/luni/src/main/java/libcore/net/http/HttpEngine.java b/luni/src/main/java/libcore/net/http/HttpEngine.java
index f32e553..820761a 100644
--- a/luni/src/main/java/libcore/net/http/HttpEngine.java
+++ b/luni/src/main/java/libcore/net/http/HttpEngine.java
@@ -38,6 +38,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
+import javax.net.ssl.SSLSocketFactory;
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 import libcore.util.EmptyArray;
@@ -305,8 +306,8 @@
     }
 
     protected final HttpConnection openSocketConnection() throws IOException {
-        HttpConnection result = HttpConnection.connect(
-                uri, policy.getProxy(), requiresTunnel(), policy.getConnectTimeout());
+        HttpConnection result = HttpConnection.connect(uri, getSslSocketFactory(),
+                policy.getProxy(), requiresTunnel(), policy.getConnectTimeout());
         Proxy proxy = result.getAddress().getProxy();
         if (proxy != null) {
             policy.setProxy(proxy);
@@ -731,6 +732,14 @@
         return policy.usingProxy();
     }
 
+    /**
+     * Returns the SSL configuration for connections created by this engine.
+     * We cannot reuse HTTPS connections if the socket factory has changed.
+     */
+    protected SSLSocketFactory getSslSocketFactory() {
+        return null;
+    }
+
     protected final String getDefaultUserAgent() {
         String agent = System.getProperty("http.agent");
         return agent != null ? agent : ("Java" + System.getProperty("java.version"));
diff --git a/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java b/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java
index e213706..9e3e4ef 100644
--- a/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java
+++ b/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java
@@ -35,6 +35,7 @@
 import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLPeerUnverifiedException;
 import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
 
 final class HttpsURLConnectionImpl extends HttpsURLConnection {
 
@@ -519,6 +520,10 @@
             return false;
         }
 
+        @Override protected SSLSocketFactory getSslSocketFactory() {
+            return enclosing.getSSLSocketFactory();
+        }
+
         @Override protected HttpURLConnection getHttpConnectionToCache() {
             return enclosing;
         }
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index d16f14a..195b7b8 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -454,6 +454,7 @@
 
     public void testConnectViaHttpsReusingConnections() throws IOException, InterruptedException {
         TestSSLContext testSSLContext = TestSSLContext.create();
+        SSLSocketFactory clientSocketFactory = testSSLContext.clientContext.getSocketFactory();
 
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
         server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
@@ -461,11 +462,11 @@
         server.play();
 
         HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
-        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+        connection.setSSLSocketFactory(clientSocketFactory);
         assertContent("this response comes via HTTPS", connection);
 
         connection = (HttpsURLConnection) server.getUrl("/").openConnection();
-        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+        connection.setSSLSocketFactory(clientSocketFactory);
         assertContent("another response via HTTPS", connection);
 
         assertEquals(0, server.takeRequest().getSequenceNumber());