Streaming File Download fails/error over SSL (HTTPS) – Issue & Solution

July 30, 2008

 

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.  smile_sarcastic 

 

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 smile_regular 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

  1. IE throws an error “Internet Explorer cannot download ABC.XYZ from http://www.mycompany.com” and does not even download the file

    doc download3
    The error message being "Internet explorer cannot download file from site. Internet explorer was not able to open this Internet site. …"

  2. IE shows the ‘Open/ Save’ dialog
    1. 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
    2. When ‘Save’ is clicked, things go smooth as expected.

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…

  1. 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.
  2. The uploaded file is stored in the database in ‘Image’ type field of one of the tables. Database is run on SQL Server 2000
  3. 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. smile_omg Here are the links that I ended up in the initial search!

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 smile_sad)

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! lightbulb – 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. smile_shades

Solution:

The solution itself is very simple (at least in our case).

  1. There should a temporary location which the website can access with RW permissions
  2. 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’
  3. Create a HTTP Handler class (inheriting IHttpHandler) you can refer to this KB
  4. 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>
  1. When you to open the file to the Response stream, do the following instead of directly writing to the Response stream
    1. Write the file to the temp location
    2. Redirect the response to the custom http handler by passing the filename also
  1. 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"

  1. In IE 7 (or IE 8 b1), the white space is replaced with underscore. Ref this.
    1. In our case the filename in open/ save dialog becomes ‘My_F_&___.pdf’
    2. This cannot be fixed – (rather, shall not be! Since there is no correct solution and is by design in IE7 and IE8 beta1)
  2. 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.
    1. 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! smile_regular

I’ve submitted this to IE forums here, let’s see what happens next!

Few things learned in the course of finding the solution:

  1. How to install, configure and issue a SSL certificate and configure website to use HTTPS – from here
  2. Detailed look up on HTTP Handlers and different ways to implement/ enforce file download

More comments and critics welcome!

 

 

Beautify the web! Share this :

 


Adding/ Trapping ‘Return key’ hook to input text box

July 8, 2008
Even though invention of mighty ‘mouse’ has revolutionized the our computer usage, still we are used to lot of typing – it’s not that we like it, we have no other choice (say like ‘speaking to the computer’, at least not in mainstream).

Often we come across either one of these dialog boxes in the web very frequently: Search box, Log in box. When we do use keyboard to input values to those text boxes, we tend to hit ‘enter’ (the ‘return’ key) which is accepted as if you clicked the ‘Go’ or ‘Log in’ or ‘Sign in’ or similar kind of button available just beneath the text box where you were typing. Such buttons are called ‘default buttons’ and the actual action of hitting the enter key takes.

Most of the times this doesn’t have to be a problem for a web developer – the behaviour that "when  ‘enter’ key is pressed, the event for ‘default’ button should be activated". when you just mention one particular button to be ‘default’ for the page, all such ‘enter’ key actions will be taken as the default button being clicked.

Well, all seems to work fine, but you wonder why am I writing this? If you look closer, the ‘default’ button that you could mention only one default for a page, yes! So, imagine a page with a search box, log in box, couple of others (or imagine a dashboard or home page with lot of sections) each having their own ‘default’ buttons. That’s the kind of situation one will have to do something more to make the ‘default’ button work for each section and only for that section correctly.

In general, this can be achieved by adding  a ‘key hook’ to the text box, commanding the browser to do something our way whenever enter key is hit from the text box.This is made feasible with help of JavaScript.

Here’s an article on how to fix this thing!


Have you forgot something..? ASP.NET Peformance Tips

May 17, 2007

Before anyone starts
the development process in the web application projects, I feel they should definitely have a look at
this…

http://samples.gotdotnet.com/quickstart/aspplus/doc/perftuning.aspx

The article
starts with

             Any programming model has
its common performance pitfalls, and ASP.NET is no exception…

Now making
them better or worse is in the hands of the project team as a whole, but developers in particular.


Having
these in our mind will not only increase the performance of the web application
but also help us,


  • develop
    a robust development environment during design time

  • understand
    adapt best practices

  • overall,
    become a better web developer

Just thought it would be useful to
revisit our basics on web development!


Invalid ViewState error – a rare case scenario

March 24, 2007
 
Alright! It’s another ASP.NET 2.0 blog. Recently I got a query with a set of exception details logged in to database of a web site which went live few weeks back. The main focus was with two type of exceptions Invalid length for a Base-64 char array. and Invalid character in a Base-64 string.
 
It contained few of lines similar to

1129     0          -1         Information                    2007-03-22 19:11:43.377            <server_name>            <some_application_domain>      4716     c:\windows\system32\inetsrv\w3wp.exe   NULL    5900            Invalid length for a Base-64 char array. –   Timestamp: 3/22/2007 7:11:43 PM  Message: Invalid length for a Base-64 char array. –   Category: <some_category>  Priority: -1  EventId: 0  Severity: <some_severity>  Title:  Machine: <some_machine> Application Domain: <some_application_domain>  Process Id: 4716  Process Name: c:\windows\system32\inetsrv\w3wp.exe  Win32 Thread Id: 5900  Thread Name:   Extended Properties: Username – Unauthenticated  StrackTrace –   Source –   InnerExceptionStackTrace –    at System.Convert.FromBase64String(String s)    at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)    at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState)    at System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState)    at System.Web.UI.HiddenFieldPageStatePersister.Load()  InnerExceptionSource – mscorlib 

As the title says, the exception was due to ‘Invalid View State’. Here’s the summary of the response that was fired from my inbox quite after I received this query.
 
Possible Reasons: 
This problem may occur in any of the following scenarios
  1. When some kind of encryptions (for eg: text for passwords) are used and  that are basically stored as Base-64 types (data type to stored special encoded string). Each Base-64 types are actually made of 3 bytes. Hence when processing these type of data, when it’s not in multiples of 3, such exceptions occur. 
  2.  The ViewState is also stored in encoded Base-64 format. Another possible victim for this exception.

Resolving the problem reported…:

*Anyway, with the limited amount of exception details that was being mentioned, it’s clear that the exception occurred due to some loss/ truncation in the stored View State information.
(Because the stack trace information starts from the method “System.Web.UI.HiddenFieldPageStatePersister.Load()” which is nothing but the method used to load the ViewState (during Post back) from the HTML.) 
>> Though this does not seem to be exception of type “Invalid_Viewstate_Client_Disconnected” – which actually occurs when the ViewState is corrupt during post back from client, we can’t avoid this option either.
      • The exception details given are not actually sufficient to find the exact point of problem (like IP, User-Agent (browser used), view state itself, path of the requested page).  Now, there is a Hot Fix available, to enhance the amount of exception details logged. (This does not fix any problems though )

 Possible scenarios which would have caused this problem:

  1. The ViewState of the page is too long for the page to hold (limited by the MaxHTTPRequest length specified in web.config) and the view state gets truncated in transit. But this will be less probable since the web site had the MaxHTTPRequest length to 10MB citing some huge file uploads.
    1. Anyway, You can try to slightly lessen this with ViewState Compression techniques. Implementing this is fairly simple.
  2. In a page where there are significant amount of ViewState stored (for eg: Pages with drop down having huge amount of data which you can’t avoid), the user tried to click the button more than once, causing multiple request to be fired and even this would have truncated the View State that’s being posted back to the server.
  3. Another worst possible case would be some one trying to hack into by tampering the view state of your web page 

Exception handling?

And, one more thing! This kind of exception can not be gracefully caught in a try-catch block inside the page, because it is triggered by ASP.NET when ever it finds the ViewState seems to be tampered during transit and happens before even executing the web page’s Page_Load event.

Ok, finally…:

>> Hence, Scenario Case 1 can be controlled only to a limit (the limit you set as maximum HTTP Request size). Case 2 can not be controlled the web site host and Case 3, no way!  Don’t worry, it doesn’t matter.
>> If possible, give a thought to the Hot Fix mentioned, to log more details if it’s already not installed. And, make sure u log all the exception details recursively.

 — EOM —

Any better methods/ fixes available? 

 

  Digg!


3-Tier Architecture with ASP.NET 2.0

October 4, 2006
Many a times, I’ve seen people just wondering how to do a project. For those who are still searching, MSDN has come up with a nice set of tutorials for developing a 3-tier based web application using ASP.NET 2.0
 
Here’s the link
 
Introduction
 
Basic Reporting
Tutorial 5 – Declarative parameters
 
Master/Details
 
This is also available in VB.NET version from here.
 
 Anyway, this is just a tutorial, more can be done in ASP.NET 2.0.

Your First ASP.NET 2.0 WebApp: eLearning!

September 18, 2006
 
Last week, one of friend wanted a simple startup for ASP.NET 2.0 in form of eLearning course.
it’s also for ASP.NET 2.0 starters! An online eLearning from Microsoft is available at
 
 
Just Sign-In with your Live ID (.NET Passport) and add the course to "My Learning section".
 
This course covers
  • Basic difference you should know between VS 2003 and VS 2005
  • ASP.NET 2.0 working model
  • ASP.NET 2.0 basics (Pages, Partial classes, Code Separation, etc..)
  • + An virtual Lab with example of creating an website in VS 2005

 

+> Praveen Kumar