0

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)
Gregg
  • 34,973
  • 19
  • 109
  • 214

2 Answers2

2

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.

user886158
  • 21
  • 2
0

It sounds like there are potentially 2 issues

  1. 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.....
  2. the response is never flushed to the client. Try this:

    • response.outputStream.flush()
dbrin
  • 15,525
  • 4
  • 56
  • 83
  • 1. Everything else in my SSL site works. Just not the downloads. I don't what you mean by "STG" cert. Yes, the request URL is correct. 2. I'll try that, but still doesn't tell me why it works in desktop and iOS, just not android. – Gregg Nov 09 '11 at 05:37
  • 2. flushing doesn't make a difference. See my updated question above for more information – Gregg Nov 09 '11 at 05:48
  • I c. So a broken pipe can be caused by client potentially closing the connection too early (like a timeout or a mis-communication of content length perhaps). Is this a large file? – dbrin Nov 09 '11 at 06:50
  • looks like you are not alone: http://stackoverflow.com/questions/5927481/android-java-net-socketexception-broken-pipe-lg – dbrin Nov 09 '11 at 07:00