2012-04-27 12 views
12

Estoy usando HttpClient para solicitudes HTTPS, lo que ha funcionado bien hasta ahora. Después de actualizar a ICS, algunos usuarios informan que tienen problemas para conectarse en conexiones 3G.Android: Esquema 'http' no registrado en ICS 4.0.4 w/proxy

EDITAR: La mayoría de ellos parece estar utilizando un proxy, y puedo reproducirlo localmente con una tarjeta SIM de T-Mobile utilizando su proxy.

Los registros tienen esta seguimiento de la pila:

java.lang.IllegalStateException: Scheme 'http' not registered. 
org.apache.http.conn.scheme.SchemeRegistry.getScheme(SchemeRegistry.java:80) 
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:126) 
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 

Nuestro punto final es HTTPS, por lo que no se registra un extremo HTTP en nuestro SchemeRegistry a propósito. No hay ningún lugar (AFAIK) donde redirigamos a HTTP.

Aquí está el código que configura el HttpClient para el cliente HTTPS:

DefaultHttpClient ret = null; 

    // sets up parameters 
    HttpParams params = new BasicHttpParams(); 
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
    HttpProtocolParams.setContentCharset(params, "utf-8"); 
    params.setBooleanParameter("http.protocol.expect-continue", false); 

    HttpConnectionParams.setConnectionTimeout(params, DEFAULT_CONN_TIMEOUT_MSEC); 
    HttpConnectionParams.setSoTimeout(params, timeoutMsec); 
    HttpConnectionParams.setStaleCheckingEnabled(params, true); 

    SchemeRegistry registry = new SchemeRegistry(); 
    final SocketFactory sslSocketFactory = getPreferredSSLSocketFactory(); 
    registry.register(new Scheme("https", sslSocketFactory, 443)); 

    ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry); 
    ret = new DefaultHttpClient(manager, params); 
    // for preemptive authentication 
    // http://dlinsin.blogspot.com/2009/08/http-basic-authentication-with-android.html 
    ret.addRequestInterceptor(preemptiveAuth, 0); 
    ret.setCookieStore(communalCookieJar); 

    SimpleCredentialsProvider credProvider = new SimpleCredentialsProvider(getAccountPreferences()); 
    ret.setCredentialsProvider(credProvider); 

    return ret; 

Nota: Compartimos este caso HttpClient entre varios subprocesos.

Respuesta

3

El problema parecía ser que algunas compañías estaban empujando las definiciones de proxy no válidos con la actualización 4.0.4. Esto rompió HTTPS, pero HTTP funcionó correctamente (Google Play no funcionó, por ejemplo).

Una posible solución (además de corregir la entrada de proxy no válida) consiste en capturar IllegalStateException al realizar solicitudes de HttpClient y establecer un marcador. Este código omitirá cualquier proxies:

hc = new DefaultHttpClient(manager, params); 
    if (BYPASS_PROXY) 
     hc.setRoutePlanner(new DefaultHttpRoutePlanner(registry)); 
+7

¿Qué es BYPASS_PROXY? ¿Por qué no podemos usar siempre este planificador de rutas? ¿Es segura esta solución (por ejemplo, todavía usará https)? –

+0

Tu código es el truco. De repente, comenzó a sucederme solo a través de 3G (Telenor, Suecia). ¿Hay algún problema potencial con tener esto siempre encendido? – apanloco

+0

Entonces, ¿hay algún problema con tenerlo siempre activado? –

1

No crearía un nuevo SchemeRegistry. Tomaría el predeterminado de ThreadSafeClientConnManager.getSchemeRegistry(). De esta forma, probablemente contenga todo tipo de esquemas soportados.

La parte http puede provenir del proxy de su operador.

+0

¿Puede compartir los detalles? No encontré la forma de obtener el registro de esquema predeterminado desde el administrador de conexiones de subproceso seguro o el cliente único. – apanloco

+0

¿qué quieres decir? no 'manager.getSchemeRegistry()' logra eso? – njzk2

+0

ThreadSafeClientConnManager y SingleClientConnManager REQUIEREN un SchemeRegistry en el constructor, por lo que solo tiene que devolver lo que TIENE para darlo. – apanloco

6

Desde su stacktrace, le sugiero que registre ambos (http, https) y vea si eso no funciona.

Debería poder depurarlo incluyendo los jar de origen de apache - profundice en el rastreo @ SchemeRegistry.getScheme().

This thread pueden ayudar.

A continuación se probó muy bien en ICS ... Muestra SSL ConnectionMgr en androidhttpclient libs:

static X509TrustManager tm = new X509TrustManager() { 

     public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { 
     } 

     public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
     return null; 
     } 
}; 

MyConnectionManager(SchemeRegistry scheme){ 
    super(scheme); 
} 

public static MyConnectionManager getInstance() { 
    if (instance == null){ 

     SSLContext ctx=null; 
     try { 
      ctx = SSLContext.getInstance("TLS"); 
      ctx.init(null, new TrustManager[]{tm}, null); 
     } catch (NoSuchAlgorithmException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (KeyManagementException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     }     
     SchemeRegistry schemeRegistry = new SchemeRegistry(); 
     schemeRegistry.register(new Scheme("http", 80,PlainSocketFactory.getSocketFactory())); 
     schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); 
     instance = new MyConnectionManager(schemeRegistry); 
     // Increase max total connection to 200 
     instance.setMaxTotal(15); 
     // Increase default max connection per route to 20 
     instance.setDefaultMaxPerRoute(15); 
     // Increase max connections for localhost:80 to 50 
     HttpHost localhost = new HttpHost("picasaweb.google.com", 443); 
     instance.setMaxForRoute(new HttpRoute(localhost), 10); 
    } 
    return instance; 
} 
Cuestiones relacionadas