3

I'm developing an Android app where I use DownloadManager to download files. It's able to successfully download certain files (eg. JPEG, MP3), but it's unsuccessful for others (eg. PDF). I'm not certain it's related to file type. I registered a BroadcastReceiver to help debug the issue. On the onReceive() callback, I query the DownloadManager to find the reason for the failure but it just gives a "400", which is not a documented reason.

Here is how I use DownloadManager:

DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(url);
request.setTitle(filename);
request.setDestinationInExternalPublicDir(folder, filename);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
manager.enqueue(request);

On DownloadManager.STATUS_FAILED, here is my debugging code:

DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = manager.query(query);
if(cursor.moveToFirst()){                    
    int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
    int reason = cursor.getInt(columnReason);
    Log.e("App", reason);
    // the value of reason is 400 which is not a valid DownloadManager.ERROR_*
}

The value of reason should be one of the constants DownloadManager.ERROR_* but 400 is not. Same thing happens on two devices: Galaxy Nexus (v4.3) & Nexus 9 (v5.1). I tested the URL on the phone's browser and confirmed that works outside the app. Does anyone have any idea what's happening? Any help would be appreciated.

Thanks

EDITED: The file I'm trying to download has a space in the filename. I did a few quick experiments: removing spaces from files that didn't work, adding space to file that previously did work. It appears it might be related to the filename containing space.

EDITED: This is what I did to fix the problem. I had to encode the URL on the server (the URL is part of a json response so I changed the response)

url = URLEncoder.encode(url, "utf-8")

E.Yuen
  • 33
  • 1
  • 4
  • Theres a reason files on websites NEVER contain spaces in their name.. and if they do the website should try to remove those spaces and make the URI uniform. This is what URL encoding means! – JoxTraex Jan 26 '16 at 21:20

2 Answers2

4

This 400 reason is HTTP error. Quoting docs:

Provides more detail on the status of the download. Its meaning depends on the value of COLUMN_STATUS. When COLUMN_STATUS is STATUS_FAILED, this indicates the type of error that occurred. If an HTTP error occurred, this will hold the HTTP status code as defined in RFC 2616. Otherwise, it will hold one of the ERROR_* constants. [...]

https://developer.android.com/reference/android/app/DownloadManager.html#COLUMN_REASON

And this HTTP error means

400 Bad Request The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

If you get other HTTP errors, consult this page for their meaning: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error

pelotasplus
  • 9,852
  • 1
  • 35
  • 37
  • The 400 error seems to be aligned with HTTP error code, but that doesn't seem to make sense in this case since the reason should always be within the range of DownloadManager.ERROR_*. Wouldn't the reason in this case be at most ERROR_UNKOWN? I've made a quick update too, the filename has a space in the name that might be causing the problem. – E.Yuen Aug 31 '15 at 08:40
  • it's not true that reason should be within the range of DownloadManget.ERROR_* -- check the docs "If an HTTP error occurred, this will hold the HTTP status code as defined in RFC 2616. Otherwise, it will hold one of the ERROR_* constants" -- https://developer.android.com/reference/android/app/DownloadManager.html#COLUMN_REASON – pelotasplus Aug 31 '15 at 08:43
  • just edited the post to include the relevant part from documentaion and link as well – pelotasplus Aug 31 '15 at 08:45
  • I missed that in the docs, thanks! It turns out the server wasn't URL encoding the path that the Android app was using. Once I fixed the server, the app worked. – E.Yuen Aug 31 '15 at 09:26
0

Spaces in URL could be simply removed by this line of code:

url = url.replaceAll(" ", "%20");

Strange thinks could happen when this sanitized URL redirects to another with spaces. For example asking for:

GET http://example.com/file%20with%20spaces.pdf HTTP/1.1
Host: example.com

results in redirect:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/new file with spaces.pdf

DownloadManager will follow this redirect and do the request for this not sanitized url:

GET http://example.com/new file with spaces.pdf HTTP/1.1
Host: example.com

which results in error 400:

HTTP/1.0 400 Bad request: request protocol version denied

unfortunately only workaround I found is to pre-resolve this redirect in your code and sanitize second URL.

gingo
  • 3,149
  • 1
  • 23
  • 32