I inherited an .net application that allows users to download a pdf. Now, I am able to download the pdf file when I run locally but when I deploy to IIS server I run into problems. The download works on Firefox but doesnt work on Chrome, and sometimes on IE. The fact that I can download it on my local development environment tells that it could be something with IIS configuration or maybe my code. The pdf is stored in ms sql server 2012 table as varbinary. I provided some code below that is used to read the data. Please let me know if there are other information you all need. Also, I checked the iis logs and I am getting 200 status codes for everything. Nothing stands out in there.
if(Session["DetailID"] != null)
{
//get the file
DataTable dt = sp_Attachment_Download(lblAttachmentIDD.Text);
DataRow row = dt.Rows[0];
string name = (string)row["AFileName"];
string contentType = (string)row["AFileType"];
Byte[] data = (Byte[])row["AFile"];
/// Send the file to the browser
Response.AddHeader("Content-type", contentType);
Response.AddHeader("Content-Disposition", "attachment; filename=" + name);
Response.BinaryWrite(data);
Response.Flush();
Response.Close();
}
EDITED----------
I am using the developer tools for IE and Chrome and found something interesting. Chrome gives me the following error when I click on the link:
interpreted as Document but transferred with MIME type application/pdf:
IE doesnt give an error but something caught my attention. I my REQUEST header, ACCEPT does not contain application/pdf and the RESPONSE Content-Type has application/pdf. Could this be something? How can I set the ACCEPT to include application/pdf in aspx page?
I had kinda similar issue when downloading pdf from chrome as in my case filename had a comma in it and that chrome apparently didn't like it, so I removed comma from filename and it worked.
PS: Please try not to use Response.Close(). It aborts the thread and throws exception.
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename=" + fileName.Replace(",",,");
Response.CacheControl = "No-cache";
Response.Write(data);
Response.Flush();
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
Maybe this will help, here's my code to do the same thing. One thing that I noticed is that you're not specifying the file length, which I believe is required. Please note that pFileData is class that contains FileName, a string, and FileData, a byte[].
System.Web.HttpResponse Response = System.Web.HttpContext.Current.Response;
Response.Clear();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=" + pFileData.FileName);
Response.AddHeader("Content-Length", pFileData.FileData.Length.ToString());
Response.BufferOutput = false;
Response.BinaryWrite(pFileData.FileData);
Response.Flush();
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
Response.End();
Related
Done everything I could with the code to fix it but Veracode still gives error for the following code:
Byte[] bytes = (Byte[])dt.Rows[i]["Content"];
Response.Buffer = true;
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = StringEncode(HttpUtility.HtmlEncode(dt.Rows[i]["Extension"].ToString()));
Response.AddHeader("content-disposition", "attachment;filename=" + StringEncode(HttpUtility.HtmlEncode(dt.Rows[0]["FileName"].ToString())));
Response.BinaryWrite(bytes);
Response.Flush();
Response.End();
It points to the line with Response.BinaryWrite(bytes);
What should be done?
Any suggestions?
I think you can safely mark this as a false positive when your users are using modern browsers.
Setting content disposition to download the response as an attachment should prevent any scripting from being executed in the browser. It appears that Veracode has not picked up the fact that you are doing this.
Note that old browsers like IE 6/7 will ignore the the content-disposition header if they already have the response cached. You could possibly detect the cases when these browsers are used and prevent the content from loading in these browsers.
I tried to get a pdf file opened in chrome but it seems to be stuck in the middle of somewhere during displaying process. The code seems to work because it can get PDF opened in IE, not sure why it got stuck in chrome. The screen will just grey out, show the "LOADING" sign, and stop at 7/8. The file is around 6MB or more.
public static void ReturnPDF(byte[] contents)
{
var response = HttpContext.Current.Response;
response.Clear();
response.AppendHeader("Content-Disposition", "inline;filename=" + "abc.pdf");
response.BufferOutput = true;
response.ContentType = System.Net.Mime.MediaTypeNames.Application.Pdf;
response.BinaryWrite(contents);
response.Flush();
response.Close();
response.End();
}
Any thoughts? Thanks
[UPDATE]
I tried firefox with version 30.0 and it WORKS. My IE is 8.0.7601.17514, which can also open pdf. My Chrome is 39.0.2171.95. Not sure wheather the version of the browser matters or not, here only chrome fails to open the inline PDF...
[SOLVED]
After adding content-length, chrome can open the inline PDF.
public static void ReturnPDF(byte[] contents)
{
var response = HttpContext.Current.Response;
response.Clear();
response.AppendHeader("Content-Disposition", "inline;filename=" + "abc.pdf");
//After adding Content-Length, chrome is able to open PDF inline
response.AppendHeader("Content-Length", contents.Length.ToString());
response.BufferOutput = true;
response.ContentType = System.Net.Mime.MediaTypeNames.Application.Pdf;
response.BinaryWrite(contents);
response.Flush();
response.Close();
response.End();
}
The OP's original code created the response like this:
response.Clear();
response.AppendHeader("Content-Disposition", "inline;filename=" + "abc.pdf");
response.BufferOutput = true;
response.ContentType = System.Net.Mime.MediaTypeNames.Application.Pdf;
response.BinaryWrite(contents);
response.End();
This code especially does not set the Content-Length header. Some web browser versions (not only Chrome but also certain versions of other browsers) without that header tend to prematurely consider the download finished.
Detecting when a download is finished on a connection initially created as persistent, may not be trivial if neither a non-identity Transfer-Encoding nor a Content-Length has been supplied.
Thus, the solution here is to add
response.AppendHeader("Content-Length", contents.Length.ToString());
before writing the contents.
Try with "Content-disposition: attachment" header.
Thanks mkl's suggestions.
I added the content length in the header and the pdf can be successfully opened in Chrome!
I have an ASP.NET page and a c# method that takes a memorystream (of an excel-file) and then uses the HTTPResponse-class to stream this file, in binary, to the browser.
public static void WriteStreamToBrowser(MemoryStream streamExcelFile, string filename, bool isResponseEnd = false)
{
System.Web.HttpResponse Response = System.Web.HttpContext.Current.Response;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", filename));
Response.Clear();
Response.BinaryWrite(streamExcelFile.GetBuffer());
}
Now this method works FINE when I use my asp.net page in Firefox or Chrome. They neatly trigger the websites "do you want to download this file" feature.
However, when using IE11, the browser window instantly closes but the "do you want to download this file?" dialog actually pops up and remains.
I'm guessing that IE needs some special treatment when it comes to the Response-methods but I haven't been able to figure out what I do wrong.
How do I change the above method so that will also work with IE11?
--
Let me know if you need any extra details!
EDIT:
Worth mentioning is that debugging does not throw any exceptions.
Also, the dialoge that pops up is actually the download history.
EDIT 2:
I've tried to follow some advice from other guides and added some stuff. Still, resultat is the same.
public static void WriteStreamToBrowser2(MemoryStream streamExcelFile, string filename, bool isUseNewExcel = true)
{
System.Web.HttpResponse Response = System.Web.HttpContext.Current.Response;
string contentType = isUseNewExcel ? "application/vnd.ms-excel" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", filename));
Response.AddHeader("content-length", streamExcelFile.Length.ToString());
Response.AddHeader("content-type", contentType);
Response.BinaryWrite(streamExcelFile.GetBuffer());
//to avoid ThreadAbortion
Response.Flush();
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
Response.Close();
}
Alright, I managed to solve the broken excel download by adding a +".xls" to the file name. Why IE but not Chrome and Firefox requires you to explicitly define the extension in the filenamestring, I will never know. To be clear, this did not solve my problem with IE closing my main window but that's not an issue right now.
I have a byte array in the database and i need to show that in a pdf file format. Here is the way i did that. However, this doesn't work on Android tablets(checked in 2.3.5 and 3.2).
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.BufferOutput = true;
Response.Buffer = false;
Response.AddHeader("Content-Length", binaryData.Length.ToString());
Response.AppendHeader("Content-Disposition", "inline;filename=ClientDocument.PDF");
// Response.BinaryWrite(binaryData);
Response.OutputStream.Write(binaryData, 0, binaryData.Length);
Response.End();
Can you guys think of any way i could make it work on all the browsers?
Appreciate the help
Thanks
Couple of things...
Change the content type to correct mime-type of PDF files. There are vast array of these in use application/pdf, application/x-pdf, application/acrobat, applications/vnd.pdf, text/pdf, text/x-pdf", we just use application/pdf.
Response.ContentType = "application/pdf";
Then if you want the browser to open and display the PDF file, remove the Content-Disposition header.
... or ... if you want the browser to download the PDF file change the Content-Disposition type to "attachment" rather than "inline".
Response.AppendHeader("Content-Disposition", "attachment;filename=ClientDocument.PDF");
Have you upgraded to latest version of Android on the test tablets/phones?
That fixed it for me when I had a similar problem (PDFs not opening or downloading when sent to browser from stream or byte[] on Android only).
I'm trying to send an xlsx file by using
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "application/vnd-ms.excel";
Response.TransmitFile(file.FullName);
Response.End();
The IE dialog pops up and I can successfully save the file, then open it from the folder, that works fine and dandy. But if I click on "Open" in the IE dialog, I get a "myFile.xlsx couldn't be downloaded." I click on "Retry" and it opens Excel but pops up the "Excel cannot open the file 'myFile.xlsx' because the file format or file extension is not valid..." error.
I'm currently running the site from VS2010 in debug mode.
Does anybody know why it would let me save, but not open directly?
Edit
Chrome just downloads it. FF tried opening it but gives the error The file you are trying to open, 'myFile.xlsx.xls', is in a different format than specified by the file extension... I can choose to open it anyways and it successfully opens, but in readonly mode.
So, something funky is going on here.
fileName = "myFile.xlsx"
Edit 2
This is in IE 9. I've also tried octet-stream and application/vnd.openxmlformats-officedocument.spreadsheetml.sheet as the ContentType.
It is because your ContentType is wrong. Use
Response.ContentType = "application/vnd.ms-excel";
Edit
if it didnt work, can you try
FileStream sourceFile = new FileStream(file.FullName, FileMode.Open);
float FileSize;
FileSize = sourceFile.Length;
byte[] getContent = new byte[(int)FileSize];
sourceFile.Read(getContent, 0, (int)sourceFile.Length);
sourceFile.Close();
Response.ClearContent();
Response.ClearHeaders();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Length", getContent.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.BinaryWrite(getContent);
Response.Flush();
Response.End();
I had the same problem once, and solved by revising caching instructions sent by application server, in this case, IIS. Sometimes you add headers at application level that prevents the file from being saved in some conditions, like in HTTPS connections. Make sure that you aren't putting conflicting instructions.
I ran into similar issue.
Turned out I was reading from end of the stream so, the byte array wasn't getting filled with anything.
Setting the stream position to 0 (sourceFile.Position=0;) just before reading the stream (sourceFile.Read(getContent, 0, (int)sourceFile.Length);) fixed it for me.
See if that helps.
As for "Response.ContentType", "application/vnd.ms-excel" worked for me.
FileStream sourceFile = new FileStream(file.FullName, FileMode.Open);
float FileSize;
FileSize = sourceFile.Length;
byte[] getContent = new byte[(int)FileSize];
sourceFile.Position=0;
sourceFile.Read(getContent, 0, (int)sourceFile.Length);
sourceFile.Close();
Response.ClearContent();
Response.ClearHeaders();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Length", getContent.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.BinaryWrite(getContent);
Response.Flush();
Response.End();
By coincidence I'm right in the middle of something similar...
The MIME type to use for xlsx is application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, see this question.
I was stumped by this issue, particularly with longer files.
Turned out in our case using the Content-Length header fixed the issue. Once the content gets over a certain length, you get this issue.
Example (where tempsbldr is a StringBuilder):
Response.AddHeader("Content-Length",tempsbldr.Length.ToString());