Stefan Steiger
Stefan Steiger

Reputation: 82146

ASP.NET: Why do I get another header than I set?

I have an annoying problem: I should show a PDF in the browser (inline-display, not download).

So far, with the code below, it works for internet explorer. But in google-chrome, it just downloads.

On the same server, a 3rd party application that does the same works fine.
I suppose the problem is the "appliction/octet-stream" that you see in the content-type header...

I find this rather annoying.
My code sets content-type application/pdf, and when I look at the actual headers sent, i see it is application/octet-stream...

According to https://superuser.com/questions/219870/how-to-open-pdf-in-chromes-integrated-viewer-without-downloading-it#

this is because the mime is octet-stream instead of application/pdf...

And I have just one question: Why ? Why ? Why ? (Why does it set octet-stream, not application/pdf as set in the code - See full code below)
Bonus question: Why is Transfer-Encoding chunked if i set Content-Length to the length of the byte-array ?

The funny thing is, it works fine on my local development server, so this seems to have something to do with the evils of IIS >= 7...

Bad HTTP Headers

ashx:

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim baPDF As Byte() = GetPdfFromImage(Me.Data)
        'context.Response.Write(COR.Tools.JSON.JsonHelper.Serialize(Me.Data(context)))

        context.Response.Clear()
        'context.Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName)
        context.Response.AddHeader("Content-Disposition", Portal.ASP.NET.GetContentDisposition("Drucken.pdf", "inline"))
        context.Response.AddHeader("Content-Length", baPDF.Length.ToString())
        ' context.Response.ContentType = "application/msword"
        ' context.Response.ContentType = "application/octet-stream"

        ' https://superuser.com/questions/219870/how-to-open-pdf-in-chromes-integrated-viewer-without-downloading-it#
        ' context.Response.ContentType = "text/html"
        context.Response.ContentType = "application/pdf"



        context.Response.BinaryWrite(baPDF)
        context.Response.Flush()

        context.Response.End()
    End Sub





    ' COR.ASP.NET.StripInvalidPathChars("") '
    Public Shared Function StripInvalidPathChars(str As String) As String
        Dim strReturnValue As String = Nothing

        If str Is Nothing Then
            Return strReturnValue
        End If

        Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder()
        Dim achrInvalidPathChars As Char() = System.IO.Path.GetInvalidPathChars()


        For Each cThisChar As Char In str
            Dim bIsValid As Boolean = True

            For Each cInvalid As Char In achrInvalidPathChars
                If cThisChar = cInvalid Then
                    bIsValid = False
                    Exit For
                End If
            Next cInvalid

            If bIsValid Then
                sb.Append(cThisChar)
            End If
        Next cThisChar

        strReturnValue = sb.ToString()
        sb = Nothing
        Return strReturnValue
    End Function ' StripInvalidPathChars '


    Public Shared Function GetContentDisposition(ByVal strFileName As String) As String
        Return GetContentDisposition(strFileName, "attachment")
    End Function ' GetContentDisposition '


    ' http://www.iana.org/assignments/cont-disp/cont-disp.xhtml '
    Public Shared Function GetContentDisposition(ByVal strFileName As String, ByVal strDisposition As String) As String
        ' http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http '
        Dim contentDisposition As String
        strFileName = StripInvalidPathChars(strFileName)

        If String.IsNullOrEmpty(strDisposition) Then
            strDisposition = "inline"
        End If

        If System.Web.HttpContext.Current IsNot Nothing AndAlso System.Web.HttpContext.Current.Request.Browser IsNot Nothing Then
            If (System.Web.HttpContext.Current.Request.Browser.Browser = "IE" And (System.Web.HttpContext.Current.Request.Browser.Version = "7.0" Or System.Web.HttpContext.Current.Request.Browser.Version = "8.0")) Then
                contentDisposition = strDisposition + "; filename=" + Uri.EscapeDataString(strFileName).Replace("'", Uri.HexEscape("'"c))
            ElseIf (System.Web.HttpContext.Current.Request.Browser.Browser = "Safari") Then
                contentDisposition = strDisposition + "; filename=" + strFileName
            Else
                contentDisposition = strDisposition + "; filename*=UTF-8''" + Uri.EscapeDataString(strFileName)
            End If
        Else
            contentDisposition = strDisposition + "; filename*=UTF-8''" + Uri.EscapeDataString(strFileName)
        End If

        Return contentDisposition
    End Function ' GetContentDisposition '

This is the header of the 3rd party application, where Chrome displays it fine Aperture Headers

Upvotes: 1

Views: 779

Answers (2)

Stefan Steiger
Stefan Steiger

Reputation: 82146

The solution is as simple as it is hideous.

Thanks to a coworker change, the code was in an ashx file directly, not in ashx.vb.

The good part of this is, one can modify the ashx on the server, even when you have a compiled web-application. The bad part is, this has the same effect of compile on the fly as a website project.

Consequently, when you just recompile the application and put the MyWebApplication.dll onto the server, this leaves the old ashx as is.

And since ASP.NET uses the code in the ashx rather than the compiled dll, it always uses the old code, as long as you don't update the ashx file, too.

Changed it now, and it began working immediately.
Now, that was a good one...
There never was a mistake in the code to begin with.

Upvotes: 1

Adam Zuckerman
Adam Zuckerman

Reputation: 1641

You need to clear the headers before setting the header you want.

From Microsoft's page about Response.Clear.

The Clear method does not clear header information.

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
    Dim baPDF As Byte() = GetPdfFromImage(Me.Data)

    context.Response.ClearHeaders()
    context.Response.ContentType = "application/pdf"

    ... ' Cut for brevity
End Sub

Upvotes: 0

Related Questions