For a long time (quite a long time for an issue of such small size) in my project, we had this issue: file downloaded over SSL connection fails with strange error. After hunting in various woods (read articles) in several planets (read web sites), I found that solution was nowhere to be found easily but it was available as part of the application already.
Here’s the scenario:
The application is written in ASP.NET/ C# 2.0 and it runs over SSL (HTTPS) in production. User is allowed to upload a file in a certain module in the application (say, Profile -> Options page). A link in the home page of every user is the provision to download this file. That is all – no big fuzz in the implementation as such.
There are other few environmental setups which influenced this particular issue to slip till the production release The development environment was not using SSL certificates for obvious reasons; I mean who would want to set up a certificate for a dev environment? (It turned out, at least in QA environment it helps when the exact production settings are simulated – this is one more thing we overlook.)
File Download Issue:
When the application moved to QA environment, there were two types of errors experienced. The scenario goes like this: The user clicks on the link (to download the file) one of the following might occur
- IE throws an error “Internet Explorer cannot download ABC.XYZ from http://www.mycompany.com” and does not even download the file
The error message being "Internet explorer cannot download file from site. Internet explorer was not able to open this Internet site. …" - IE shows the ‘Open/ Save’ dialog
- When ‘Open’ is clicked, the file opens in the appropriate editor (say Adobe Acrobat reader) and shows ‘File not found error’
On inspection (using Sysinternals FileMon tools), we found that file is deleted by the IE browser as soon the ‘open’ button is clicked on the dialog. This is not the case in FF browsers - When ‘Save’ is clicked, things go smooth as expected.
- When ‘Open’ is clicked, the file opens in the appropriate editor (say Adobe Acrobat reader) and shows ‘File not found error’
The issue #2 was not seen lately, so I didn’t give it a priority. I’ll talk about how issue #1 was solved below.
‘Code’ Behind:
Here are few details about the application…
- Application is based on ASP.NET/C# 2.0 deployed on WinServer2003/HTTPS (Production/ QA environment). We use normal FileUpload control in ASP.NET for uploading the file.
- The uploaded file is stored in the database in ‘Image’ type field of one of the tables. Database is run on SQL Server 2000
- On click of the link to download, the file is read from the database and streamed to the HTTP Response using appropriate headers (see attached code: entity class and utility class)
Initial Research:
The initial research didn’t lead to any place meaningful – couple of support KBs, few forums, and couple of blogs – but nothing seemed to give correct solution. Here are the links that I ended up in the initial search!
- http://support.microsoft.com/?kbid=319032
- http://support.microsoft.com/default.aspx?scid=kb;en-us;316431
- http://nilangshah.wordpress.com/2007/05/28/successfully-stream-a-pdf-to-browser-through-https/
- http://it.toolbox.com/blogs/paytonbyrd/successfully-stream-a-pdf-through-https-1554
I did find something interesting – that too in our intranet projects portal’s FAQ section – which again didn’t direct me to any solution but gave few reasons why it was a browser issue and few links which ‘proved’ that it wasn’t anything to do with code. (All these actually convinced me that there nothing we could do to solve this )
Understanding how the wheel works and extend it to my issue:
I really wanted to do a ‘root cause analysis’ for this issue as it was bothering me for a significant time, I knew there is one another similar feature wherein the application throws up the PDF file to the user in the ‘Open/ Save’ dialog.
When I found how it was implemented, I was surprised and shocked! – surprised because it was lying all along in the space place much near to what I was looking for and shocked because this particular way to implementing the feature was hidden due to the fact that the faulty code which I’ve been working on lately was an initial (aka 1st release) implementation which now has surpassed about 8+ releases.
So I didn’t even imagine doubting the component code that was supposed to achieve the expected behavior (it failed to do anyway) – and all these took some quite a humongous amount of effort – which I feel should not have been wasted given that one another working solution for similar problem is there in the application already! Well, whatever, we got what we wanted – scrutiny later.
Solution:
The solution itself is very simple (at least in our case).
- There should a temporary location which the website can access with RW permissions
- Create a virtual directory (in case of Win server 2003, create within the website) and make it point to the temporary location. Let’s call this ‘\tmpFolder’
- Create a HTTP Handler class (inheriting IHttpHandler) you can refer to this KB
- In <system.web> section of config file, add httpHandlers, like the given below
<system.web> <!-- This is used for File Download --> <httpHandlers> <add verb="*" path="FileRetrieveHandler.aspx" type="MyNameSpace.FileHandler, MyNameAssembly"/> </httpHandlers> <!-- ... Rest of System.Web section --> </system.web>
- When you to open the file to the Response stream, do the following instead of directly writing to the Response stream
- Write the file to the temp location
- Redirect the response to the custom http handler by passing the filename also
- I’m sure this could be optimized for performance and security, but I keep it open for comments! J
Okay, the main focus here should the use of HTTP handler. The reason why temp folder was used, in my case, is that similar solution was already implemented in the application. So instead of steps 1 and 2, one could even choose to read the file inside the HTTP handler or use a wrapper that do the job as you wish!
Couple of more issues noticed:
When the file being downloaded has some specifics characteristics, different browsers behave differently – this was also quite interesting… For e.g. lets take the file name as "My F#& # .pdf"
- In IE 7 (or IE 8 b1), the white space is replaced with underscore. Ref this.
- In our case the filename in open/ save dialog becomes ‘My_F_&___.pdf’
- This cannot be fixed – (rather, shall not be! Since there is no correct solution and is by design in IE7 and IE8 beta1)
- In FF, the final downloaded file name was just “My” – the part of file before the first white space. FF forum blames IE for not implementing prescribed international standard. Read this.
- We’ll follow the standard mentioned in RFC 2231 of IETF, as recommended by FF forum, which works pretty fine in any situation on any browser!
I’ve submitted this to IE forums here, let’s see what happens next!
Few things learned in the course of finding the solution:
- How to install, configure and issue a SSL certificate and configure website to use HTTPS – from here
- Detailed look up on HTTP Handlers and different ways to implement/ enforce file download
More comments and critics welcome!
Beautify the web! Share this : |