48

The code below works great if I connect to what seems to be Apache servers, however when I try to connect to my .Net server it throws an error. I am guessing it is a header requirement, but I can not seem to get a successful response no matter what I try.

public String Download(String Url)
{
 String filepath=null;
 try {
  //set the download URL, a url that points to a file on the internet
  //this is the file to be downloaded
  URL url = new URL(Url);
  //create the new connection
  HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

  //set up some things on the connection
  urlConnection.setRequestMethod("GET");
  urlConnection.setDoOutput(true); 
   //and connect!
  urlConnection.connect();
  //set the path where we want to save the file
  //in this case, going to save it on the root directory of the sd card.
  File SDCardRoot = Environment.getExternalStorageDirectory();
  //create a new file, specifying the path, and the filename
  //which we want to save the file as.

  String filename= "effortback.png";   // you can download to any type of file ex:.jpeg (image) ,.txt(text file),.mp3 (audio file)
  Log.i("Local filename:",""+filename);
  File file = new File(SDCardRoot + "/",filename);

  //=====================================
  if(file.createNewFile())
  {
   file.createNewFile();
  }
  //=====================================

  //this will be used to write the downloaded data into the file we created
  FileOutputStream fileOutput = new FileOutputStream(file);

  //this will be used in reading the data from the internet
  InputStream inputStream = urlConnection.getInputStream();

  //=====================================
  //this is the total size of the file
  int totalSize = urlConnection.getContentLength();
  //variable to store total downloaded bytes
  int downloadedSize = 0;
  //=====================================

  //create a buffer...
  byte[] buffer = new byte[2048];
  int bufferLength = 0; //used to store a temporary size of the buffer

  //now, read through the input buffer and write the contents to the file
  while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
   //add the data in the buffer to the file in the file output stream (the file on the sd card
   fileOutput.write(buffer, 0, bufferLength);
   //add up the size so we know how much is downloaded
   downloadedSize += bufferLength;
   //this is where you would do something to report the prgress, like this maybe
   Log.i("Progress:","downloadedSize:"+downloadedSize+"totalSize:"+ totalSize) ;

  }
  //close the output stream when done
  fileOutput.close();
  if(downloadedSize==totalSize)   filepath=file.getPath();

 //catch some possible errors...
 } catch (MalformedURLException e) {
  e.printStackTrace();
  Log.i("URL-ERROR:",e.toString());
 } catch (IOException e) {
  filepath=null;
  e.printStackTrace();
  Log.i("IO-ERROR:",e.toString());
 }
 Log.i("filepath:"," "+filepath) ;

 return filepath;

}

Errors range from:

java.io.FileNotFoundException  //I always get this with either one of the below
   org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1061)

//or this one below
libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionTmpl.java:186)

It seems that no matter what I try I can not get it to work. Again, it works if I try to download an image from Google or some other sites, but not all, but definitely not mine (.Net). What am I missing here? Please help.

cybernetic.nomad
  • 6,100
  • 3
  • 18
  • 31
nathan
  • 477
  • 1
  • 4
  • 8
  • OK, did a little more digging and found that I am getting a 403 error from the server. This is a security error, so now my question is how do I get past it? Thanks in advance. – nathan Apr 27 '13 at 22:17
  • 43
    OK, I figured it out. Very important not to use this line if you are having the same issue, also check your URL. First issue was my URL was misspelled so I got the obvious response from the server. After I fixed my URL it was still having issues. Ultimately it was this line: urlConnection.setDoOutput(true); Apparently this line in JAVA forces the http protocol to change a GET to a POST regardless of specifying the GET. Just an FYI, for those in the future. – nathan May 06 '13 at 01:26
  • THANK YOU, this has been keeping me busy for a whole day. – Christoffer Klang May 13 '13 at 10:34
  • Thanks, please answer your own question! – Wotuu Jun 12 '13 at 21:58
  • Me also stuck on this problem. Now it's working fine. Thank you. – noNameYet Sep 12 '13 at 07:06
  • 4
    @nathan, you should post this as an answer to your own question and accept it. This is completely fine according to SO rules and have been done many times before. – Alexander Malakhov Oct 09 '13 at 04:19

3 Answers3

113

You can get a FileNotFoundException from HttpUrlConnection (and OkHttpClient) if your server returns >= HTTPStatus.BAD_REQUEST (400). You should check the status code first to check what stream you need to read.

int status = connection.getResponseCode();

if(status >= HttpStatus.SC_BAD_REQUEST)
    in = connection.getErrorStream();
else
    in = connection.getInputStream();

HttpStatus deprecated. Latest syntax seems to be:

InputStream inputStream;
int status = urlConnection.getResponseCode();

if (status != HttpURLConnection.HTTP_OK)  {
    inputStream = urlConnection.getErrorStream();
}
else  {
    inputStream = urlConnection.getInputStream();
}
Georgios
  • 4,764
  • 35
  • 48
Dori
  • 18,283
  • 17
  • 74
  • 116
49

Had the same problem, solved like you said:

urlConnection.setDoOutput(false);

Note that you must set it to false because it's true by default.
Note that you must set it to false because Volley HurlStack was setting it to true.
Take care ;)

EDIT: I've just checked the code and by default it's false as @Abraham Philip said. But I had to set it to false because if I called getDoOutput() it was returning true. I found that Volley HurlStack was setting it to true. So, my conclusion is, setDoOutput to false and it will work.

package java.net;
public abstract class URLConnection {
...

    /**
     * Specifies whether this {@code URLConnection} allows sending data.
     */
    protected boolean doOutput;

...
    public boolean getDoOutput() {
        return doOutput;
    }

    public void setDoOutput(boolean newValue) {
        checkNotConnected();
        this.doOutput = newValue;
    }
GuilhE
  • 11,591
  • 16
  • 75
  • 116
  • 1
    Your statement seems to be incorrect. setDoOutput is false by default. Reference (Java Docs):http://download.java.net/jdk7/archive/b123/docs/api/java/net/URLConnection.html#setDoOutput(boolean) – Abraham Philip Jun 04 '15 at 02:40
  • Yes your are right, by default it's false. Check my update ;) – GuilhE Jun 04 '15 at 09:37
  • 1
    and +1, because you turned into an answer what OP had just mentioned as a comment. – Abraham Philip Jun 04 '15 at 09:42
2

I faced an issue, where executing a HEAD-Request threw a FileNotFoundException.
The reason is, that a response to a HEAD does not have a body and therefore a call to getInputStream throws a FileNotFoundException.

So if you are executing a HEAD, you should not try to get the InputStream.

Robert P
  • 9,398
  • 10
  • 58
  • 100