1 /*
   2  * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.net.www.protocol.https;
  27 
  28 import java.net.URL;
  29 import java.net.Proxy;
  30 import java.net.SecureCacheResponse;
  31 import java.security.Principal;
  32 import java.io.IOException;
  33 import java.util.List;
  34 import javax.net.ssl.SSLPeerUnverifiedException;
  35 import sun.net.www.http.*;
  36 import sun.net.www.protocol.http.HttpURLConnection;
  37 
  38 /**
  39  * HTTPS URL connection support.
  40  * We need this delegate because HttpsURLConnection is a subclass of
  41  * java.net.HttpURLConnection. We will avoid copying over the code from
  42  * sun.net.www.protocol.http.HttpURLConnection by having this class
  43  *
  44  */
  45 public abstract class AbstractDelegateHttpsURLConnection extends
  46         HttpURLConnection {
  47 
  48     protected AbstractDelegateHttpsURLConnection(URL url,
  49             sun.net.www.protocol.http.Handler handler) throws IOException {
  50         this(url, null, handler);
  51     }
  52 
  53     protected AbstractDelegateHttpsURLConnection(URL url, Proxy p,
  54             sun.net.www.protocol.http.Handler handler) throws IOException {
  55         super(url, p, handler);
  56     }
  57 
  58     protected abstract javax.net.ssl.SSLSocketFactory getSSLSocketFactory();
  59 
  60     protected abstract javax.net.ssl.HostnameVerifier getHostnameVerifier();
  61 
  62     /**
  63      * No user application is able to call these routines, as no one
  64      * should ever get access to an instance of
  65      * DelegateHttpsURLConnection (sun.* or com.*)
  66      */
  67 
  68     /**
  69      * Create a new HttpClient object, bypassing the cache of
  70      * HTTP client objects/connections.
  71      *
  72      * Note: this method is changed from protected to public because
  73      * the com.sun.ssl.internal.www.protocol.https handler reuses this
  74      * class for its actual implemantation
  75      *
  76      * @param url the URL being accessed
  77      */
  78     public void setNewClient (URL url)
  79         throws IOException {
  80         setNewClient (url, false);
  81     }
  82 
  83     /**
  84      * Obtain a HttpClient object. Use the cached copy if specified.
  85      *
  86      * Note: this method is changed from protected to public because
  87      * the com.sun.ssl.internal.www.protocol.https handler reuses this
  88      * class for its actual implemantation
  89      *
  90      * @param url       the URL being accessed
  91      * @param useCache  whether the cached connection should be used
  92      *        if present
  93      */
  94     public void setNewClient (URL url, boolean useCache)
  95         throws IOException {
  96         int readTimeout = getReadTimeout();
  97         http = HttpsClient.New (getSSLSocketFactory(),
  98                                 url,
  99                                 getHostnameVerifier(),
 100                                 null,
 101                                 -1,
 102                                 useCache,
 103                                 getConnectTimeout(),
 104                                 this);
 105         http.setReadTimeout(readTimeout);
 106         ((HttpsClient)http).afterConnect();
 107     }
 108 
 109     /**
 110      * Create a new HttpClient object, set up so that it uses
 111      * per-instance proxying to the given HTTP proxy.  This
 112      * bypasses the cache of HTTP client objects/connections.
 113      *
 114      * Note: this method is changed from protected to public because
 115      * the com.sun.ssl.internal.www.protocol.https handler reuses this
 116      * class for its actual implemantation
 117      *
 118      * @param url       the URL being accessed
 119      * @param proxyHost the proxy host to use
 120      * @param proxyPort the proxy port to use
 121      */
 122     public void setProxiedClient (URL url, String proxyHost, int proxyPort)
 123             throws IOException {
 124         setProxiedClient(url, proxyHost, proxyPort, false);
 125     }
 126 
 127     /**
 128      * Obtain a HttpClient object, set up so that it uses per-instance
 129      * proxying to the given HTTP proxy. Use the cached copy of HTTP
 130      * client objects/connections if specified.
 131      *
 132      * Note: this method is changed from protected to public because
 133      * the com.sun.ssl.internal.www.protocol.https handler reuses this
 134      * class for its actual implemantation
 135      *
 136      * @param url       the URL being accessed
 137      * @param proxyHost the proxy host to use
 138      * @param proxyPort the proxy port to use
 139      * @param useCache  whether the cached connection should be used
 140      *        if present
 141      */
 142     public void setProxiedClient (URL url, String proxyHost, int proxyPort,
 143             boolean useCache) throws IOException {
 144         proxiedConnect(url, proxyHost, proxyPort, useCache);
 145         if (!http.isCachedConnection()) {
 146             doTunneling();
 147         }
 148         ((HttpsClient)http).afterConnect();
 149     }
 150 
 151     protected void proxiedConnect(URL url, String proxyHost, int proxyPort,
 152             boolean useCache) throws IOException {
 153         if (connected)
 154             return;
 155         int readTimeout = getReadTimeout();
 156         http = HttpsClient.New (getSSLSocketFactory(),
 157                                 url,
 158                                 getHostnameVerifier(),
 159                                 proxyHost,
 160                                 proxyPort,
 161                                 useCache,
 162                                 getConnectTimeout(),
 163                                 this);
 164         http.setReadTimeout(readTimeout);
 165         connected = true;
 166     }
 167 
 168     /**
 169      * Used by subclass to access "connected" variable.
 170      */
 171     public boolean isConnected() {
 172         return connected;
 173     }
 174 
 175     /**
 176      * Used by subclass to access "connected" variable.
 177      */
 178     public void setConnected(boolean conn) {
 179         connected = conn;
 180     }
 181 
 182     /**
 183      * Implements the HTTP protocol handler's "connect" method,
 184      * establishing an SSL connection to the server as necessary.
 185      */
 186     public void connect() throws IOException {
 187         if (connected)
 188             return;
 189         plainConnect();
 190         if (cachedResponse != null) {
 191             // using cached response
 192             return;
 193         }
 194         if (!http.isCachedConnection() && http.needsTunneling()) {
 195             doTunneling();
 196         }
 197         ((HttpsClient)http).afterConnect();
 198     }
 199 
 200     // will try to use cached HttpsClient
 201     protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
 202         throws IOException {
 203         return HttpsClient.New(getSSLSocketFactory(), url,
 204                                getHostnameVerifier(), p, true, connectTimeout,
 205                                this);
 206     }
 207 
 208     // will open new connection
 209     protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout,
 210                                           boolean useCache)
 211         throws IOException {
 212         return HttpsClient.New(getSSLSocketFactory(), url,
 213                                getHostnameVerifier(), p,
 214                                useCache, connectTimeout, this);
 215     }
 216 
 217     /**
 218      * Returns the cipher suite in use on this connection.
 219      */
 220     public String getCipherSuite () {
 221         if (cachedResponse != null) {
 222             return ((SecureCacheResponse)cachedResponse).getCipherSuite();
 223         }
 224         if (http == null) {
 225             throw new IllegalStateException("connection not yet open");
 226         } else {
 227            return ((HttpsClient)http).getCipherSuite ();
 228         }
 229     }
 230 
 231     /**
 232      * Returns the certificate chain the client sent to the
 233      * server, or null if the client did not authenticate.
 234      */
 235     public java.security.cert.Certificate[] getLocalCertificates() {
 236         if (cachedResponse != null) {
 237             List<java.security.cert.Certificate> l = ((SecureCacheResponse)cachedResponse).getLocalCertificateChain();
 238             if (l == null) {
 239                 return null;
 240             } else {
 241                 return l.toArray(new java.security.cert.Certificate[0]);
 242             }
 243         }
 244         if (http == null) {
 245             throw new IllegalStateException("connection not yet open");
 246         } else {
 247             return (((HttpsClient)http).getLocalCertificates ());
 248         }
 249     }
 250 
 251     /**
 252      * Returns the server's certificate chain, or throws
 253      * SSLPeerUnverified Exception if
 254      * the server did not authenticate.
 255      */
 256     public java.security.cert.Certificate[] getServerCertificates()
 257             throws SSLPeerUnverifiedException {
 258         if (cachedResponse != null) {
 259             List<java.security.cert.Certificate> l = ((SecureCacheResponse)cachedResponse).getServerCertificateChain();
 260             if (l == null) {
 261                 return null;
 262             } else {
 263                 return l.toArray(new java.security.cert.Certificate[0]);
 264             }
 265         }
 266 
 267         if (http == null) {
 268             throw new IllegalStateException("connection not yet open");
 269         } else {
 270             return (((HttpsClient)http).getServerCertificates ());
 271         }
 272     }
 273 
 274     /**
 275      * Returns the server's X.509 certificate chain, or null if
 276      * the server did not authenticate.
 277      */
 278     public javax.security.cert.X509Certificate[] getServerCertificateChain()
 279             throws SSLPeerUnverifiedException {
 280         if (cachedResponse != null) {
 281             throw new UnsupportedOperationException("this method is not supported when using cache");
 282         }
 283         if (http == null) {
 284             throw new IllegalStateException("connection not yet open");
 285         } else {
 286             return ((HttpsClient)http).getServerCertificateChain ();
 287         }
 288     }
 289 
 290     /**
 291      * Returns the server's principal, or throws SSLPeerUnverifiedException
 292      * if the server did not authenticate.
 293      */
 294     Principal getPeerPrincipal()
 295             throws SSLPeerUnverifiedException
 296     {
 297         if (cachedResponse != null) {
 298             return ((SecureCacheResponse)cachedResponse).getPeerPrincipal();
 299         }
 300 
 301         if (http == null) {
 302             throw new IllegalStateException("connection not yet open");
 303         } else {
 304             return (((HttpsClient)http).getPeerPrincipal());
 305         }
 306     }
 307 
 308     /**
 309      * Returns the principal the client sent to the
 310      * server, or null if the client did not authenticate.
 311      */
 312     Principal getLocalPrincipal()
 313     {
 314         if (cachedResponse != null) {
 315             return ((SecureCacheResponse)cachedResponse).getLocalPrincipal();
 316         }
 317 
 318         if (http == null) {
 319             throw new IllegalStateException("connection not yet open");
 320         } else {
 321             return (((HttpsClient)http).getLocalPrincipal());
 322         }
 323     }
 324 
 325 }