0

I've written code to download some data from external server. The server is using self-signed certificate, need to have session cookie set and some POST data. Currently I have the following code:

private byte[] getResponse(URL url, String postData) 
    throws IOException, KeyManagementException, CertificateException, KeyStoreException, 
    NoSuchAlgorithmException
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.setRequestProperty("User-Agent", userAgent);
    urlConnection.setRequestProperty("Cookie", cookie);
    urlConnection.setRequestMethod("POST");
    urlConnection.setDoInput(true);
    urlConnection.setDoOutput(true);

    urlConnection.setSSLSocketFactory(getSocketFactory());

    OutputStream os = urlConnection.getOutputStream();
    BufferedWriter writer = new BufferedWriter(
            new OutputStreamWriter(os, "UTF-8"));
    writer.write(postData);
    writer.flush();
    writer.close();
    os.close();

    try {
        urlConnection.connect();
        InputStream is = urlConnection.getInputStream();
        int len = 0;
        while ((len = is.read(buffer)) != -1) 
        {
            baos.write(buffer, 0, len);
        }

    }
    catch(IOException e)
    {
        throw e;
    }
    finally {
        urlConnection.disconnect();
    }
    return baos.toByteArray();
}

On Ice Cream Sandwich and higher (API >= 14) everything works fine. The problem started when I tried to make the app work on API >= 8. It is now properly sending the request with GET and no params (CAPTCHA) but when it comes to getting the actual data urlConnection's connect method fails with no exception. The code for getSocketFactory() is:

private SSLSocketFactory getSocketFactory() 
    throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, 
    KeyManagementException
{
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = context.getResources().openRawResource(R.raw.historiapojazdu);
    Certificate ca;
    try {
    ca = cf.generateCertificate(caInput);
    } finally {
    caInput.close();
    }
    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    return context.getSocketFactory();
}

EDIT: I've just realized that connect method apparently worked but it didn't follow redirect on the response so input stream was always empty.

4

1 回答 1

0

我只是自己想通了。看起来 HttpsUrlConnection 出于某种原因根本不遵循 API 10 和更低版本的重定向,即使隐式调用 setInstanceFollowRedirects(true) 也是如此。它只是忽略了该设置。在调用 urlConnection.connect() 之后,我已经使用此代码解决了这个问题:

String redirect = urlConnection.getHeaderField("Location");
        if(redirect != null)    //truth before ICS
        {
            urlConnection.disconnect();

            urlConnection = (HttpsURLConnection) (new URL(redirect)).openConnection();
            urlConnection.setRequestProperty("User-Agent", userAgent);
            urlConnection.setRequestProperty("Cookie", cookie);
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);

            urlConnection.setSSLSocketFactory(getSocketFactory());

            OutputStream os2 = urlConnection.getOutputStream();
            BufferedWriter writer2 = new BufferedWriter(
                    new OutputStreamWriter(os2, "UTF-8"));
            writer2.write(postData);
            writer2.flush();
            writer2.close();
            os2.close();

            urlConnection.connect();
        }
于 2014-07-21T18:47:30.793 回答