2

I am trying to download a file from my server. If I make this request through the browser I get the desired file, but when I use volley I first got com.android.volley.TimeoutError after I use setRetryPolicy I get

BasicNetwork.performRequest: Unexpected response code 200

Here is my class that makes the download:

public class DefexConnection implements Response.Listener<byte[]>, Response.ErrorListener {
private Context ctx;
private DefexDownload download;
public DefexConnection(Context ctx){
    this.ctx = ctx;
}


public void download(String link, final HashMap<String, String> params){
    DefexDownload req = new DefexDownload(Request.Method.GET, link, DefexConnection.this, DefexConnection.this, params);
    req.setRetryPolicy(new DefaultRetryPolicy( 500000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    RequestQueue queue = Volley.newRequestQueue(this.ctx, new HurlStack(null, getSocketFactory()));
    queue.add(req);
}




private SSLSocketFactory getSocketFactory() {

    CertificateFactory cf = null;
    try {
        cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = ctx.getResources().openRawResource(R.raw.comodoroca);
        Certificate ca;
        try {
            ca = cf.generateCertificate(caInput);
            Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }


        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);


        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);


        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {

                Log.d("CipherUsed", session.getCipherSuite());
                return hostname.compareTo("www.defexsecurity.com")==0; 

            }
        };


        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        SSLContext context = null;
        context = SSLContext.getInstance("TLS");

        context.init(null, tmf.getTrustManagers(), null);
        HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

        SSLSocketFactory sf = context.getSocketFactory();


        return sf;

    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }

    return  null;
}


@Override
public void onResponse(byte[] response) {
    HashMap<String, Object> map = new HashMap<String, Object>();
    int count;
    if (response!=null) {
        String content = download.responseHeaders.get("Content-Disposition").toString();
        StringTokenizer st = new StringTokenizer(content, "=");
        String[] arrTag = st.toArray();

        String filename = arrTag[1];
        filename = filename.replace(":", ".");
        Log.d("DEBUG::RESUME FILE NAME", filename);
        try{
            long lenghtOfFile = response.length;

            //covert reponse to input stream
            InputStream input = new ByteArrayInputStream(response);
            File path = Environment.getExternalStorageDirectory();
            File file = new File(path, filename);
            map.put("resume_path", file.toString());
            BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file));
            byte data[] = new byte[1024];

            long total = 0;

            while ((count = input.read(data)) != -1) {
                total += count;
                output.write(data, 0, count);
            }

            output.flush();

            output.close();
            input.close();
            Log.e("DEFEX","file saved to "+file.getAbsolutePath());
        }catch(IOException e){
            e.printStackTrace();

        }
    }
}

@Override
public void onErrorResponse(VolleyError error) {
    Log.e("DEFEX", "UNABLE TO DOWNLOAD FILE. ERROR:: "+error.toString());
}

}

Here is my class DefexDownload (which extends Request):

class DefexDownload extends Request<byte[]>{

    private final Response.Listener<byte[]> mListener;
    private Map<String, String> mParams;
    public Map<String, String> responseHeaders ;


    DefexDownload(int post, String mUrl, Response.Listener<byte[]> listener, Response.ErrorListener errorListener, HashMap<String, String> params){
        super(post, mUrl, errorListener);
        setShouldCache(false);
        mListener = listener;
        mParams=params;
    }

    @Override
    protected Map<String, String> getParams() throws com.android.volley.AuthFailureError {
        return mParams;
    }

    @Override
    protected void deliverResponse(byte[] response) {
        mListener.onResponse(response);
    }

    @Override
    protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {
        //Initialise local responseHeaders map with response headers received
        responseHeaders = response.headers;

        //Pass the response data here
        return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response));
    }

}

I have no clue what could be wrong here, any help will be gratly appreciated

Edit: on every other answer I found here on SO the problems seems to be the proxy or device emulator, but I'm running my app on my real device which is not using any proxy

Yuri Waki
  • 663
  • 1
  • 11
  • 25
  • Are you sure that `SSLSocketFactory` created as expect, Please check LogCat for `getSocketFactory()` may be crash logged and return null, – Khaled Lela Aug 12 '18 at 21:59
  • getSocketFactory is working, there are other requests (common requests, not file downloads) that use this method and are working as expected, I removed them because I think they are not relevant – Yuri Waki Aug 12 '18 at 22:10
  • Are you testing using real device or emulator? – Khaled Lela Aug 12 '18 at 22:15
  • If you testing throw the emulator, try to stop you antivirus or firewall, and give it a trial, :) – Khaled Lela Aug 12 '18 at 22:18
  • I am testing on my real device – Yuri Waki Aug 13 '18 at 12:58
  • I could not do it with Volley, but I could succesfully download a file using this [answer](https://stackoverflow.com/questions/3028306/download-a-file-with-android-and-showing-the-progress-in-a-progressdialog) (the solution that worked for me was solution 2 from the accepted answer) – Yuri Waki Aug 13 '18 at 23:02

1 Answers1

0

According to this issue on Github.

So HurlStack is more or less just a thin wrapper around HttpUrlConnection. The EOFException is presumably coming from there when trying to make the connection. I don't think there is much that Volley can do about this, short of applying a safe workaround if there's a known platform bug.

The stack traces of the cause chain would be good to look at, since the exception is being thrown by some platform class under the covers. Otherwise, I suspect you would reproduce the same issue if you just used HttpUrlConnection directly, which means there's unfortunately not much Volley can do.

Searching for the exception indicates a number of potential issues such as Android HttpUrlConnection Url doesn't work on emulator indicating networking issues on the machine in question which explained why it was emulator only.

Expectation of the issue:

  • Emulator connection is not well configured
  • Host PC antivirus or firewall.

Solutions

  • Try your code using real device.
  • Try with emulator after configure network with host PC and stop antivirus or/and firewall.
Khaled Lela
  • 7,831
  • 6
  • 45
  • 73