Apache HTTP Client Android Exception on Execute only for LG G3 6.0

雨燕双飞 提交于 2019-12-05 05:12:06

问题


I've taken over an android app that takes pictures and attaches them to jobs for a larger software system at a company's home base- it has worked fine until recently.

It seems that only on LG G3 phones that have upgraded to Android 6.0 there is an exception in this prodecure:

public static String frapiGetRequest(String transaction, ArrayList<Content> parameters) {
    StringBuilder builder = new StringBuilder();
    DefaultHttpClient client = new DefaultHttpClient();
    HttpHost targetHost = new HttpHost(HOST,PORT,SCHEME);
    String url = SCHEME + "://" + HOST + "/" + transaction;
    if (parameters != null && parameters.size() > 0) {
        url += "?" + buildParameterString(parameters);
    }

    Utilities.bLog(TAG, "Making FrapiRequest -- " + url);

    try {
        HttpGet getRequest = new HttpGet(url);
        client.getCredentialsProvider().setCredentials(
                new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                new UsernamePasswordCredentials(USERNAME, PASSWORD));

        /**Exception Occurs Here**/
        HttpResponse response = client.execute(getRequest);


        StatusLine statusLine = response.getStatusLine();
        int statusCode = -1;

        statusCode = statusLine.getStatusCode();
        if (statusCode == 200) {
            HttpEntity entity = response.getEntity();
            InputStream content = entity.getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(content));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            Utilities.bLog(TAG,"Frapi Request Succeeded");
        } 
        else {
            Utilities.bLog(TAG, "Frapi Request Failed: " + url);
        }

    } catch (ClientProtocolException e) {
        e.printStackTrace();
        Utilities.eLog(e);
    } catch (IOException e) {
        e.printStackTrace();
        Utilities.eLog(e);
    } catch (Exception e) {
        e.printStackTrace();
        Utilities.eLog(e);
    }
    return builder.toString();
}

The stack trace

java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at org.apache.http.impl.auth.DigestScheme.isGbaScheme(DigestScheme.java:210)
at org.apache.http.impl.auth.DigestScheme.processChallenge(DigestScheme.java:176)
at org.apache.http.impl.client.DefaultRequestDirector.processChallenges(DefaultRequestDirector.java:1097)
at org.apache.http.impl.client.DefaultRequestDirector.handleResponse(DefaultRequestDirector.java:980)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:490)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470)
at com.rossware.sd_quickpics.Utilities.frapiGetRequest(Utilities.java:111)
at com.rossware.sd_quickpics.Business.authenticate(Business.java:83)
at com.rossware.sd_quickpics.MainActivity$AuthenticateAsyncTask.doInBackground(MainActivity.java:320)
at com.rossware.sd_quickpics.MainActivity$AuthenticateAsyncTask.doInBackground(MainActivity.java:307)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)

This hasn't been reported on any other phone.. I would use HttpURLConnection But it doesn't support Digest Authentication (which is currently what our frapi server is using)

I'm just not sure if there's any way to continue using the authentication mechanism we have or if I have to implement a different protocol in frapi (hopefully without breaking all of our existing applications..) or if there is another way to bypass this issue for the folks with these phones? This issue is pretty restricted (one client who has about 10 phones, not the end of the world, but definitely a major issue for them)

Is there anything in android that I can do to resolve this kind of problem for the affected users? Does it seem like the code is incorrect?


回答1:


It is possible to use DigestAuth with HttpUrlConnection:

private InputStream connect(String urlStr, String username, String password) throws Exception {

    URL url = new URL(urlStr);
    HttpURLConnection connection = (HttpURLConnection) new URL(urlStr).openConnection();
    connection.setDoInput(true);
    connection.setRequestMethod("GET");

    try {

        return connection.getInputStream();

    } catch(Exception e) {

        if (connection.getResponseCode() == 401) {

            String header = connection.getHeaderField("WWW-Authenticate");

            String uri = new URL(urlStr).getFile();

            String nonce = Tools.match(header, "nonce=\"([A-F0-9]+)\"");
            String realm = match(header, "realm=\"(.*?)\"");
            String qop = match(header, "qop=\"(.*?)\"");
            String algorithm = match(header, "algorithm=(.*?),");
            String cnonce = generateCNonce();
            String ha1 = username + ":" + realm + ":" + password;
            String ha1String = md5digestHex(ha1);
            String ha2 = "GET" + ":" + uri;
            String ha2String = md5digestHex(ha2);
            int nc = 1;
            String response = ha1String + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2String;
            String responseString = md5digestHex(response);


            String authorization =
                "Digest username=\"" + username + "\"" + 
                ", realm=\"" + realm + "\"" +
                ", nonce=\"" + nonce + "\"" +
                ", uri=\"" + uri + "\"" +
                ", qop=\"" + qop + "\"" +
                ", nc=\"" + nc + "\"" +
                ", cnonce=\"" + cnonce + "\"" +
                ", response=\"" + responseString + "\"" +
                ", algorithm=\"" + algorithm + "\"";


            HttpURLConnection digestAuthConnection = prepareConnection(urlStr);
            digestAuthConnection.setRequestMethod("GET");
            digestAuthConnection.setRequestProperty("Authorization", authorization);

            return processResponse(digestAuthConnection);

        } else throw e;
    }
}

public static String match(String s, String patternString, boolean strict) {

    if (!isEmpty(s) && !isEmpty(patternString)) {
        Pattern pattern = Pattern.compile(patternString);
        if (pattern != null) {
            Matcher matcher = pattern.matcher(s);
            if (matcher != null && matcher.find() && (matcher.groupCount() == 1 || !strict)) {
                return matcher.group(1);
            }
        }
    }
    return null;
}

public static String match(String s, String patternString) {
    return match(s, patternString, true);
}

public static byte[] md5Digist(String s) {
    try {
        MessageDigest md5 = MessageDigest.getInstance("md5");
        md5.update(s.getBytes());
        return md5.digest();
    } catch (NoSuchAlgorithmException e) {
        return null;
    }
}

public static String digest2HexString(byte[] digest) {

   String digestString="";
   int low, hi;

   for (int i = 0; i < digest.length; i++) {
      low = (digest[i] & 0x0f ) ;
      hi  = ((digest[i] & 0xf0) >> 4);
      digestString += Integer.toHexString(hi);
      digestString += Integer.toHexString(low);
   }
   return digestString;
}

public static String md5digestHex(String s) {
    return digest2HexString(md5Digist(s));
}

public static String generateCNonce() {
    String s = "";
    for (int i = 0; i < 8; i++) {
        s += Integer.toHexString(new Random().nextInt(16));
    }

    return s;

}



回答2:


I ran into a similar issue today and just started using HttpClient for Android

  1. Added dependency compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1' to build.gradle.
  2. Replace new DefaultHttpClient() with HttpClientBuilder.create().build()

There are probably some other minor refactors you might need to make in other portions of the code, but that should be pretty straight forward.



来源:https://stackoverflow.com/questions/35708938/apache-http-client-android-exception-on-execute-only-for-lg-g3-6-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!