Firefox and chrome get different header than IE - asp.net

My .mvc application tries to show a pdf file. It works properly on IE, but fails on Chrome and FF, giving ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION According to similar questions asked here and on other websites, it seems to be a http header problem? When I tried looking at the headers directly, I've found that that responses sent to IE and Firefox differ, as FF gets 3 responses while IE gets 1:
IE response header:
Response HTTP/1.1 200 OK
Cache-Control no-cache, no-store, must-revalidate
Pragma no-cache
Content-Type application/pdf
Expires 0
Server Microsoft-IIS/7.5
X-AspNetMvc-Version 4.0
Content-Disposition inline; filename="Invoice Number US123412.pdf#toolbar=1&view=FitV"
Content-Disposition attachment; filename="Invoice Number US123412.pdf"
X-AspNet-Version 4.0.30319
Persistent-Auth true
X-Powered-By ASP.NET
Date Wed, 19 Apr 2017 12:00:00 GMT
Content-Length 77107
The solution that was given by many people was to add qutation marks ("") around the filename, which I did, but it doesn't seem to help in any way. Here is my header editing code:
Response.AddHeader("Content-Disposition", "inline; filename=\"" + fileName + "#toolbar=1&view=FitV\"");
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.
invoiceHelper.PDF = new InvoicePDF { FileBytes = renderedBytes, FileName = fileName };
return File(renderedBytes, "application/pdf", fileName);
It seems I might be misunderstanding the solution suggested in other threads? Any help would be appreciated.
EDIT:
I should note that I also tried changing the file name to contain no spaces, so that the current response would have Invoice_Number_somenuber12121
EDIT2:
It seems that when I remove my header code, and instead add esponse.ClearHeaders();, the website loads but the pdf is downloaded instead of being shown
EDIT3:
I've found the answer, and so I removed a few parts of this question that weren't significant after all.

a) There can only be one response; maybe what you see is a redirect and a new request?
b) In any case, the error code is pretty clear: you are sending multiple Content-Disposition response header fields. Don't. (Note: it's possible that one of those was added by the framework you're using).

I've found the answer. As is often the case, I found it AFTER i posted on stack overflow, not the whole day I was searching for it before that. As seen in the comment to the answer here: Returning a file to View/Download in ASP.NET MVC , the problem lies with the return File(renderedBytes, "application/pdf", fileName); . The moment you return 3 parameters, the return statement will create its own header. In my case, I just removed the third parameter.
Hint to other people who might have similar problem: try modifying the fileName variable, or some other variable that is used in your header, to pinpoint the more precise location of the problem.

Related

Response header Content-Disposition not doing anything

I am trying to retrieve a file from my server (which is using ASP.NET Core MVC) and display it in the browser. After looking through many threads on here and other sites, the same solution seems to be suggested every time; which is to use Content-Disposition inline in the response header. I have my code as follows:
IFileInfo file = _fileProvider.GetFileInfo(filename);
Response.Headers.Add("Content-Disposition", $"inline; {file.Name}");
return File(file.CreateReadStream(), "application/pdf", file.Name);
While this seems to be the correct code based on other threads I've seen, the Content-Disposition header does absolutely nothing in my code. Whether I have the header, remove it, or make it something else (i.e. attachment), it downloads and saves the file but does not display it unless I manually open the file.
Does anyone know what I'm missing here?
Returning the File overload that accepts the filename param is overwriting your Content-Disposition header to be attachment; {filename}. Just do:
return File(file.CreateReadStream(), "application/pdf");
And you'll be fine.

Is the header comparison in vertx web case sensitive

I have a vertx web routers defined as follows:
router.route(POST, "/customers")
.consumes("application/json;charset=utf-8")
.handler { runHandler(it) }
When I hit this route, I am getting a 404 error with header set as:
Content-Type: application/json;charset=UTF-8
It works for header:
Content-Type: application/json;charset=utf-8
This beg the question whether the header value comparison is case sensitive. Is this the standard or an implementation issue with vertx web?
1) Field values in general are case-sensitive. However, the charset parameter value is not, so it shouldn't matter (see https://greenbytes.de/tech/webdav/rfc7231.html#rfc.section.3.1.1.2)
2) That said: there is no "charset" parameter on application/json anyway, so just get rid of it (see https://greenbytes.de/tech/webdav/rfc8259.html#rfc.section.11)

File is cached by browser even if the response has no-cache header

var epoch = time.Unix(0, 0).Format(time.RFC1123)
var headers = map[string]string{
"Expires": epoch,
"Cache-Control": "no-cache, private, max-age=0",
"Pragma": "no-cache",
"X-Accel-Expires": "0",
}
log.Errorln("no cache header")
for k, v := range headers {
rw.Header().Set(k, v)
}
http.ServeFile(rw, req, path)
I have the above code block in my server side to serve file requests. But the files served are still cached in browser.
But instead of http.ServeFile() I used http.ServeContent() with the last modified timestamp as time.Now(). This works if the request has considerable time difference. Does browser give priority to last modified time than no-cache header? Then what is the purpose of no-cache header? Am I doing anything wrong?
Some browsers cache files without paying attention to headers. Typical solution is to add some get parameter to static file path, so the browser considered it like different request. It can be hash-sum or last modified timestamp. It might look somethind like this: site.com/icon.png?q=123456.

text/html vs application/x-www-form-urlencoded and FormUrlEncodedMediaTypeFormatter

For a POST request, I got back a response in text/html format and the response body was containing the below info:
oauth_token=XXXXXXXXXXXXXXXXXXXXXXXXX&oauth_token_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&oauth_callback_confirmed=true
I made this request through System.Net.Http.HttpClient and I throught I could read the response with FormUrlEncodedMediaTypeFormatter as FormDataCollection but it turned out that FormUrlEncodedMediaTypeFormatter only supports application/x-www-form-urlencoded format by default. So, I worked around this with the following code:
using (OAuthHttpClient client = new OAuthHttpClient(creds)) {
var response = await client.PostAsync(requestUri, new EmptyContent());
var formatter = new FormUrlEncodedMediaTypeFormatter();
formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
var result = await response.Content.ReadAsAsync<FormDataCollection>(new List<MediaTypeFormatter>() { formatter });
}
The question here is:
Is the response provider (in this case it is Twitter) doing it wrong by sending this response as text/html or should FormUrlEncodedMediaTypeFormatter support text/html type by default?
Your question is missing some key info i.e. what is the requestUri supposed to return by default, is it a Web API service or an external one etc. It seems it's not Web API because it's little odd that it returns "text/html".
But the fact that FormUrlEncodedMediaTypeFormatter doesn't support formatting back from text/html is absolutely fine. Because why would it? "application/x-www-form-urlencoded" is effectively a key-value dictionary and text/html is a rich media type.
In Web API, with the way content negotiation works, it looks at
Mediatype mappings (I assume not in place in your case)
Accept headers - looking at your request you don't set them
Request content type - again, looking at your request you don't set it so it's empty
Can the formatter serialize a given type
So if you make the request as you showed to any Web API action, it would return text/xml (if you didn't tweak conneg manually).
I agree with Filip that this is a fine work around to an incorrect content type header.
Henrik

Browser support of multipart responses

I would like to create a HTTP response, using multipart/mixed, but I'm not sure which browsers support it; and if it's as convenient as it sounds, from the client's point of view.
To be honest, I do not need specifically that content type. I just want to transmit more than one file in the same response; maybe there's another content-type more used.
I've tested it, with a home-made server and a simple response. Not sure if the response is well-formed because no browser understands it 100% OK. But here are the results:
Firefox 67.0.1 (64-bit): Renders only the last part, others are ignored.
IE 11.503: Saves all the content in a single file (including the boundaries), nothing is rendered.
Chrome May 2019: Saves all the content in a single file, nothing is rendered.
Safari 4: Saves all the content in a single file, nothing is rendered.
Opera 10.10: Something weird. Starts rendering the first part as plain/text, and then clears everything. The loading progress bar hangs on 31%.
Here's the complete response, if anyone finds any error, please tell me and I'll try again:
HTTP/1.1 200 OK
Date: Tue, 01 Dec 2009 23:27:30 GMT
Vary: Accept-Encoding,User-Agent
Content-Length: 681
Content-Type: Multipart/mixed; boundary="sample_boundary";
Multipart not supported :(
--sample_boundary
Content-Type: text/css; charset=utf-8
Content-Location: http://localhost:2080/file.css
body
{
background-color: yellow;
}
--sample_boundary
Content-Type: application/x-javascript; charset=utf-8
Content-Location: http://localhost:2080/file.js
alert("Hello from a javascript!!!");
--sample_boundary
Content-Type: text/html; charset=utf-8
Content-Base: http://localhost:2080/
<html>
<head>
<link rel="stylesheet" href="http://localhost:2080/file.css">
</head>
<body>
Hello from a html
<script type="text/javascript" src="http://localhost:2080/file.js"></script>
</body>
</html>
--sample_boundary--
In my experience, multipart responses work in Firefox but not in Internet Explorer. This was 2 years ago, using the browsers of the time.
I have had HTTP multipart responses working for a stream of JPEG images. For example, Axis IP cameras use for their motion JPEG stream for Firefox. For Internet explorer, Axis require the use of a plugin.
If Firefox-only support meets your requirements, then I recommend setting the content-length header in each part of the multi-part response. It might help to make the boundary string identical in the original HTTP header and the multi-part response (the '--' is missing in the HTTP header).
Two ideas:
Formatting: I think "multipart" should be in lower case, and I don't think a semicolon is expected at the end of the Content-type header (although it's doubtful that it will make a difference, it's possible that it might).
Have you tried replace mode? Just use: Content-type: multipart/x-mixed-replace -- everything else should stay the same.
 Multi part it yourself
(A good option)
A multipart response can be made manually!
So one can write a no multipart response! Let's say in chunked mode! There it make sense!
So you are streaming the data!
Send all as blunt text!
Make your own separators! Between each part!
In the browser! Extract and parse the data! Split to get each part separately!
And parse each appart! Depending on what type of data it hold!
So if a part is json! You parse it as so!
Quick illustration! Let say we want to send a csv file! Or some other type of file! Along that we want to send too a json object!
And that by streaming it by chunk
Here a code that illustrate that in express:
const data = {
initCapital: fileState.mappingObj.initialCapital
};
res.write(JSON.stringify(data, undefined, 0));
res.write('>>>>'); // parts separator
fileState.readStream.pipe(res); // continue streaming the file (chunk by chunk)
And in the client
export function parseBackTestFetchedData(data: string) {
const [_data, csvData] = data.split('>>>>');
return {
data: JSON.parse(_data),
backTestStatesData: parseCsv(csvData)
};
}
That way! it doesn't matter who the client is!

Resources