1 /*
   2  * Copyright (c) 2001, 2006, 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         http = HttpsClient.New (getSSLSocketFactory(),
  97                                 url,
  98                                 getHostnameVerifier(),
  99                                 useCache);
 100         ((HttpsClient)http).afterConnect();
 101     }
 102 
 103     /**
 104      * Create a new HttpClient object, set up so that it uses
 105      * per-instance proxying to the given HTTP proxy.  This
 106      * bypasses the cache of HTTP client objects/connections.
 107      *
 108      * Note: this method is changed from protected to public because
 109      * the com.sun.ssl.internal.www.protocol.https handler reuses this
 110      * class for its actual implemantation
 111      *
 112      * @param url       the URL being accessed
 113      * @param proxyHost the proxy host to use
 114      * @param proxyPort the proxy port to use
 115      */
 116     public void setProxiedClient (URL url, String proxyHost, int proxyPort)
 117             throws IOException {
 118         setProxiedClient(url, proxyHost, proxyPort, false);
 119     }
 120 
 121     /**
 122      * Obtain a HttpClient object, set up so that it uses per-instance
 123      * proxying to the given HTTP proxy. Use the cached copy of HTTP
 124      * client objects/connections if specified.
 125      *
 126      * Note: this method is changed from protected to public because
 127      * the com.sun.ssl.internal.www.protocol.https handler reuses this
 128      * class for its actual implemantation
 129      *
 130      * @param url       the URL being accessed
 131      * @param proxyHost the proxy host to use
 132      * @param proxyPort the proxy port to use
 133      * @param useCache  whether the cached connection should be used
 134      *        if present
 135      */
 136     public void setProxiedClient (URL url, String proxyHost, int proxyPort,
 137             boolean useCache) throws IOException {
 138         proxiedConnect(url, proxyHost, proxyPort, useCache);
 139         if (!http.isCachedConnection()) {
 140             doTunneling();
 141         }
 142         ((HttpsClient)http).afterConnect();
 143     }
 144 
 145     protected void proxiedConnect(URL url, String proxyHost, int proxyPort,
 146             boolean useCache) throws IOException {
 147         if (connected)
 148             return;
 149         http = HttpsClient.New (getSSLSocketFactory(),
 150                                 url,
 151                                 getHostnameVerifier(),
 152                                 proxyHost, proxyPort, useCache);
 153         connected = true;
 154     }
 155 
 156     /**
 157      * Used by subclass to access "connected" variable.
 158      */
 159     public boolean isConnected() {
 160         return connected;
 161     }
 162 
 163     /**
 164      * Used by subclass to access "connected" variable.
 165      */
 166     public void setConnected(boolean conn) {
 167         connected = conn;
 168     }
 169 
 170     /**
 171      * Implements the HTTP protocol handler's "connect" method,
 172      * establishing an SSL connection to the server as necessary.
 173      */
 174     public void connect() throws IOException {
 175         if (connected)
 176             return;
 177         plainConnect();
 178         if (cachedResponse != null) {
 179             // using cached response
 180             return;
 181         }
 182         if (!http.isCachedConnection() && http.needsTunneling()) {
 183             doTunneling();
 184         }
 185         ((HttpsClient)http).afterConnect();
 186     }
 187 
 188     // will try to use cached HttpsClient
 189     protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
 190         throws IOException {
 191         return HttpsClient.New(getSSLSocketFactory(), url,
 192                                getHostnameVerifier(), p, true, connectTimeout);
 193     }
 194 
 195     // will open new connection
 196     protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout,
 197                                           boolean useCache)
 198         throws IOException {
 199         return HttpsClient.New(getSSLSocketFactory(), url,
 200                                getHostnameVerifier(), p,
 201                                useCache, connectTimeout);
 202     }
 203 
 204     /**
 205      * Returns the cipher suite in use on this connection.
 206      */
 207     public String getCipherSuite () {
 208         if (cachedResponse != null) {
 209             return ((SecureCacheResponse)cachedResponse).getCipherSuite();
 210         }
 211         if (http == null) {
 212             throw new IllegalStateException("connection not yet open");
 213         } else {
 214            return ((HttpsClient)http).getCipherSuite ();
 215         }
 216     }
 217 
 218     /**
 219      * Returns the certificate chain the client sent to the
 220      * server, or null if the client did not authenticate.
 221      */
 222     public java.security.cert.Certificate[] getLocalCertificates() {
 223         if (cachedResponse != null) {
 224             List l = ((SecureCacheResponse)cachedResponse).getLocalCertificateChain();
 225             if (l == null) {
 226                 return null;
 227             } else {
 228                 return (java.security.cert.Certificate[])l.toArray();
 229             }
 230         }
 231         if (http == null) {
 232             throw new IllegalStateException("connection not yet open");
 233         } else {
 234             return (((HttpsClient)http).getLocalCertificates ());
 235         }
 236     }
 237 
 238     /**
 239      * Returns the server's certificate chain, or throws
 240      * SSLPeerUnverified Exception if
 241      * the server did not authenticate.
 242      */
 243     public java.security.cert.Certificate[] getServerCertificates()
 244             throws SSLPeerUnverifiedException {
 245         if (cachedResponse != null) {
 246             List l = ((SecureCacheResponse)cachedResponse).getServerCertificateChain();
 247             if (l == null) {
 248                 return null;
 249             } else {
 250                 return (java.security.cert.Certificate[])l.toArray();
 251             }
 252         }
 253 
 254         if (http == null) {
 255             throw new IllegalStateException("connection not yet open");
 256         } else {
 257             return (((HttpsClient)http).getServerCertificates ());
 258         }
 259     }
 260 
 261     /**
 262      * Returns the server's X.509 certificate chain, or null if
 263      * the server did not authenticate.
 264      */
 265     public javax.security.cert.X509Certificate[] getServerCertificateChain()
 266             throws SSLPeerUnverifiedException {
 267         if (cachedResponse != null) {
 268             throw new UnsupportedOperationException("this method is not supported when using cache");
 269         }
 270         if (http == null) {
 271             throw new IllegalStateException("connection not yet open");
 272         } else {
 273             return ((HttpsClient)http).getServerCertificateChain ();
 274         }
 275     }
 276 
 277     /**
 278      * Returns the server's principal, or throws SSLPeerUnverifiedException
 279      * if the server did not authenticate.
 280      */
 281     Principal getPeerPrincipal()
 282             throws SSLPeerUnverifiedException
 283     {
 284         if (cachedResponse != null) {
 285             return ((SecureCacheResponse)cachedResponse).getPeerPrincipal();
 286         }
 287 
 288         if (http == null) {
 289             throw new IllegalStateException("connection not yet open");
 290         } else {
 291             return (((HttpsClient)http).getPeerPrincipal());
 292         }
 293     }
 294 
 295     /**
 296      * Returns the principal the client sent to the
 297      * server, or null if the client did not authenticate.
 298      */
 299     Principal getLocalPrincipal()
 300     {
 301         if (cachedResponse != null) {
 302             return ((SecureCacheResponse)cachedResponse).getLocalPrincipal();
 303         }
 304 
 305         if (http == null) {
 306             throw new IllegalStateException("connection not yet open");
 307         } else {
 308             return (((HttpsClient)http).getLocalPrincipal());
 309         }
 310     }
 311 
 312 }