19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.net.http; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 20886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport android.util.Log; 21886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport org.apache.harmony.xnet.provider.jsse.FileClientSessionCache; 223c7c351a6217ac48b741740167c201a679a0ca65Brian Carlstromimport org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl; 23886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.Header; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpException; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpHost; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpStatus; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.ParseException; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.ProtocolVersion; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.StatusLine; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.message.BasicHttpRequest; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.params.BasicHttpParams; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.params.HttpConnectionParams; 34886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport org.apache.http.params.HttpParams; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 36886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport javax.net.ssl.SSLException; 37886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport javax.net.ssl.SSLSocket; 38886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport javax.net.ssl.SSLSocketFactory; 39886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport javax.net.ssl.TrustManager; 40886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport javax.net.ssl.X509TrustManager; 41886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport java.io.File; 42886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport java.io.IOException; 43886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport java.net.InetSocketAddress; 44886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport java.net.Socket; 45886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport java.security.KeyManagementException; 46886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeimport java.security.cert.X509Certificate; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A Connection connecting to a secure http server or tunneling through 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a http proxy server to a https server. 51886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * 52886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * @hide 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 54886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leepublic class HttpsConnection extends Connection { 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SSL socket factory 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static SSLSocketFactory mSslSocketFactory = null; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 6237254dcdcf9f9eee9c61e124d23f2cb7114adedaBrian Carlstrom // This initialization happens in the zygote. It triggers some 63886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee // lazy initialization that can will benefit later invocations of 64886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee // initializeEngine(). 65886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee initializeEngine(null); 66886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } 67886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 68886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee /** 69886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * @hide 70886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * 71886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * @param sessionDir directory to cache SSL sessions 72886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee */ 73886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee public static void initializeEngine(File sessionDir) { 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 75886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee SSLClientSessionCache cache = null; 76886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee if (sessionDir != null) { 77886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee Log.d("HttpsConnection", "Caching SSL sessions in " 78886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee + sessionDir + "."); 79886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee cache = FileClientSessionCache.usingDirectory(sessionDir); 80886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 823c7c351a6217ac48b741740167c201a679a0ca65Brian Carlstrom OpenSSLContextImpl sslContext = new OpenSSLContextImpl(); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 84886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee // here, trust managers is a single trust-all manager 85886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee TrustManager[] trustManagers = new TrustManager[] { 86886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee new X509TrustManager() { 87886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee public X509Certificate[] getAcceptedIssuers() { 88886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee return null; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 91886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee public void checkClientTrusted( 92886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee X509Certificate[] certs, String authType) { 93886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } 94886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 95886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee public void checkServerTrusted( 96886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee X509Certificate[] certs, String authType) { 97886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } 98886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } 99886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee }; 100886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 1012c42c8fbaf02be1f3ea6298077128d0c419526f0Brian Carlstrom sslContext.engineInit(null, trustManagers, null); 1022c42c8fbaf02be1f3ea6298077128d0c419526f0Brian Carlstrom sslContext.engineGetClientSessionContext().setPersistentCache(cache); 103886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 104886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee synchronized (HttpsConnection.class) { 105886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee mSslSocketFactory = sslContext.engineGetSocketFactory(); 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 107886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } catch (KeyManagementException e) { 108886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee throw new RuntimeException(e); 109886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } catch (IOException e) { 110886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee throw new RuntimeException(e); 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 114886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee private synchronized static SSLSocketFactory getSocketFactory() { 115886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee return mSslSocketFactory; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Object to wait on when suspending the SSL connection 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Object mSuspendLock = new Object(); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * True if the connection is suspended pending the result of asking the 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * user about an error. 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mSuspended = false; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * True if the connection attempt should be aborted due to an ssl 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * error. 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mAborted = false; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13586806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott // Used when connecting through a proxy. 13686806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott private HttpHost mProxyHost; 13786806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Contructor for a https connection. 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14186806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott HttpsConnection(Context context, HttpHost host, HttpHost proxy, 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RequestFeeder requestFeeder) { 14386806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott super(context, host, requestFeeder); 14486806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott mProxyHost = proxy; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the server SSL certificate associated with this 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * connection. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param certificate The SSL certificate 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void setCertificate(SslCertificate certificate) { 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCertificate = certificate; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Opens the connection to a http server or proxy. 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the opened low level connection 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IOException if the connection fails for any reason. 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AndroidHttpClientConnection openConnection(Request req) throws IOException { 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SSLSocket sslSock = null; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16686806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott if (mProxyHost != null) { 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we have a proxy set, we first send a CONNECT request 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to the proxy; if the proxy returns 200 OK, we negotiate 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a secure connection to the target server via the proxy. 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the request fails, we drop it, but provide the event 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handler with the response status and headers. The event 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handler is then responsible for cancelling the load or 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // issueing a new request. 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AndroidHttpClientConnection proxyConnection = null; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Socket proxySock = null; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxySock = new Socket 17886806ce11a89260147d7c2efa2c192b711d923dbPatrick Scott (mProxyHost.getHostName(), mProxyHost.getPort()); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxySock.setSoTimeout(60 * 1000); 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyConnection = new AndroidHttpClientConnection(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpParams params = new BasicHttpParams(); 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpConnectionParams.setSocketBufferSize(params, 8192); 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyConnection.bind(proxySock, params); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch(IOException e) { 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (proxyConnection != null) { 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyConnection.close(); 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String errorMessage = e.getMessage(); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (errorMessage == null) { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project errorMessage = 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "failed to establish a connection to the proxy"; 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IOException(errorMessage); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StatusLine statusLine = null; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int statusCode = 0; 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Headers headers = new Headers(); 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BasicHttpRequest proxyReq = new BasicHttpRequest 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ("CONNECT", mHost.toHostString()); 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 208ea4e597a87b51b8ec19798f3fdedf74a723d75d8Henrik Baard // add all 'proxy' headers from the original request, we also need 209ea4e597a87b51b8ec19798f3fdedf74a723d75d8Henrik Baard // to add 'host' header unless we want proxy to answer us with a 210ea4e597a87b51b8ec19798f3fdedf74a723d75d8Henrik Baard // 400 Bad Request 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Header h : req.mHttpRequest.getAllHeaders()) { 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String headerName = h.getName().toLowerCase(); 213ea4e597a87b51b8ec19798f3fdedf74a723d75d8Henrik Baard if (headerName.startsWith("proxy") || headerName.equals("keep-alive") 214ea4e597a87b51b8ec19798f3fdedf74a723d75d8Henrik Baard || headerName.equals("host")) { 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyReq.addHeader(h); 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyConnection.sendRequestHeader(proxyReq); 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyConnection.flush(); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it is possible to receive informational status 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // codes prior to receiving actual headers; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // all those status codes are smaller than OK 200 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a loop is a standard way of dealing with them 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statusLine = proxyConnection.parseResponseHeader(headers); 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statusCode = statusLine.getStatusCode(); 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (statusCode < HttpStatus.SC_OK); 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (ParseException e) { 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String errorMessage = e.getMessage(); 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (errorMessage == null) { 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project errorMessage = 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "failed to send a CONNECT request"; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IOException(errorMessage); 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (HttpException e) { 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String errorMessage = e.getMessage(); 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (errorMessage == null) { 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project errorMessage = 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "failed to send a CONNECT request"; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IOException(errorMessage); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String errorMessage = e.getMessage(); 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (errorMessage == null) { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project errorMessage = 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "failed to send a CONNECT request"; 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IOException(errorMessage); 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statusCode == HttpStatus.SC_OK) { 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 258886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee sslSock = (SSLSocket) getSocketFactory().createSocket( 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxySock, mHost.getHostName(), mHost.getPort(), true); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch(IOException e) { 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sslSock != null) { 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sslSock.close(); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String errorMessage = e.getMessage(); 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (errorMessage == null) { 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project errorMessage = 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "failed to create an SSL socket"; 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IOException(errorMessage); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if the code is not OK, inform the event handler 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ProtocolVersion version = statusLine.getProtocolVersion(); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project req.mEventHandler.status(version.getMajor(), 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project version.getMinor(), 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statusCode, 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statusLine.getReasonPhrase()); 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project req.mEventHandler.headers(headers); 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project req.mEventHandler.endData(); 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proxyConnection.close(); 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // here, we return null to indicate that the original 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // request needs to be dropped 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we do not have a proxy, we simply connect to the host 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 29279ae37086b277765001a0d2da3fd058e9fa73abfLorenzo Colitti sslSock = (SSLSocket) getSocketFactory().createSocket( 29379ae37086b277765001a0d2da3fd058e9fa73abfLorenzo Colitti mHost.getHostName(), mHost.getPort()); 294886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee sslSock.setSoTimeout(SOCKET_TIMEOUT); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch(IOException e) { 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sslSock != null) { 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sslSock.close(); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String errorMessage = e.getMessage(); 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (errorMessage == null) { 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project errorMessage = "failed to create an SSL socket"; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IOException(errorMessage); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // do handshake and validate server certificates 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SslError error = CertificateChainValidator.getInstance(). 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project doHandshakeAndValidateServerCertificates(this, sslSock, mHost.getHostName()); 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Inform the user if there is a problem 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (error != null) { 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handleSslErrorRequest may immediately unsuspend if it wants to 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // allow the certificate anyway. 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // So we mark the connection as suspended, call handleSslErrorRequest 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // then check if we're still suspended and only wait if we actually 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to. 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSuspendLock) { 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSuspended = true; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // don't hold the lock while calling out to the event handler 324dba8cb76371960457e91b31fa396478f809a5a34Brian Carlstrom boolean canHandle = req.getEventHandler().handleSslErrorRequest(error); 3254c8db8a4feb2afbd9d5f94ff09c7167ca34076c4Grace Kloba if(!canHandle) { 3264c8db8a4feb2afbd9d5f94ff09c7167ca34076c4Grace Kloba throw new IOException("failed to handle "+ error); 3274c8db8a4feb2afbd9d5f94ff09c7167ca34076c4Grace Kloba } 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSuspendLock) { 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSuspended) { 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Put a limit on how long we are waiting; if the timeout 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // expires (which should never happen unless you choose 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to ignore the SSL error dialog for a very long time), 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we wake up the thread and abort the request. This is 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to prevent us from stalling the network if things go 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // very bad. 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSuspendLock.wait(10 * 60 * 1000); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSuspended) { 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mSuspended is true if we have not had a chance to 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // restart the connection yet (ie, the wait timeout 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // has expired) 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSuspended = false; 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAborted = true; 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (HttpLog.LOGV) { 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpLog.v("HttpsConnection.openConnection():" + 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " SSL timeout expired and request was cancelled!!!"); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAborted) { 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The user decided not to use this unverified connection 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // so close it immediately. 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sslSock.close(); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new SSLConnectionClosedByUserException("connection closed by the user"); 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // All went well, we have an open, verified connection. 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AndroidHttpClientConnection conn = new AndroidHttpClientConnection(); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BasicHttpParams params = new BasicHttpParams(); 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project conn.bind(sslSock, params); 367886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return conn; 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Closes the low level connection. 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If an exception is thrown then it is assumed that the connection will 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * have been closed (to the extent possible) anyway and the caller does not 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * need to take any further action. 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void closeConnection() { 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if the connection has been suspended due to an SSL error 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSuspended) { 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // wake up the network thread 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project restartConnection(false); 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHttpClientConnection.close(); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (HttpLog.LOGV) 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpLog.v("HttpsConnection.closeConnection():" + 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " failed closing connection " + mHost); 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Restart a secure connection suspended waiting for user interaction. 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void restartConnection(boolean proceed) { 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (HttpLog.LOGV) { 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpLog.v("HttpsConnection.restartConnection():" + 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " proceed: " + proceed); 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSuspendLock) { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSuspended) { 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSuspended = false; 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAborted = !proceed; 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSuspendLock.notify(); 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String getScheme() { 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "https"; 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 422886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 423886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee/** 424886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * Simple exception we throw if the SSL connection is closed by the user. 425886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * 426886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee * {@hide} 427886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee */ 428886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Leeclass SSLConnectionClosedByUserException extends SSLException { 429886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee 430886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee public SSLConnectionClosedByUserException(String reason) { 431886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee super(reason); 432886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee } 433886f3d69b79748fe937725e33b8bbb3d67ab82c7Bob Lee} 434