androidandroid-networkingandroidhttpclient

How to handle IOException using https connection in Android?


I have using Https enabled services to fetch data from server. Here I am using self-signed method for creating httpClient. Application working fine but sometimes I am getting IOExcetion and my api call is failing. I am not able to fetch data from server. I have used ConnectionTimeOut, SocketTimeouts for my httpClient. I don't why my api calling failed in some cases. How can I avoid IOException while working with https:// api calling?

Here I have attached my code for self-signed process.

SSLFactory class :

public class MySSLSocketFactory extends SSLSocketFactory{
     SSLContext sslContext = SSLContext.getInstance("TLS");
     public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, 
     KeyManagementException, KeyStoreException, UnrecoverableKeyException {
         super(truststore);

         TrustManager tm = new X509TrustManager() {

             public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                 return null;
             }
                         

                         @Override
                         public void checkClientTrusted(
                                         java.security.cert.X509Certificate[] chain,
                                         String authType)
                                         throws java.security.cert.CertificateException {
                         }

                         @Override
                         public void checkServerTrusted(
                                         java.security.cert.X509Certificate[] chain,
                                         String authType)
                                         throws java.security.cert.CertificateException {
                         }
         };

         sslContext.init(null, new TrustManager[] { tm }, null);
     }
    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

and my httpClient object method is follows:

public HttpClient getNewHttpClient(boolean containsTimeout) {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
            if(containsTimeout)
            {
                int timeout = 60000;
                HttpConnectionParams.setConnectionTimeout(params, timeout);

                HttpConnectionParams.setSoTimeout(params, timeout);
            }
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 8443));
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }

And my api calling method is

HttpClient httpclient = getNewHttpClient(true);
            HttpPost httppost = new HttpPost(url);
            httppost.setHeader("Content-Type", "text/xml");
        BasicHttpResponse httpResponse = null;
            httpResponse = (BasicHttpResponse) httpclient.execute(httppost);
        InputStream is = httpResponse.getEntity().getContent();

In the above code is (InputStream) is my final result.

I am not getting final result atleast 2 out of 10 iterations. How can I avoid IOException?


Solution

  • First create a class name EasySSLSocketFactory

    public class EasySSLSocketFactory implements SocketFactory,
            LayeredSocketFactory {
    
        private SSLContext sslcontext = null;
    
        private static SSLContext createEasySSLContext() throws IOException {
            try {
                SSLContext context = SSLContext.getInstance("TLS");
                context.init(null, new TrustManager[] { new EasyX509TrustManager(
                        null) }, null);
                return context;
            } catch (Exception e) {
                throw new IOException(e.getMessage());
            }
        }
    
        private SSLContext getSSLContext() throws IOException {
            if (this.sslcontext == null) {
                this.sslcontext = createEasySSLContext();
            }
            return this.sslcontext;
        }
    
        /**
         * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket,
         *      java.lang.String, int, java.net.InetAddress, int,
         *      org.apache.http.params.HttpParams)
         */
        public Socket connectSocket(Socket sock, String host, int port,
                InetAddress localAddress, int localPort, HttpParams params)
                throws IOException, UnknownHostException, ConnectTimeoutException {
            int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
            int soTimeout = HttpConnectionParams.getSoTimeout(params);
            InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
            SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
    
            if ((localAddress != null) || (localPort > 0)) {
                // we need to bind explicitly
                if (localPort < 0) {
                    localPort = 0; // indicates "any"
                }
                InetSocketAddress isa = new InetSocketAddress(localAddress,
                        localPort);
                sslsock.bind(isa);
            }
    
            sslsock.connect(remoteAddress, connTimeout);
            sslsock.setSoTimeout(soTimeout);
            return sslsock;
    
        }
    
        /**
         * @see org.apache.http.conn.scheme.SocketFactory#createSocket()
         */
        public Socket createSocket() throws IOException {
            return getSSLContext().getSocketFactory().createSocket();
        }
    
        /**
         * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
         */
        public boolean isSecure(Socket socket) throws IllegalArgumentException {
            return true;
        }
    
        /**
         * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket,
         *      java.lang.String, int, boolean)
         */
        public Socket createSocket(Socket socket, String host, int port,
                boolean autoClose) throws IOException, UnknownHostException {
            return getSSLContext().getSocketFactory().createSocket(socket, host,
                    port, autoClose);
        }
    
        // -------------------------------------------------------------------
        // javadoc in org.apache.http.conn.scheme.SocketFactory says :
        // Both Object.equals() and Object.hashCode() must be overridden
        // for the correct operation of some connection managers
        // -------------------------------------------------------------------
    
        public boolean equals(Object obj) {
            return ((obj != null) && obj.getClass().equals(
                    EasySSLSocketFactory.class));
        }
    
        public int hashCode() {
            return EasySSLSocketFactory.class.hashCode();
        }
    
    }
    

    Then implement X509 Trust Manager

    public class EasyX509TrustManager implements X509TrustManager {
    
        private X509TrustManager standardTrustManager = null;
    
        /**
         * Constructor for EasyX509TrustManager.
         */
        public EasyX509TrustManager(KeyStore keystore)
                throws NoSuchAlgorithmException, KeyStoreException {
            super();
            TrustManagerFactory factory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            factory.init(keystore);
            TrustManager[] trustmanagers = factory.getTrustManagers();
            if (trustmanagers.length == 0) {
                throw new NoSuchAlgorithmException("no trust manager found");
            }
            this.standardTrustManager = (X509TrustManager) trustmanagers[0];
        }
    
        /**
         * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],
         *      String authType)
         */
        public void checkClientTrusted(X509Certificate[] certificates,
                String authType) throws CertificateException {
            standardTrustManager.checkClientTrusted(certificates, authType);
        }
    
        /**
         * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
         *      String authType)
         */
        public void checkServerTrusted(X509Certificate[] certificates,
                String authType) throws CertificateException {
            if ((certificates != null) && (certificates.length == 1)) {
                certificates[0].checkValidity();
            } else {
                standardTrustManager.checkServerTrusted(certificates, authType);
            }
        }
    
        /**
         * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
         */
        public X509Certificate[] getAcceptedIssuers() {
            return this.standardTrustManager.getAcceptedIssuers();
        }
    
    }
    

    Now you can get your content

    public class GetContent{
    
        private ClientConnectionManager clientConnectionManager = null;
        private HttpContext context = null;
        private HttpParams params = null;
    
        public GetContent() {
            setup();
        }
    
        private HttpResponse getResponseFromUrl(String url) {
    
            HttpResponse response = null;
            try {
    
                HttpConnectionParams.setConnectionTimeout(params, 300000);
                HttpConnectionParams.setSoTimeout(params, 300000);
    
                // connection (client has to be created for every new connection)
                HttpClient client = new DefaultHttpClient(clientConnectionManager,
                        params);
                HttpGet get = new HttpGet(url);
    
                response = client.execute(get, context);
    
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
    
            }
            return response;
        }
    
        public ClientConnectionManager getClientConnectionManager() {
            return clientConnectionManager;
        }
    
        public HttpParams getHttpParams() {
            return params;
        }
    
        public HttpContext getHttpContext() {
            return context;
        }
    
        public InputStream getInputStream(final Context context, String url) {
    
            InputStream is = null;
    
            try {
    
                HttpResponse response = getResponseFromUrl(url);
                if (response != null) {
                    HttpEntity entity = response.getEntity();
    
                    if (entity != null) 
    
                        is = entity.getContent();
    
                        return is;
                       }
            } catch (ClientProtocolException e) {
    
                Log.e("log_tag", "Error in http connection " + e.toString());
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } catch (JSONException e) {
                Log.e("log_tag", "Error parsing data " + e.toString());
                return null;
            }
    
            return null;
    
        }
    
        private final void setup() {
    
            SchemeRegistry schemeRegistry = new SchemeRegistry();
    
            // http scheme
            schemeRegistry.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 80));
            // https scheme
            schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(),
                    443));
    
            params = new BasicHttpParams();
            params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
            params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE,
                    new ConnPerRouteBean(1));
            params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
    
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, "utf8");
    
            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            // set the user credentials for our site "example.com"
            credentialsProvider.setCredentials(new AuthScope("example.com",
                    AuthScope.ANY_PORT), new UsernamePasswordCredentials(
                    "UserNameHere", "UserPasswordHere"));
            clientConnectionManager = new ThreadSafeClientConnManager(params,
                    schemeRegistry);
    
            context = new BasicHttpContext();
            context.setAttribute("http.auth.credentials-provider",
                    credentialsProvider);
    
        }
    
    }
    

    This is How to get InputStream

    GetContent content =new GetContent();
    InputStream is = content.getInputStream(this,MY_URL);