1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17package com.squareup.okhttp.internal.http;
18
19import com.squareup.okhttp.OkHttpClient;
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.OutputStream;
23import java.net.HttpURLConnection;
24import java.net.ProtocolException;
25import java.net.SecureCacheResponse;
26import java.net.URL;
27import java.security.Permission;
28import java.security.Principal;
29import java.security.cert.Certificate;
30import java.util.List;
31import java.util.Map;
32import javax.net.ssl.HostnameVerifier;
33import javax.net.ssl.HttpsURLConnection;
34import javax.net.ssl.SSLPeerUnverifiedException;
35import javax.net.ssl.SSLSocket;
36import javax.net.ssl.SSLSocketFactory;
37
38public final class HttpsURLConnectionImpl extends HttpsURLConnection {
39
40  /** HttpUrlConnectionDelegate allows reuse of HttpURLConnectionImpl. */
41  private final HttpUrlConnectionDelegate delegate;
42
43  public HttpsURLConnectionImpl(URL url, OkHttpClient client) {
44    super(url);
45    delegate = new HttpUrlConnectionDelegate(url, client);
46  }
47
48  @Override public String getCipherSuite() {
49    SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
50    if (cacheResponse != null) {
51      return cacheResponse.getCipherSuite();
52    }
53    SSLSocket sslSocket = getSslSocket();
54    if (sslSocket != null) {
55      return sslSocket.getSession().getCipherSuite();
56    }
57    return null;
58  }
59
60  @Override public Certificate[] getLocalCertificates() {
61    SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
62    if (cacheResponse != null) {
63      List<Certificate> result = cacheResponse.getLocalCertificateChain();
64      return result != null ? result.toArray(new Certificate[result.size()]) : null;
65    }
66    SSLSocket sslSocket = getSslSocket();
67    if (sslSocket != null) {
68      return sslSocket.getSession().getLocalCertificates();
69    }
70    return null;
71  }
72
73  @Override public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException {
74    SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
75    if (cacheResponse != null) {
76      List<Certificate> result = cacheResponse.getServerCertificateChain();
77      return result != null ? result.toArray(new Certificate[result.size()]) : null;
78    }
79    SSLSocket sslSocket = getSslSocket();
80    if (sslSocket != null) {
81      return sslSocket.getSession().getPeerCertificates();
82    }
83    return null;
84  }
85
86  @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
87    SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
88    if (cacheResponse != null) {
89      return cacheResponse.getPeerPrincipal();
90    }
91    SSLSocket sslSocket = getSslSocket();
92    if (sslSocket != null) {
93      return sslSocket.getSession().getPeerPrincipal();
94    }
95    return null;
96  }
97
98  @Override public Principal getLocalPrincipal() {
99    SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
100    if (cacheResponse != null) {
101      return cacheResponse.getLocalPrincipal();
102    }
103    SSLSocket sslSocket = getSslSocket();
104    if (sslSocket != null) {
105      return sslSocket.getSession().getLocalPrincipal();
106    }
107    return null;
108  }
109
110  public HttpEngine getHttpEngine() {
111    return delegate.getHttpEngine();
112  }
113
114  private SSLSocket getSslSocket() {
115    if (delegate.httpEngine == null || !delegate.httpEngine.connected) {
116      throw new IllegalStateException("Connection has not yet been established");
117    }
118    return delegate.httpEngine instanceof HttpsEngine
119        ? ((HttpsEngine) delegate.httpEngine).getSslSocket()
120        : null; // Not HTTPS! Probably an https:// to http:// redirect.
121  }
122
123  @Override public void disconnect() {
124    delegate.disconnect();
125  }
126
127  @Override public InputStream getErrorStream() {
128    return delegate.getErrorStream();
129  }
130
131  @Override public String getRequestMethod() {
132    return delegate.getRequestMethod();
133  }
134
135  @Override public int getResponseCode() throws IOException {
136    return delegate.getResponseCode();
137  }
138
139  @Override public String getResponseMessage() throws IOException {
140    return delegate.getResponseMessage();
141  }
142
143  @Override public void setRequestMethod(String method) throws ProtocolException {
144    delegate.setRequestMethod(method);
145  }
146
147  @Override public boolean usingProxy() {
148    return delegate.usingProxy();
149  }
150
151  @Override public boolean getInstanceFollowRedirects() {
152    return delegate.getInstanceFollowRedirects();
153  }
154
155  @Override public void setInstanceFollowRedirects(boolean followRedirects) {
156    delegate.setInstanceFollowRedirects(followRedirects);
157  }
158
159  @Override public void connect() throws IOException {
160    connected = true;
161    delegate.connect();
162  }
163
164  @Override public boolean getAllowUserInteraction() {
165    return delegate.getAllowUserInteraction();
166  }
167
168  @Override public Object getContent() throws IOException {
169    return delegate.getContent();
170  }
171
172  @SuppressWarnings("unchecked") // Spec does not generify
173  @Override public Object getContent(Class[] types) throws IOException {
174    return delegate.getContent(types);
175  }
176
177  @Override public String getContentEncoding() {
178    return delegate.getContentEncoding();
179  }
180
181  @Override public int getContentLength() {
182    return delegate.getContentLength();
183  }
184
185  @Override public String getContentType() {
186    return delegate.getContentType();
187  }
188
189  @Override public long getDate() {
190    return delegate.getDate();
191  }
192
193  @Override public boolean getDefaultUseCaches() {
194    return delegate.getDefaultUseCaches();
195  }
196
197  @Override public boolean getDoInput() {
198    return delegate.getDoInput();
199  }
200
201  @Override public boolean getDoOutput() {
202    return delegate.getDoOutput();
203  }
204
205  @Override public long getExpiration() {
206    return delegate.getExpiration();
207  }
208
209  @Override public String getHeaderField(int pos) {
210    return delegate.getHeaderField(pos);
211  }
212
213  @Override public Map<String, List<String>> getHeaderFields() {
214    return delegate.getHeaderFields();
215  }
216
217  @Override public Map<String, List<String>> getRequestProperties() {
218    return delegate.getRequestProperties();
219  }
220
221  @Override public void addRequestProperty(String field, String newValue) {
222    delegate.addRequestProperty(field, newValue);
223  }
224
225  @Override public String getHeaderField(String key) {
226    return delegate.getHeaderField(key);
227  }
228
229  @Override public long getHeaderFieldDate(String field, long defaultValue) {
230    return delegate.getHeaderFieldDate(field, defaultValue);
231  }
232
233  @Override public int getHeaderFieldInt(String field, int defaultValue) {
234    return delegate.getHeaderFieldInt(field, defaultValue);
235  }
236
237  @Override public String getHeaderFieldKey(int position) {
238    return delegate.getHeaderFieldKey(position);
239  }
240
241  @Override public long getIfModifiedSince() {
242    return delegate.getIfModifiedSince();
243  }
244
245  @Override public InputStream getInputStream() throws IOException {
246    return delegate.getInputStream();
247  }
248
249  @Override public long getLastModified() {
250    return delegate.getLastModified();
251  }
252
253  @Override public OutputStream getOutputStream() throws IOException {
254    return delegate.getOutputStream();
255  }
256
257  @Override public Permission getPermission() throws IOException {
258    return delegate.getPermission();
259  }
260
261  @Override public String getRequestProperty(String field) {
262    return delegate.getRequestProperty(field);
263  }
264
265  @Override public URL getURL() {
266    return delegate.getURL();
267  }
268
269  @Override public boolean getUseCaches() {
270    return delegate.getUseCaches();
271  }
272
273  @Override public void setAllowUserInteraction(boolean newValue) {
274    delegate.setAllowUserInteraction(newValue);
275  }
276
277  @Override public void setDefaultUseCaches(boolean newValue) {
278    delegate.setDefaultUseCaches(newValue);
279  }
280
281  @Override public void setDoInput(boolean newValue) {
282    delegate.setDoInput(newValue);
283  }
284
285  @Override public void setDoOutput(boolean newValue) {
286    delegate.setDoOutput(newValue);
287  }
288
289  @Override public void setIfModifiedSince(long newValue) {
290    delegate.setIfModifiedSince(newValue);
291  }
292
293  @Override public void setRequestProperty(String field, String newValue) {
294    delegate.setRequestProperty(field, newValue);
295  }
296
297  @Override public void setUseCaches(boolean newValue) {
298    delegate.setUseCaches(newValue);
299  }
300
301  @Override public void setConnectTimeout(int timeoutMillis) {
302    delegate.setConnectTimeout(timeoutMillis);
303  }
304
305  @Override public int getConnectTimeout() {
306    return delegate.getConnectTimeout();
307  }
308
309  @Override public void setReadTimeout(int timeoutMillis) {
310    delegate.setReadTimeout(timeoutMillis);
311  }
312
313  @Override public int getReadTimeout() {
314    return delegate.getReadTimeout();
315  }
316
317  @Override public String toString() {
318    return delegate.toString();
319  }
320
321  @Override public void setFixedLengthStreamingMode(int contentLength) {
322    delegate.setFixedLengthStreamingMode(contentLength);
323  }
324
325  @Override public void setChunkedStreamingMode(int chunkLength) {
326    delegate.setChunkedStreamingMode(chunkLength);
327  }
328
329  @Override public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
330    delegate.client.setHostnameVerifier(hostnameVerifier);
331  }
332
333  @Override public HostnameVerifier getHostnameVerifier() {
334    return delegate.client.getHostnameVerifier();
335  }
336
337  @Override public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
338    delegate.client.setSslSocketFactory(sslSocketFactory);
339  }
340
341  @Override public SSLSocketFactory getSSLSocketFactory() {
342    return delegate.client.getSslSocketFactory();
343  }
344
345  private final class HttpUrlConnectionDelegate extends HttpURLConnectionImpl {
346    private HttpUrlConnectionDelegate(URL url, OkHttpClient client) {
347      super(url, client);
348    }
349
350    @Override public HttpURLConnection getHttpConnectionToCache() {
351      return HttpsURLConnectionImpl.this;
352    }
353
354    public SecureCacheResponse getSecureCacheResponse() {
355      return httpEngine instanceof HttpsEngine
356          ? (SecureCacheResponse) httpEngine.getCacheResponse()
357          : null;
358    }
359  }
360}
361