web-dev-qa-db-fra.com

Publication HTTP sécurisée en Android

J'ai une classe d'aide assez basique que j'utilise pour faire tous mes trucs Http Get/Post. J'utilise HttpGet, HttpPost et HttpClient de la bibliothèque org.Apache.http. Tous mes trucs fonctionnent bien sur HTTP, mais dès que j'ai essayé de consommer un service qui fonctionne sur HTTPS, j'obtiens une exception ClientProtocolException lors de l'exécution de la demande. Le seul message de l'exception est "Le serveur n'a pas répondu avec une réponse HTTP valide".

Pour tester, j'ai envoyé exactement la même charge utile à partir d'un navigateur en utilisant un simple formulaire html et Fiddler2 en utilisant RequestBuilder. J'ai envoyé des charges utiles invalides et vides et j'ai même envoyé tout ce qui précède avec et sans en-têtes pour voir s'il y avait quelque chose de génial dans la façon dont les objets construisaient la demande.

Tout ce que j'ai utilisé dans les tests me donne une réponse HTTP valide à 200 états. Le service me donne juste une structure décrivant l'erreur si je lui donne autre chose que ce qu'il attend.

Y a-t-il quelque chose de spécial que je dois ajouter aux objets HttpPost ou HttpClient pour lui dire d'utiliser HTTPS? Dois-je lui dire explicitement d'utiliser un port différent?

MODIFIER:

J'ai en effet enregistré la mauvaise usine de socket pour la communication https. Voici la méthode mise à jour que j'utilise pour créer mon objet HttpClient avec la fabrique de socket correcte au cas où quelqu'un chercherait ce type de problème à l'avenir:

private HttpClient createHttpClient()
{
    HttpParams params = new BasicHttpParams();
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
    HttpProtocolParams.setUseExpectContinue(params, true);

    SchemeRegistry schReg = new SchemeRegistry();
    schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
    ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);

    return new DefaultHttpClient(conMgr, params);
}
38
Rich

Je ne sais pas pourquoi vous ne pouvez pas gérer HTTPS. J'ai écrit une classe d'aide pour mes propres applications et je peux GET/POST en HTTPS sans problème. Je posterai le code ici et vous pourrez peut-être voir s'il y a des différences entre mon code et le vôtre.

import Java.io.IOException;
import Java.io.InputStream;
import Java.io.UnsupportedEncodingException;
import Java.net.HttpURLConnection;
import Java.net.URL;
import Java.net.URLConnection;

import org.Apache.http.HttpResponse;
import org.Apache.http.client.methods.HttpGet;
import org.Apache.http.client.methods.HttpPost;
import org.Apache.http.client.params.ClientPNames;
import org.Apache.http.client.params.CookiePolicy;
import org.Apache.http.entity.StringEntity;
import org.Apache.http.impl.client.DefaultHttpClient;
import org.Apache.http.params.BasicHttpParams;
import org.Apache.http.params.HttpConnectionParams;
import org.Apache.http.params.HttpParams;
import org.Apache.http.protocol.BasicHttpContext;
import org.Apache.http.protocol.HttpContext;
import org.Apache.http.util.EntityUtils;
import org.json.JSONObject;

import Android.util.Log;

public class HttpRequest{

    DefaultHttpClient httpClient;
    HttpContext localContext;
    private String ret;

    HttpResponse response = null;
    HttpPost httpPost = null;
    HttpGet httpGet = null;

    public HttpRequest(){
        HttpParams myParams = new BasicHttpParams();

        HttpConnectionParams.setConnectionTimeout(myParams, 10000);
        HttpConnectionParams.setSoTimeout(myParams, 10000);
        httpClient = new DefaultHttpClient(myParams);       
        localContext = new BasicHttpContext();    
    }

    public void clearCookies() {
        httpClient.getCookieStore().clear();
    }

    public void abort() {
        try {
            if (httpClient != null) {
                System.out.println("Abort.");
                httpPost.abort();
            }
        } catch (Exception e) {
            System.out.println("Your App Name Here" + e);
        }
    }

    public String sendPost(String url, String data) {
        return sendPost(url, data, null);
    }

    public String sendJSONPost(String url, JSONObject data) {
        return sendPost(url, data.toString(), "application/json");
    }

    public String sendPost(String url, String data, String contentType) {
        ret = null;

        httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);

        httpPost = new HttpPost(url);
        response = null;

        StringEntity tmp = null;        

        Log.d("Your App Name Here", "Setting httpPost headers");

        httpPost.setHeader("User-Agent", "SET YOUR USER AGENT STRING HERE");
        httpPost.setHeader("Accept", "text/html,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");

        if (contentType != null) {
            httpPost.setHeader("Content-Type", contentType);
        } else {
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
        }

        try {
            tmp = new StringEntity(data,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            Log.e("Your App Name Here", "HttpUtils : UnsupportedEncodingException : "+e);
        }

        httpPost.setEntity(tmp);

        Log.d("Your App Name Here", url + "?" + data);

        try {
            response = httpClient.execute(httpPost,localContext);

            if (response != null) {
                ret = EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            Log.e("Your App Name Here", "HttpUtils: " + e);
        }

        Log.d("Your App Name Here", "Returning value:" + ret);

        return ret;
    }

    public String sendGet(String url) {
        httpGet = new HttpGet(url);  

        try {
            response = httpClient.execute(httpGet);  
        } catch (Exception e) {
            Log.e("Your App Name Here", e.getMessage());
        }

        //int status = response.getStatusLine().getStatusCode();  

        // we assume that the response body contains the error message  
        try {
            ret = EntityUtils.toString(response.getEntity());  
        } catch (IOException e) {
            Log.e("Your App Name Here", e.getMessage());
        }

        return ret;
    }

    public InputStream getHttpStream(String urlString) throws IOException {
        InputStream in = null;
        int response = -1;

        URL url = new URL(urlString); 
        URLConnection conn = url.openConnection();

        if (!(conn instanceof HttpURLConnection))                     
            throw new IOException("Not an HTTP connection");

        try{
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");
            httpConn.connect(); 

            response = httpConn.getResponseCode();                 

            if (response == HttpURLConnection.HTTP_OK) {
                in = httpConn.getInputStream();                                 
            }                     
        } catch (Exception e) {
            throw new IOException("Error connecting");            
        } // end try-catch

        return in;     
    }
}
38
MattC

Comme certaines méthodes sont obsolètes, ne devrait-il pas en être ainsi?

  private DefaultHttpClient createHttpClient() {
    HttpParams params = new BasicHttpParams();

    HttpConnectionParams.setConnectionTimeout(params, 10000);
    HttpConnectionParams.setSoTimeout(params, 10000);
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
    HttpProtocolParams.setUseExpectContinue(params, true);

    SchemeRegistry schReg = new SchemeRegistry();
    schReg.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    schReg.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
    ClientConnectionManager conMgr = new PoolingClientConnectionManager(schReg);

    return new DefaultHttpClient(conMgr, params);
  }

Dois-je changer autre chose, comme HttpVersion?

1
Miquel