1/*
2 * Copyright (c) 2001, 2015, 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
26package sun.net.www.protocol.https;
27
28import java.net.URL;
29import java.net.Proxy;
30import java.net.SecureCacheResponse;
31import java.security.Principal;
32import java.io.IOException;
33import java.util.List;
34import javax.net.ssl.SSLPeerUnverifiedException;
35import sun.net.www.http.*;
36import 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 */
45public 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, this);
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, this);
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                               this);
194    }
195
196    // will open new connection
197    protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout,
198                                          boolean useCache)
199        throws IOException {
200        return HttpsClient.New(getSSLSocketFactory(), url,
201                               getHostnameVerifier(), p,
202                               useCache, connectTimeout, this);
203    }
204
205    /**
206     * Returns the cipher suite in use on this connection.
207     */
208    public String getCipherSuite () {
209        if (cachedResponse != null) {
210            return ((SecureCacheResponse)cachedResponse).getCipherSuite();
211        }
212        if (http == null) {
213            throw new IllegalStateException("connection not yet open");
214        } else {
215           return ((HttpsClient)http).getCipherSuite ();
216        }
217    }
218
219    /**
220     * Returns the certificate chain the client sent to the
221     * server, or null if the client did not authenticate.
222     */
223    public java.security.cert.Certificate[] getLocalCertificates() {
224        if (cachedResponse != null) {
225            List<java.security.cert.Certificate> l = ((SecureCacheResponse)cachedResponse).getLocalCertificateChain();
226            if (l == null) {
227                return null;
228            } else {
229                return l.toArray(new java.security.cert.Certificate[0]);
230            }
231        }
232        if (http == null) {
233            throw new IllegalStateException("connection not yet open");
234        } else {
235            return (((HttpsClient)http).getLocalCertificates ());
236        }
237    }
238
239    /**
240     * Returns the server's certificate chain, or throws
241     * SSLPeerUnverified Exception if
242     * the server did not authenticate.
243     */
244    public java.security.cert.Certificate[] getServerCertificates()
245            throws SSLPeerUnverifiedException {
246        if (cachedResponse != null) {
247            List<java.security.cert.Certificate> l =
248                    ((SecureCacheResponse)cachedResponse)
249                            .getServerCertificateChain();
250            if (l == null) {
251                return null;
252            } else {
253                return l.toArray(new java.security.cert.Certificate[0]);
254            }
255        }
256
257        if (http == null) {
258            throw new IllegalStateException("connection not yet open");
259        } else {
260            return (((HttpsClient)http).getServerCertificates ());
261        }
262    }
263
264    /**
265     * Returns the server's principal, or throws SSLPeerUnverifiedException
266     * if the server did not authenticate.
267     */
268    Principal getPeerPrincipal()
269            throws SSLPeerUnverifiedException
270    {
271        if (cachedResponse != null) {
272            return ((SecureCacheResponse)cachedResponse).getPeerPrincipal();
273        }
274
275        if (http == null) {
276            throw new IllegalStateException("connection not yet open");
277        } else {
278            return (((HttpsClient)http).getPeerPrincipal());
279        }
280    }
281
282    /**
283     * Returns the principal the client sent to the
284     * server, or null if the client did not authenticate.
285     */
286    Principal getLocalPrincipal()
287    {
288        if (cachedResponse != null) {
289            return ((SecureCacheResponse)cachedResponse).getLocalPrincipal();
290        }
291
292        if (http == null) {
293            throw new IllegalStateException("connection not yet open");
294        } else {
295            return (((HttpsClient)http).getLocalPrincipal());
296        }
297    }
298
299}
300