4

I am sending a file from ASP.NET Page to the browser. To properly send a filename I am adding a header:

Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);

The problem is that when file contains white spaces (e.g. "abc def") browser receives only "abc" part of the filename. I have tried with: Server.HtmlEncode but it didn't help.

Do you have any idea how to solve this problem?

PK

pkolodziej
  • 1,347
  • 3
  • 17
  • 24

4 Answers4

10

Put the file name in quotes:-

Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
4

Don't UrlEncode. This is not the right way to escape a value for use in an HTTP structured header parameter. It only works in IE due to that browser's buggy handling, and even then not reliably.

For a space you can use a quoted-string as suggested by Anthony (+1). But the dirty truth of Content-Disposition is that there is no reliable, supported escaping scheme that can be used to put arbitrary characters such as ;, " or Unicode characters in the filename parameter. The only approach that works reliably cross-browser is to drop the filename parameter completely and put the desired filename in the URI as a trailing, UTF-8+URL-encoded path part.

See this answer for some background.

Community
  • 1
  • 1
bobince
  • 528,062
  • 107
  • 651
  • 834
  • Typically in a windows environment ; isn't a valid filename character anyway. I tend to put anything that uses this filename parameter through a "legal-in-filename" sanitizer to take out such characters. – AnthonyWJones Oct 19 '09 at 13:54
1

Filename with special symbols(e.g: space; # @ ! $ ) or Non-Unicode characters either cannot be supported by some browsers or cause incorrect filename in client machine. Here is an article by a Chinese called chanext, he gave a perfect way to solve this problem: this article gave a sample code(written with c#) to show how to get perfect solution to this problem in the all four popular browsers (IE; Opera; Firefox and Chrome) the filename "Microsoft.Asp.Net.doc" and "F ile;;!@%#^&y.doc" can both be output correctly using the way the author provided in this article.

http://ciznx.com/post/aspnetstreamdownloaddisplaynonunicodespacechar.aspx

Koen
  • 3,626
  • 1
  • 34
  • 55
chanext
  • 31
  • 1
0

Based on the code referenced by @chanext I cleaned it up and put it into a single extension method. Hope this can help someone.

Partial Class Uploader
  Inherits Page

  Private Sub UploadFile()
    Dim sFileName As String
    Dim oPdf As MigraDoc.Rendering.PdfDocumentRenderer

    sFileName = "File Name With Spaces #22.pdf"

    With Me.Request.Browser
      If .Browser = "InternetExplorer" OrElse .Browser = "IE" Then
        sFileName = sFileName.EncodeForIE
      Else
        sFileName = String.Format("""{0}""", sFileName)
      End If
    End With

    oPdf = New MigraDoc.Rendering.PdfDocumentRenderer
    oPdf.Document = FileFactory.CreatePdf()
    oPdf.RenderDocument()

    Using oStream As New MemoryStream
      oPdf.Save(oStream, False)

      Me.Response.Clear()
      Me.Response.ContentType = "application/pdf"
      Me.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", sFileName))
      Me.Response.AddHeader("content-length", oStream.Length)
      Me.Response.BinaryWrite(oStream.ToArray)
    End Using

    Me.Response.Flush()
    Me.Response.End()
  End Sub
End Class



Public Module StringExtensions
  <Extension()>
  Public Function EncodeForIE(Url As String) As String
    Dim _
      sReservedChars,
      sEncodedString As String

    sReservedChars = "$-_.+!*'(),@=&"

    With New StringBuilder
      Url.ToList.ForEach(Sub(C)
                           If Char.IsLetterOrDigit(C) OrElse sReservedChars.Contains(C) Then
                             .Append(C)
                           Else
                             With New StringBuilder
                               C.ToBytes.ToList.ForEach(Sub(B)
                                                          .AppendFormat("%{0}", Convert.ToString(B, 16))
                                                        End Sub)

                               sEncodedString = .ToString
                             End With

                             .Append(sEncodedString)
                           End If
                         End Sub)

      Return .ToString
    End With
  End Function

  <Extension()>
  Public Function ToBytes(Chr As Char) As Byte()
    Return Encoding.UTF8.GetBytes(Chr.ToString)
  End Function
End Module
InteXX
  • 6,135
  • 6
  • 43
  • 80