Scorpion
Scorpion

Reputation: 6901

Authorization fails in HttpURLConnection in File Download Android

I want to download a zip file from the server in Android and for that I am using the below code. It also requires authorization so for that I am passing the username and password in the request of the URL connection. But I am always getting 401-Response code(UNAUTHORIZED).

Code :-

protected String doInBackground(final String... params) {
            int count;
            try {
                if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                    /*Authenticator.setDefault(new Authenticator(){
                        protected PasswordAuthentication getPasswordAuthentication() {
                            return new PasswordAuthentication(Constants.USERNAME,Constants.PASSWORD.toCharArray());
                        }});*/

                    Log.i(TAG, "URL == " + params[0]);
                    final URL url = new URL(params[0]);
                    final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    final String auth = new String(Constants.USERNAME + ":" + Constants.PASSWORD);
                    connection.setRequestProperty("Authorization", "Basic " + Base64.encodeToString(auth.getBytes(), Base64.URL_SAFE));
                    //connection.addRequestProperty("Authorization", "Basic " + Base64.encodeToString(auth.getBytes(), Base64.DEFAULT));
                    connection.setUseCaches(false);
                    connection.setConnectTimeout(5000);
                    connection.setDoOutput(true);
                    connection.connect();
                    Log.i(TAG, "Response == " + connection.getResponseMessage());
                    Log.i(TAG, "Response Code == " + connection.getResponseCode());

                    // download the file
                    final InputStream input = new BufferedInputStream(connection.getInputStream());
                    // Path to the just created empty db

                    // this will be useful so that you can show a tipical 0-100% progress bar
                    lenghtOfFile = connection.getContentLength();
                    lengthOfFileInMB = lenghtOfFile / 1048576;
                    Log.i(TAG, "File Size in MB = " + lengthOfFileInMB);

                    outFileName = Environment.getExternalStorageDirectory() + File.separator + ZIP_NAME;
                    final File file = new File(outFileName);
                    if (!file.exists()) {
                        file.createNewFile();
                    }

                    // Output stream
                    final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
                    final byte data[] = new byte[lenghtOfFile];
                    long total = 0;

                    while ((count = input.read(data)) != -1) {
                        total += count;
                        publishProgress("" + total);
                        bufferedOutputStream.write(data, 0, count);
                    }
                    bufferedOutputStream.flush();
                    bufferedOutputStream.close();
                    input.close();
                } else {
                    Toast.makeText(DashboardActivity.this, "MEDIA IS NOT MOUNTED.", Toast.LENGTH_LONG).show();
                }
            } catch (final MalformedURLException e) {
                flag = false;
                Log.e(TAG, e.getMessage(), e);
            } catch (final FileNotFoundException e) {
                flag = false;
                Log.e(TAG, e.getMessage(), e);
            } catch (final IOException e) {
                flag = false;
                Log.e(TAG, e.getMessage(), e);
            } catch (final Exception e) {
                Log.e(TAG, e.getMessage(), e);
            }

            return null;
        }

I am having the web service in the same server and for getting JSON/XML response I used the DefaultHttpClient. That is working perfectly fine and I am getting the response code OK as well. I don't know why it is not authorizing at the time of URLConnection.

Here is the code of it.

String line = null;
        try {
            final URL urlObj = new URL(url);
            final HttpHost host = new HttpHost(urlObj.getHost(), urlObj.getPort(), urlObj.getProtocol());
            final HttpParams httpParameters = new BasicHttpParams();
            // Set the timeout in milliseconds until a connection is established.
            HttpConnectionParams.setConnectionTimeout(httpParameters, Constants.CONNECTION_TIME_OUT);
            // Set the default socket timeout (SO_TIMEOUT) 
            // in milliseconds which is the timeout for waiting for data.
            HttpConnectionParams.setSoTimeout(httpParameters, Constants.CONNECTION_TIME_OUT);

            final DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
            final AuthScope scope = new AuthScope(urlObj.getHost(), urlObj.getPort());
            final UsernamePasswordCredentials creds = new UsernamePasswordCredentials(Constants.USERNAME, Constants.PASSWORD);
            final CredentialsProvider credentialProvider = new BasicCredentialsProvider();
            credentialProvider.setCredentials(scope, creds);
            final HttpContext credContext = new BasicHttpContext();
            credContext.setAttribute(ClientContext.CREDS_PROVIDER, credentialProvider);

            final HttpGet job = new HttpGet(url);
            job.addHeader("USER-AGENT", userAgentString);
            final HttpResponse httpResponse = httpClient.execute(host,job,credContext);

            final HttpEntity httpEntity = httpResponse.getEntity();

            try {
                line = EntityUtils.toString(httpEntity);
            } catch (final ParseException e) {
                line = "Error";
                Log.e("Parse Error", e.getMessage().toString());
            } catch (final IOException e) {
                line = "Error";
                Log.e("IOException Error", e.getMessage().toString());
            }
            final StatusLine status = httpResponse.getStatusLine();
            Log.d("Authentication Status = ", status.toString());
        } catch (final ClientProtocolException e1) {
            line = "Error";
            Log.e("ClientPrtocol Error", e1.getMessage().toString());
        } catch (final ConnectTimeoutException e1) {
            line = "ConnectionTimeOut";
            Log.e("Connection Error", e1.getMessage().toString());
        } catch (final IOException e1) {
            Log.e("IO Error", e1.getMessage().toString());
            line = "Error";
        }

I also tried to add the following code in URLConnection for authentication but that also not worked for me.

Authenticator.setDefault(new Authenticator() {
  protected PasswordAuthentication getPasswordAuthentication() {
     return new PasswordAuthentication(loginNameString, passwordString.toCharArray());
  }
});

Questions:-

1) Is it problem at server side or at android side?

2) Can I download the file using the defaulthttpclient code that I have? If yes any clue how to download it, because I think i can only get content from that way not the whole file.

Upvotes: 0

Views: 1876

Answers (2)

Jerry Tian
Jerry Tian

Reputation: 3448

It seems using HttpClient is a more straight way, which is also available on Android.

I will skip the auth part since your code looks fine to me, and based on your comment, the below downloading part of code should work. This is typical read&copy&write IO operation code, from my own project.

   HttpGet httpget = new HttpGet(url);
    //
    // Authorization configuration code here ...
    // 
    HttpResponse response = httpClient.execute(httpget);
    HttpEntity entity = response.getEntity();

    //
    // The content is all cached in memory for demonstration only, 
    // you can also write to file system using FileOutputStream.
    //
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    if (entity != null) {
        InputStream inputStream = entity.getContent();

        byte[] buf = new byte[1024];
        int read = 0;

        try {
            while ((read = is.read(buf)) >= 0) {
                baos.write(buf, 0, read);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {is.close();} catch (Exception ex) {}
            try {baos.close();} catch (Exception ex) {}
        }
    }

    byte[] content = baos.toByteArray();

Upvotes: 1

Matt
Matt

Reputation: 690

I think you need to add connection.setDoInput(true) otherwise I'm pretty sure you can't get the input stream (you can have both doInput and doOutput true on the same connection) This may not answer your exact problem, but it will definitely prevent you from downloading.

Edit: not having setDoInput(true) may prevent downloading and I do not see that in your code

Upvotes: 0

Related Questions