I have an application in which we have files that are being served from a secure encrypted file system to the user. THe files are decrypted on the fly by the application and then pushed to the client through the response header. This works perfectly fine in all browsers and iOS devices, but fails on all androids. It just simply says the download failed.
I have tried many different solutions that have been suggested around for android devices, as they seem to have a lot of problems with files like this. Nothing has seemed to work.
change file extension to be in all caps in the Content-Disposition header
tried multiple content types (application/octet-stream and specific file types)
Below is the actual code writing the response headers.
strMimeType = objDocument.FileMime
If strMimeType = "" Then
strMimeType = "application/octet-stream"
End If
HttpContext.Current.Response.ContentType = strMimeType
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=" & objDocument.Filename)
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.WriteFile(Server.MapPath("/FS/CO/" & objDocument.DocumentID & "/" & objDocument.Filename))
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.Close()
HttpContext.Current.Response.End()
this worked for me - adb logcat DownloadManager:I *:S
that shows in the adb logcat only things from the downloadmanager. i am on a samsung galaxy s4 so if you have something different and you probably do you have to find out the name of your download manager by google, or start the log : use "adb logcat" do that, and then download the file then quickly scroll up to stop the adb from printing more stuff, and then find it.
i got this problem:
I/DownloadManager( 9250): Initiating request for download id = 2011 with mAllowedNetworkTypes = -1 forP2Pbit = 8194
W/DownloadManager( 9250): Aborting request for download 2011: http error 403, mContinuingDownload: false FinalStatus = 403
i think it has something to do with my server but my server works just fine. so im not sure why it is breaking
Related
I'm building a short python script, logging into a website and grabbing some data on the page, using requests.
The script runs perfectly fine on my Mac, but when launched in Kivy Launcher, I get a certificate error, and the data is not grabbed
The code is as follows :
s = requests.session()
response = s.post('URL', data=form)
responsetext = response.text
On my Mac, responsetext is the data I need. On Android, I get the same message as here : "SSL: CERTIFICATE_VERIFY_FAILED" Error and the variable remains empty. I of course have tried the solutions proposed in the said post, but they are of course NOT working.
I can't use Kivy's UrlRequest because I need to stay logged into the website (and thus using Requests' sessions)
Thanks !
I've stored my .apk file in my rails server. I've set up a route that redirects a given url to a method that essentially sends the file
in my routes.rb file
match '/myApk.apk' to: 'upgradeapk#index'
Upgradeapk_controller.rb file
def index
#filename = '/myApk/myApk.apk'
#tmpfile = 'upgradedApk.apk'
send_file(#filename, :disposition => 'inline', :stream => true, :type=> 'application/vnd.android.package-archive', :file_name => #tmpfile)
end
When i type my sever url and add '/myApk.apk' it starts the downloading process as long as i do it on my a computer. However if i try to do it on my android device it doesn't work. Checking the download lists in my android device browser i notice that the download "job" for the apk is created, however its in an endless loop changing between states "in queue" and "downloading". Nothing ever downloads.
Do I have to set the send_file differently when it comes to making it work on android devices?
----EDIT------
Ok so i've decided to store the files in a dropbox location instead of storing it in my server. If i pass the url for the file directly in my android function for the http request, it works well. The file is found, downloaded and the installation is prompted.
class UpgradeapkController < ApplicationController
def index
android_apk = Androidaplicacion.first (Model to access the table in which i store the apk dropbox url)
route = android_apk.url
redirect_to route
end
end
I've set up my controller to redirect to the given url for the dropbox file. If i try the url (same as before, using the "match" url) in my android browser, this time it downloads. However, if I try it from the android app, its the same as before, it just doesnt download.
So, the "send_file" method seems to not be working if its on the android platform. redirecting to my dropbox url from the controller works on android but only from a browser, not using the http request on my android app. The only way to get it to work in my android app is if I use the dropbox direct link.
Also, I first thought this was because my server was running on https and the certificate its not a valid one. I found a way to bypass the https certification encryption/certificate validation thing on my android app but it didnt work either (it appeared to have succeed in avoiding the validation) but the results ended up been the same. I then ran an instance of my server using http and still same results.
Grails 1.3.7
I have some code that looks like this...
response.setHeader("Content-disposition", "attachment; filename=${fileName}")
response.contentType = download.contentType
response.contentLength = file.length()
response.outputStream << file.getBytes()
On the desktop and on the iPad, the downloads work just fine. But on android devices it just gives me "Unknown myserver.com In progress". And then eventually fails. A couple of points...
This happens locally, staging, and on production servers
Testing without SSL, everything works fine.
When I try the download in the Dolphin Browser I get the same results
with an added bit of text "Waiting for data connection"
Update #2: Stacktrace that only occurs when downloading from an Android device:
Stacktrace follows:
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at com.sun.net.ssl.internal.ssl.OutputRecord.writeBuffer(OutputRecord.java:297)
at com.sun.net.ssl.internal.ssl.OutputRecord.write(OutputRecord.java:286)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:743)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:731)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at com.wbr.consumer.ProductController$_closure1_closure2.doCall(ProductController.groovy:30)
at com.wbr.consumer.ProductController$_closure1.doCall(ProductController.groovy:28)
at com.wbr.consumer.ProductController$_closure1.doCall(ProductController.groovy)
at java.lang.Thread.run(Thread.java:680)
I realize this is a few months late but I also ran into this issue with the Android browser and a Grails application I was working on.
The issue appears to be how Android handles downloadable content and the android browser integration with download manager.
http://code.google.com/p/android/issues/detail?id=1978
http://code.google.com/p/android/issues/detail?id=18462
I was receiving two requests on the server side for a downloadable file; one from the browser and one from the download manager. The one from the browser ends up getting terminated and the socket closed as soon as the browser determines that it is downloadable content. The browser then hands off the download to the download manager.
I was also having issues with the download failing from download manager but that had to due with me not sending headers as soon as they were ready. I ran into this only with larger APKs, small APKs (under 10-20K) seemed to download just fine.
Some code may help:
response.contentType = 'application/vnd.android.package-archive'
response.addHeader('Content-Disposition', 'attachment; filename=FILENAME.APK')
// output file content
response.setStatus(200)
response.setContentLength("CONTENTSIZE")
// send headers
response.flushBuffer()
try {
response.outputStream << {FILE}.getBytes()
response.outputStream.flush()
} catch (SocketException e) {
log.error(e)
}
return
With this, I always end up with one socket exception. Don't know if thats avoidable, from some quick searching I didn't see a way to determine socket state from servlet without simply trying to write to the socket.
It sounds like there are potentially 2 issues
the browser you are using does not trust the self signed cert.
Do other SSL sites work from this browser?
Can you install your STG
cert into the browser's trusted certs store?
A stupid question is : did you get the request URL correct? https vs http ... i know it's stupid.....
the response is never flushed to the client. Try this:
response.outputStream.flush()
I am creating an aplication that involves an WebView. The thing is that I want to load the full page and not the mobile one, so I have changed the User Agent. Nevertheless there are pages that loads the mobile version.
Here are two versions of code that I have tried:
1.webview.getSettings().setUserAgentString("Mozila ");
2.
String DESKTOP_USERAGENT = webview.getSettings().getUserAgentString ();
DESKTOP_USERAGENT = DESKTOP_USERAGENT.replace("Mobile ","");
webview.getSettings().setUserAgentString(DESKTOP_USERAGENT);
This are exemples of webpages that loads the mobile version in any cases:
http://www.jurnalul.ro
http://www.androidzoom.com
1.Does anyone knows how I can trick the server and tell him I am using a desktop and not a mobile?
2.How does a website knows that I am using a mobile version?
Thank you very much,
Razvan
The problem may be that if you are using a device that your carrier is routing all your HTTP requests through a proxy, and that the proxy is changing the User-Agent. Check on the other end, with your own server, using nc -l 80 -vvv that your request is indeed sending the User-Agent that you have modified.
EDIT: Some specific troubleshooting steps
Forward a port 9090 on your router to your desktop machine or laptop.
Download netcat
Run netcat with the command "nc -l 9090 -vvv"
In your Android application's WebView, make an HTTP request with the User-Agent you are injecting to http://your.ip.address:9090
In the terminal you ran netcat, you will see the HTTP request dump in plain text. There you can check the HTTP header User-Agent to see if it has been changed by a proxy server or not.
You cannot test this stuff with Wireshark or Fiddler because it is happening in the WAN. You need to test it on the receiving end, either on a server, or on your own desktop machine.
webview.getSettings().setUserAgent(1);//for desktop 1 or mobil 0.
If I have a file made available to a browser through my webapp, I normally just set the URL to something like http://website.com/webapp/download/89347/image.jpg. I then set the HTTP headers Content-Type: application/octet-stream; filename=image.jpg and Content-Disposition: Attachment.
However, on the Android. It seems the only way I can get the file to download is to set Content-Type: image/jpg. Otherwise the file name says <Unknown> and an error comes
Download unsuccessful
Cannot download. The content is not supported on this phone
Is there any way I can get Android to download and open the file through the browser without keeping a list of mime types?
To make any downloads work on all (and especially older) Android versions as expected, you need to...
set the ContentType to application/octet-stream
put the Content-Disposition filename value in double quotes
write the Content-Disposition filename extension in UPPERCASE
Read my blog post for more details:
http://digiblog.de/2011/04/19/android-and-the-download-file-headers/
Dmitriy (or others looking for a possible solution) if an html page is appearing in your downloaded file, I suspect this is due to the double HttpRequest GET issue. A typical scenario is the following POST, Redirect, GET model:
Android browser issues a HttpRequest POST to server (e.g. submit button or link to request a download file, filename.ext say)
Server streams the requested filename.ext to bytes, stores in a session variable, and then issues a Response.Redirect to Download.aspx, for example, to handle the response object construction
Android browser correctly sends HttpRequest GET to server for Download.aspx
Server responds with typical Content-Disposition: attachment; filename="filename.ext" style construct with the response object containing the requested filename.ext, being the bytes in the session variable.
Android download manager, I believe, then sends another HttpRequest GET to server for Download.aspx. I suspect that the download manager interprets the previous "attachment" response as a trigger to send this second GET.
Server (Download.aspx) again tries to construct the response object to send back to the browser.
Android download manager downloads filename.ext, using the response object contents from the second Download.aspx.
In many scenarios this would be fine. But if, for example, the server in the Download.aspx code does some housekeeping and removes the session variable the first time it is called, then the next time around there is no session variable. So, depending on how the code is written it is possible that the response object doesn't get explicity constructed and maybe the Response.End doesn't get called and so only the Download.aspx's html ends up being sent.
This is what we discovered using Wireshark, although I admit I am assuming it is the Android download manager that is the cause for the double GET.
I hope this explanation has been of some help.
As I wrote at downloading files from android:
Android browser will not download file in button Post events. In post events the file will be some .htm garbage file. to over come this do as below.
In download button click
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
Response.Redirect("download-file.aspx");
}
and on download-file.aspx file do as below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class mobile_download_file : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string filename = "usermanual.pdf";
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + "" + filename + "");
Response.Write(Server.MapPath(Request.ApplicationPath) + "\\" + filename);
Response.TransmitFile(Server.MapPath(Request.ApplicationPath) + "\\" + filename);
Response.End();
}
}
the same can be implemented in php also.
I have tried all recommendations from Jspy blog and nothing worked so far. Content-disposition brings browser in downloading mode, however nothing gets downloaded except HTML of page from which download got initiated. So my conclusion, it is pure bug from Google and we may only pray for that Google fix it. My work around was to set content type to some type coming from Accept header form mobile browser. It generally works, you can even download zip files as text.
In theory, the filename parameter should be set on Content-Disposition, not Content-Type. Not sure whether this will help with the Android browser.