1

I am trying to send get request to a server (sending get request for testing, actually I need to send a post request to same server. If get works, post will work)

link to server is https://bits-bosm.org/2017/registrations/signup/

The problem is when I send request using okHttp, I get a failure response saying Handshake failed.

Here is the code I am using to send the request using okHttp (in kotlin)

val request = Request.Builder()
            .url("https://bits-bosm.org/2017/registrations/signup/")
            .build()

    okHttpClient.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call?, e: IOException?) {
            val mMessage = e?.message?.toString()
            Log.w("failure Response", mMessage)
        }

        override fun onResponse(call: Call?, response: Response?) {
            val mMessage = response?.body()?.string()
            Log.e("Message", mMessage)
        }
    })

But if I use HttpUrlConnection to send the get request to the same server, I get the response.

Here is the code for the same (java)

private static final String USER_AGENT = "Mozilla/5.0";

private static final String GET_URL = "https://bits-bosm.org/2017/registrations/signup/";



static void sendGET() throws IOException {
    URL obj = new URL(GET_URL);
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();
    con.setRequestMethod("GET");
    con.setRequestProperty("User-Agent", USER_AGENT);
    int responseCode = con.getResponseCode();
    System.out.println("GET Response Code :: " + responseCode);
    if (responseCode == HttpURLConnection.HTTP_OK) { // success
        BufferedReader in = new BufferedReader(new InputStreamReader(
                con.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();

        // print result
        Log.e("Result", response.toString());
    } else {
        System.out.println("GET request not worked");
    }

}

From what I have searched the internet and from what I could deduce, the problem is the site is signed using self certificate, and okHttp disallows them. I have even tried using code snippets which I found on Internet which don't check the certificate (Custom SSLSocketFactory) and a few more solutions but none of them worked. Also I don't care about security right now, I just want to get it worked. But I have no access to backend and cannot change/remove ssl security.

What can do to make it work? Is there something which I am missing?

Vaibhav Maheshwari
  • 384
  • 1
  • 4
  • 18

1 Answers1

5

Here's the insecure OkHttpClient widely used as a workaround.

Do not use it on production, it's merely for dev purposes.

import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;

public class Http {

    private final static String SSL = "SSL";

    private static OkHttpClient InsecureHttpClient;

    public static OkHttpClient client () {
        if (InsecureHttpClient == null) {
            try {
                InsecureHttpClient = insecureOkHttpClient ();
            } catch (Exception e) {
                e.printStackTrace ();
            }
        }

        return InsecureHttpClient;
    }

    private static OkHttpClient insecureOkHttpClient () throws Exception {
        TrustManager [] trustAllCerts       = new TrustManager [] { trustManager () };

        SSLContext sslContext               = SSLContext.getInstance (SSL);
        sslContext.init (null, trustAllCerts, new SecureRandom ());

        SSLSocketFactory sslSocketFactory   = sslContext.getSocketFactory ();

        OkHttpClient.Builder builder        = new OkHttpClient.Builder ();
        builder.sslSocketFactory (sslSocketFactory, (X509TrustManager)trustAllCerts [0]);
        builder.hostnameVerifier (hostnameVerifier ());

        return builder.build ();
    }

    private static TrustManager trustManager () {
        return new X509TrustManager () {

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

            @Override
            public void checkServerTrusted (X509Certificate[] chain, String authType) throws CertificateException {  }

            @Override
            public X509Certificate [] getAcceptedIssuers () {
                return new X509Certificate [] {  };
            }
        };
    }

    private static HostnameVerifier hostnameVerifier () {
        return new HostnameVerifier () {

            @Override
            public boolean verify (String hostname, SSLSession session) {
                return true;
            }
        };
    }
}

You then obviously use the above client like the following test code for example: (which, by the way, works with your url)

final Request request = new Request.Builder ()
    .url ("https://bits-bosm.org/2017/registrations/signup/")
    .get ()
    .addHeader ("Accept", "text/html")
    .build ();

final OkHttpClient httpClient = Http.client ();

new Thread (new Runnable () {

    @Override
    public void run () {
        try {
            Response response = httpClient.newCall (request).execute ();

            Logger.error (MainActivity.class.getSimpleName () + " --> Http Response", response.body ().string ());

        } catch (IOException e) {
            e.printStackTrace ();
        }
    }

}).start ();
  • As I said, I have already tried this and this is not working. It still gives handshake failed as error. I have also provided the URL in case you need it – Vaibhav Maheshwari Aug 22 '17 at 15:01
  • You obviously haven't tested it. I just did and it works. See my test code on my edited answer. –  Aug 22 '17 at 15:13
  • Thanks for response. Well I did tried it before commenting, but It didn't worked. While searching for the solution for this problem, I found that there were some changes in Android N which probably prevented this. I am using API 24 so maybe this isn't working because of that. On which API have you tried this? Also can you please confirm it working for API >= 24? – Vaibhav Maheshwari Aug 22 '17 at 15:31
  • @VaibhavMaheshwari, Yes it does work for APIs >= 24. I have tested it on the API 25, should be all good for the rest :) –  Aug 22 '17 at 15:35
  • Oh! I got it. API 24 has a bug which prevented this and I was trying this on API 24 only for last 12 hours. Just found https://stackoverflow.com/questions/39133437/sslhandshakeexception-handshake-failed-on-android-n-7-0 which explained this. I tried it on API 25 and it worked. Thank you! btw is there any workaround for API 24 on the android side? – Vaibhav Maheshwari Aug 22 '17 at 16:09
  • Hmm, interesting. I wasn't aware of that regression so I'm not sure about any workaround doable on the Android side. From what I've read on that post, the workarounds are mainly on the server-side. –  Aug 22 '17 at 16:15