ASP.NET: Overriding Content-Type Header - asp.net

I am running a set of ASP.NET pages on IIS 7.5, Windows 2008 R2. I do not have access to the ASP.NET source code.
Each of these pages is emitted with the default Content-Type header:
Content-Type: text/html; charset=utf-8
However, these pages are producing KML and as such should instead be emitting this Content-Type header:
Content-Type: application/vnd.google-earth.kml; charset=utf-8
I tried to override the default Content-Type header in IIS Manager as follows:
Default Web Site => Application Folder => IIS Group => HTTP Reponse Headers => Add:
Add Custom HTTP Response Header
Name: [Content-Type]
Value: [application/vnd.google-earth.kml; charset=utf-8]
After doing so, the Content-Type header was changed but not in a desirable way:
text/html; charset=utf-8,application/vnd.google-earth.kml; charset=utf-8
As you can see, instead of replacing the default Content-Type header, the value I provided was appended to the existing Content-Type header.
Question: Is there some way to override the Content-Type header in IIS Manager? Or, is the only solution to acquire the ASP.NET source and explicitly set the Content-Type header there?

Related

IIS/ASP.NET responds with cache-control: private for all requests

Why does all responses from ASP.NET contain Cache-Control: private? Even a 404 response? Is there something in IIS that sets this default value, and is there a way to configure it? Or is there something in ASP.NET that sets this?
For dynamic content (that is, all MVC results) I would not like it to be cached by the browser, since it is dynamic and can change at any time. Static content is hosted on a CDN, so is not served by IIS.
Edit:
To clarify, I understand very well what Cache-Control: private is, the difference between private, public, no-store, etc and how/when to use them. The question I have is why Cache-Control: private is added by default by IIS/ASP.NET and how to prevent it from being added by default. I understand that it can be useful to cache dynamic pages, but in my application I don't want to cache dynamic pages/responses. For example, I don't want XHR JSON responses to be cached, since they contain dynamic content. Unfortunately the server adds Cache-Control: private to all responses automatically, so I have to manually override it everywhere.
How to reproduce: Open visual studio and create a new ASP.NET Framework (yes, framework, no not Core. We are not able to migrate our system to core yet) solution with an MVC project. Now start the project in IIS Express (just press the play button), and use F12 devtools in the browser to look at the http response. You will see that it contains Cache-Control: private. My question is, what adds this header, and how can I prevent it from being added by default?
Adding my bit to the great answers, given by community;
1. http caching header attrubute Cache-Control: private is added by default by IIS/ASP.NET ?
Cache request directives
Standard Cache-Control directives that can be used by the client in an HTTP request.
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
Cache response directives
Standard Cache-Control directives that can be used by the server in an HTTP response.
Cache-Control: must-revalidate
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-Control: s-maxage=<seconds>
IIS uses the secure and more obvious/useful one for default, which happens to be private
2. how to prevent it from being added by default?
IIS/asp.net allows this to be configured from the day it was introduced like this, ref1, ref2, ref3, ref4 and
System.Web Namespace
The System.Web namespace supplies classes and interfaces that enable browser-server communication. This namespace includes the System.Web.HttpRequest class, which provides extensive information about the current HTTP request; the System.Web.HttpResponse class, which manages HTTP output to the client; and the System.Web.HttpServerUtility class, which provides access to server-side utilities and processes. System.Web also includes classes for cookie manipulation, file transfer, exception information, and output cache control.
protected void Application_BeginRequest()
{
Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
TL; DR
Caching is not used by default for dynamic ASP.NET pages. You need to make an efforts to enable caching in ASP.NET.
Presence of 'Cache-Control: private' header does not mean at all that cached version of the page will be used on repeated requests.
--
There is a very simple test to validate above statements. Create an action that returns current time:
public ActionResult Index()
{
ViewBag.CurrTime = DateTime.Now.ToString("T");
return View();
}
View:
#{
ViewBag.Title = "Home Page";
}
<h1>#ViewBag.CurrTime</h1>
If you refresh such page in abrowser, you'll see fresh time on every request:
There is a possibility to use caching with ASP.NET MVC but you should make some efforts to enable it. See this article for details.
If in spite of this you still for some reason want to exclude any possibility of the caching, you could do it by setting specific HTTP headers. There is a great SO answer that lists which headers should be set:
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
You could use action filter to set those headers in every ASP.NET response:
public class CachingHeadersFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
var response = filterContext.HttpContext.Response;
response.Cache.SetCacheability(HttpCacheability.NoCache);
response.Cache.AppendCacheExtension("no-store, must-revalidate");
response.AppendHeader("Pragma", "no-cache");
response.AppendHeader("Expires", "0");
base.OnResultExecuted(filterContext);
}
}
In FilterConfig.cs (crated automatically in ASP.NET MVC template):
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new CachingHeadersFilterAttribute());
}
}
Here are result headers from the response:
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcRHJvcGJveFxwcm9nXFN0YWNrT3ZlcmZsb3dcUTQ3MjI0NTYxQ2FjaGVcUTQ3MjI0NTYxQ2FjaGU=?=
X-Powered-By: ASP.NET
Date: Mon, 13 Nov 2017 17:44:33 GMT
Content-Length: 837
As you see there is no 'Cache-Control: private' header.
But again, I don't see a reason why you should add such filter to your application.
what adds this header?
The IIS 7 and later (included in the default installation) sends it to Web clients as one of the cache-related HTTP headers.
and how can I prevent it from being added by default?
I describe two ways of disabling cache mechanism (server-side approach and client-side approach) with a focus on server-side based on your question:
Server-Side Approach
Follow this steps Inside the Internet Information Services (IIS) Manager to change Cache-Control value (while I think this works for static contents):
In the Connections pane, go to the site, application, or
directory for which you want to disable caching.
In the Home pane, double-click HTTP Response Headers.
Click Set Common Headers ... in the Actions pane.
Check the box to expire Web content, select the option to expire after a specific interval or at a specific time,
and then click OK.
One way is to annotate your controller as follows which is quite powerful and the response headers contain a Cache-Control: public, max-age=0 header.:
[OutputCache(Duration = 0)]
public class SomeController : Controller {
}
You can also Define a cache profile in your application's Web.config file and in the profile, include duration and varyByParam settings:
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="nocache" duration="0"
varyByParam="none" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
Then use it by the [OutputCache CacheProfile="nocache"] before the action/controller.
Note that there is a configuration in web.config file (following) which won’t prevent caching. Instead it just indicates that no kind of caching mechanism should be applied. By just disabling the output cache we get the default cache headers used by ASP.net MVC which falls back to Cache-Control: private, thus again opening the browser the possibility to cache requests.
<caching>
<outputCache enableOutputCache="false" />
</caching>
Client-Side Approach
Using cache: false inside your js request like:
$.ajax({
type: 'GET',
cache: false,
url: '/nation',
...
});
For additional information, visit:
Client Cache <clientCache>
How to: Set the Cacheability of an ASP.NET Page Declaratively
output-caching-in-aspnet-mvc
An answer from RickNZ, copied from https://forums.asp.net
Cache-Control private says that it's OK for the client to cache the page, subject to its expiration date. The expiration can either be provided with Cache-Control: max-age, or with an Expires HTTP header. In the default case, the page is set to expire immediately, which means that it won't be cached.
One of the purposes of Cache-Control: private is really to tell intermediate proxies that they should not cache the page.
BTW, just because a page is dynamic doesn't mean that it should never be cached. There are many cases where caching a dynamic page is appropriate. You can cache not only at the client, but also in proxies and in the server's output cache.
More info:
IIS 7.0 - IIS adding "private" to cache-control, where is that coming from
Private vs Public in Cache-Control
https://msdn.microsoft.com/en-us/library/ms524721(v=vs.90).aspx
https://msdn.microsoft.com/en-us/library/system.web.httpcacheability(VS.71).aspx
https://forums.asp.net/t/1443346.aspx?Cache+control+private+
https://forums.asp.net/t/2052325.aspx?Remove+the+private+value+from+the+Cache+Control+in+the+Response+Header
The Cache-Control: private header is added to the response by the framework by default.
https://learn.microsoft.com/en-us/dotnet/api/system.web.configuration.httpruntimesection.sendcachecontrolheader?view=netframework-4.8
Definition
Gets or sets a value indicating whether the cache-control:private header is sent by the output cache module by default.
...
Remarks
The HttpResponse class checks both the HttpRuntimeSection.SendCacheControlHeader property and the OutputCacheSection.SendCacheControlHeader property to determine whether to send the cache-control:private header in the HTTP response. If either property is set to false, the header will not be sent. When the cache-control header is set to private, then the client will not cache the response in a shared cache.
Support for the SendCacheControlHeader property in the HttpRuntimeSection class is provided for compatibility with legacy applications; this property is obsolete in the .NET Framework version 2.0. For more information, see the OutputCacheSection class.
To prevent the Cache-Control: private header from being added, simply disable the OutputCacheSection.SendCacheControlHeader property, which defaults to true.
https://learn.microsoft.com/en-us/dotnet/api/system.web.configuration.outputcachesection.sendcachecontrolheader?view=netframework-4.8#system-web-configuration-outputcachesection-sendcachecontrolheader
Property Value
true if the sending of cache-control:private header is enabled; otherwise, false. The default is true.
Example web.config
<configuration>
<system.web>
<caching>
<outputCache sendCacheControlHeader="false" />
</caching>
</system.web>
</configuration>
The default is specified in System.Web.HttpResponse.CacheControl:
/// <devdoc>
/// <para>
/// Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
/// property instead.
/// </para>
/// </devdoc>
public string CacheControl {
get {
if (_cacheControl == null) {
// the default
return "private";
}
return _cacheControl;
}
While you can override the header through (global) filters, this doesn't work for error pages caused by authentication/authorization. Luckily there's a nice entry point for each request, allowing you to override this default:
// In Global.asax.cs:
protected void Application_BeginRequest()
{
Context.Response.CacheControl = "no-cache";
}
Furthermore when there's an error and the YSOD (yellow error page) is rendered through ReportRuntimeError, the framework will call ClearHeaders and your custom cache-control setting will be overridden. I haven't found a solution for this.
Addressing the question:
You will see that it contains Cache-Control: private. My question is,
what adds this header, and how can I prevent it from being added by
default?
The Short answer is: as others have noted, this is a default setting by IIS(7+).
To answer more fully: If you are looking to control or modify the default setting Cache-Control: private for caching HTTP requests, server side.
This will depend on your the which specific version of IIS you are running, and how specific you want to be with your modification. Generally speaking however you can do this using your HTTP Response Headers interface (in IIS Manager => Features view - IIS)
If you want to simply disable caching for a Web site or Application:
go to IIS Manager
Select Site/Application desired
in Features View select HTTP Response Headers:
In actions pane click: Set Common Headers
check Expire Web Content
Set to: Immediately
OK
alternatively, from your command line:
appcmd.exe set config "Default Web Site" -section:system.webServer/staticContent /clientCache.cacheControlMode:"DisableCache"
For Detailed Information and specifics please check:
https://learn.microsoft.com/en-us/iis/configuration/system.webserver/staticcontent/clientcache
Hope this is what your were looking for, cheers.

What does `utf-8` charset change in a `multipart/form-data` HTTP request?

In an attempt to upload a binary file to a web server, I observed that by setting the Content-Type header to a value with charset="utf-8" present, the POST request data integrity fails.
Chrome seems to omit all charset attributes in both the header and the body while performing a file upload POST request all together.
However, some web servers satisfy the request correctly if the charset="utf-8" attribute is included.
Working Example:
POST /upload.php HTTP/1.1
Content-Type: multipart/form-data; boundary=----FormBoundary
------FormBoundary
Content-Disposition: form-data; name="fileupload"; filename="data.bin"
Content-Type: application/octet-stream
------FormBoundary--
HTTP/1.1 200 OK
The file was received successfully.
Failing Example:
POST /upload.php HTTP/1.1
Content-type: multipart/form-data; charset="utf-8"; boundary=----FormBoundary
------FormBoundary
Content-Disposition: form-data; name="fileupload"; filename="data.bin"
Content-Type: application/octet-stream
------FormBoundary--
HTTP/1.1 200 OK
The uploaded file seems to be broken.
The addition of the charset="utf-8" seems to make some web servers fail to decode uploaded data correctly, while it doesn't seem to affect the process in other web servers.
Please note that in both cases, including the charset after the application/octet-stream type does not affect anything, I'm rather focusing on the addition after the multipart/form-data type.
What happens in the server and/or the os when the unicode charset flag is present after the multipart type?

How do I prevent ASP.Net from sending a default charset?

I'm working on building some web pages for testing various vulnerability scenarios, but ASP.Net, or IIS, is doing too good a job of protecting me from myself.
One of the things I'm trying to do is return responses with various Content-Type headers, with and without charset declarations. The problem I that if I leave out the charset, then ASP.Net seems to add in utf-8 by default.
In my ASPX.cs code-behind, if I have Response.AddHeader("Content-Type", "text/html") or Page.ContentType = "test/html", I would expect to see the following header returned by the page:
Content-Type: text/html
Instead I get:
Content-Type: text/html; charset=utf-8
If I use Response.AddHeader("Content-Type", "text/html; charset=iso-8859-1") then I get the expected header:
Content-Type: text/html; charset=iso-8859-1
Is there a way to stop ASP.Net (IIS?) from appending charset=utf-8 to the header when I don't want it?
I'm using ASP.Net 4.0 and IIS 7.5.
Try this:
Response.Charset = "";

How to get file type of HTTP response?

Is there a way to get the file type(extension) of http response? It is not doable to parse http request because some times there will not be file name in the url, for example, "GET www.stackoverflow.com"
HTTP isn't concerned about file types or file extensions, but uses MIME types to distinguish between different content types. As mentioned by shyam, it is represented by the Content-Type header, which for normal web pages may look like this:
Content-Type: text/html; charset=utf-8
An exception is when the HTTP response is serving a file which is supposed to be stored on the client side, in which case a Content-Disposition header may be included to indicate a filename and thus a file extension:
Content-Disposition: attachment; filename="fname.ext"
You can try to guess from the Content-Type header

OutputCache directive not working in Asp.Net

I added an outputcache directive to my asp.net page (asp.net 4.0) as such:
<%# OutputCache Duration="3600" Location="Client" VaryByParam="None" %>
However, this does not appear to be working. When I check the http header information I see this:
HTTP/1.1 200 OK =>
Cache-Control => no-cache, no-store
Pragma => no-cache
Content-Type => text/html; charset=utf-8
Expires => -1
Server => Microsoft-IIS/7.0
X-AspNet-Version => 4.0.30319
Set-Cookie => ASP.NET_SessionId=0txhgxrykz5atrc3a42lurn1; path=/; HttpOnly
X-Powered-By => ASP.NET
Date => Tue, 15 Nov 2011 20:47:28 GMT
Connection => close
Content-Length => 17428
The above shows that the OutputCache directive was not applied. I even tried this from codebehind:
this.Response.Cache.SetExpires(DateTime.Now.AddHours(1.0));
TimeSpan ds = new TimeSpan(0, 1, 0, 0);
this.Response.Cache.SetMaxAge(ds);
The above code should have the same results as the OutputCache directive, but when I check the http header information, I can see it's still not being applied.
Basically, the purpose here is to make sure that when a user clicks the back button and lands on my page, the page will not be retrieved from the server. I want to avoid getting the browser popup that asks the user to 'resend.' I want the browser to just use the copy of the page it has in it's cache.
Thanks in advace for any help.
From your question:
I want to avoid getting the browser popup that asks the user to
'resend.' I want the browser to just use the copy of the page it has
in it's cache.
If browser asks you to resend data, it means that content was response to POST request.
According to RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1:
Some HTTP methods MUST cause a cache to invalidate an entity. This is
either the entity referred to by the Request-URI, or by the Location
or Content-Location headers (if present). These methods are:
PUT
DELETE
POST
So, to make cache work, you need to convert your POST to GET.

Resources