Overriding Cache-Control Header on Azure Websites - azure

I have a Ghost blog hosted on Microsoft Azure. I want to make sure that I can set the Cache-Control header myself, because right now it has a max-age set to 0.
The way I am approaching this problem is through dropping a custom web.config (since Azure Websites uses IIS). Here is what I have:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="false">
</modules>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />
</staticContent>
<httpProtocol>
<customHeaders>
<remove name="Cache-Control" />
<add name="Cache-Control" value="public, max-age=99" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
However, this does not actually remove the original Cache-Control header, but rather appends my value to it:
Any insights on what I am missing?

The solution to this problem is more trivial than I originally thought. While I was properly setting the headers in web.config, the server node.js configuration was enforcing its own Cache-Control rule, that was overriding mine.
In \core\server\middleware there is a file called cache-control.js. Inside it there is a snippet:
cacheControl = function cacheControl(options) {
/*jslint unparam:true*/
var profiles = {
public: 'public, max-age=0',
private: 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
},
output;
All I needed to do is tweak 'public, max-age=0' to the value I wanted.
This eliminated the need for web.config altogether.

Related

Error 405 - Method not allowed with IIS Express 10 with CORS for Web API

I know this question has been asked plenty of times, each with similar answers, but after hours on this problem, I've yet to get it resolved, so I'm hoping additional suggestions may be provided.
I'm getting Error 405 - Method not allowed
I've removed the WebDAV entries from the module and handler section as suggested.
I've also changed the ExtensionlessUrlHandler-Integrated-4.0. Removed it first as suggested but didn't work so re-added it but with a slightly different definition <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*."
verb="GET,POST,OPTIONS,PUT,DELETE"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
where each verb is defined rather than using *
I've ensure CORS was enabled i.e. app.UseCors(CorsOptions.AllowAll); is called from my Startup class in public void Configuration(IAppBuilder app)
Access-Control-Allow-Methods has been set in my web.config
The weird thing is that it works just fine for DELETE but not for PUT.
Here's my System.WebServer section from my web.config:
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/>
</modules>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods"
value="GET,POST,OPTIONS,PUT,DELETE" />
</customHeaders>
</httpProtocol>
<handlers>
<clear/>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*."
verb="GET,POST,OPTIONS,PUT,DELETE"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
When I run Fiddler, I'm getting the following:
HTTP/1.1 405 Method Not Allowed
Allow: GET,POST
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/10.0
X-SourceFiles: =?UTF-8?B?RDpcU3BpbmRldlxXb3JrXEpvaWZmTGlzdGluZ05lnM=?=
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,OPTIONS,PUT,DELETE
Date: Mon, 15 Jul 2019 23:41:32 GMT
Content-Length: 79
{
"message": "The requested resource does not support http method 'PUT'."
}
As you can see, the Access-Control-Allow-Origin and Access-Control-Allow-Methods appears to be set correctly but the Allow: is still set to GET,POST. Why is that? Where am I suppose to change this to have all the verbs?
And finally my action in my web controller is defined as follows:
[HttpPut]
[Route("id:{Guid}")]
public async Task<IHttpActionResult> UpdateCompany(Guid id)
{
}
Pretty standard stuff!
Any ideas and/or suggestions? Remember that I'm concentrating on getting this to work on IIS Express. Once I've got that resolved, I'll check it out in IIS but I really want to get to the bottom of this first.
Any help much appreciated.
Thanks.
UPDATE-1
I've just found an article from Microsoft regarding CORS, and even thought I'm enabling it as mentioned above, I've noticed that I don't have any references in my list of references to Microsoft.AspNet.WebApi.Cors which is odd and when I try to add the [EnableCors...] attribute, no references are shown which would indicate even more clearly that it may not be installed properly or at all.
I'll check that tomorrow and update.
I've also forgot to mention that OWIN is installed and set up. In the event this may give more clues as to why I still can't resolve this problem.
UPDATE-2
My add company (POST) is defined as follows:
[HttpPost]
public async Task<IHttpActionResult> AddCompany (
CompanyRequestDto companyRequestDto)
{
}
My update company (PUT) is defined as follows:
[HttpPut]
public async Task<IHttpActionResult> UpdateCompany (
Guid Id,
CompanyRequestDto companyRequestDto)
{
}
and my WebApiConfig.cs has the following route defined in it:
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I've removed [Route("id:{Guid}")] as I thought it could have been that, but it's not. Same issue.
As Andrei Dragotoniu suggested, commenting out my UpdateCompany function generated the very same error which means another function is being hit but I have no idea which one as none of the breakpoints I've put are being hit, nor, any of them are defined as PUT so it's confusion. I'm sure we'll get to the bottom of it.
UPDATE-3
I feel really stupid right now!! After wasting so much time researching this problem, it actually wasn't there! Unlike a POST request where you only post the object, the PUT request expected a CompanyId as part of the query string which I had omitted and cause the problem!
http://localhost:12345/Companies
instead of
http://localhost:12345/Companies/61770BAA-78A6-E911-AEB1-001A7DDA7111
Anyway, I'm glad I'm up and running and I hope nobody else will do something as silly as this but if you do, hopefully, this will help!
Do not do this on IIS Express, that's pointless. Get it working in proper IIS instead.
One thing to check, the error method tells you that the particular method you're accessing does not support PUT. This doesn't mean that the PUT verb is not enabled in config. What it means is that the particular method you're accessing does not support it.
You need to check and see which endpoint is being hit because it doesn't seem to be the one you think. Check your rules basically. Remember they get applied in order so you really want your most concrete ones to be loaded first and the most general one at the end.
One quick way to check this is to comment out the UpdateCompany(Guid id) endpoint and see if you still get the same response when you repeat the call in Postman. If you do, then it's obvious that your request is being handled by a different endpoint, not the one you think.

CORS Error with ttf font file on Azure CDN

I have a CDN I have created using the Verizon Premium SKU. when it comes to fonts I get "from origin 'https://myfqdn.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource"
However, I have followed this doc https://learn.microsoft.com/en-us/azure/cdn/cdn-cors with no luck.
However, if I go to my https://cdn.myfqdn.com (yes I have a custom domain and https enabled) the page loads however with no issues.
Here is the XML from the rule that I created from the doc above.
<rules schema-version="2" rulesetversion="6" rulesetid="945266" xmlns="http://www.whitecdn.com/schemas/rules/2.0/rulesSchema.xsd">
<rule id="1823263" platform="http-large" status="active" version="3" custid="A76A4">
<!--Changed by userId: 952 on 02/25/2019 03:45:01 PM GMT-->
<!--Changed by xxx#cdn.windowsazure.com on 02/25/2019 03:25:23 PM GMT from IP: xxx.xxx.xxx.xxx-->
<description>Wildcard</description>
<!--If-->
<match.request-header.wildcard name="Origin" result="match" value="Https://myFQDN.com" ignore-case="true">
<feature.set-request-header action="set" key="Access-Control-Allow-Origin" value="*" />
<feature.set-request-header action="set" key="Access-Control-Allow-Headers" value="*" />
<feature.set-request-header action="set" key="Access-Control-Allow-Methods" value="GET, HEAD, OPTIONS" />
<feature.set-request-header action="set" key="Access-Control-Expose-Headers" value="*" />
</match.request-header.wildcard>
</rule>
</rules>
Thanks for your help
I was also facing this issue in my blog. All the files were loading from the CDN except fonts and icons. I had to do two things. One is to allow all the origins in the Azure web app and the other is to configure the files in IIS by editing the web.config.
Just login to your Azure portal, and go to your Azure web application. Click on the CORS menu under API and * as the allowed origin.
By default files with .woff2, .woff, and .ttf extensions are not served by IIS in Azure App Service. That is the reason for this CORS issue. We will add these configurations in the system.webServer tag which is the child tag of configuration tag.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension="woff" mimeType="application/font-woff" />
<mimeMap fileExtension="woff2" mimeType="application/font-woff2" />
<mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
<mimeMap fileExtension=".ttc" mimeType="application/octet-stream" />
<mimeMap fileExtension=".otf" mimeType="application/octet-stream" />
</staticContent>
</system.webServer>
</configuration>
You can also do this by adding the extension called “Enable Static Web Fonts”. I have written a detailed blog about this, you can read it here.

What exactly do the module ProtocolSupportModule?

In the doc (https://learn.microsoft.com/en-us/iis/get-started/introduction-to-iis/iis-modules-overview) they say that ProtocolSupportModule Implements the supports which allow or turn off keep-alive support via configuration. I don't understand what it's mean exactly ?
I saw that for example without ProtocolSupportModule the custom headers will not work. So it's not only about TRACE and OPTIONS
I Think now that maybe ProtocolSupportModule is connected to this in the web.config
<httpProtocol allowKeepAlive="true">
<customHeaders>
<clear />
</customHeaders>
<redirectHeaders>
<clear />
</redirectHeaders>
</httpProtocol>
This seam to correspond to what the doc say (keepalive, redirect and custom header)

Azure Websites Dropping Custom Headers

An Azure Website I am working on inspects custom headers of incoming requests to decide what to do with the request internally. The request is being sent/received by the website server with the customer headers:
X-HEADER-1: ...
X-HEADER-2: ...
among other standard and non-standard headers.
I verified this by inspecting the FREB logs and looking at GENERAL_REQUEST_HEADERS, which correctly includes my custom headers.
When the application receives the request, those custom headers are not there. I explicitly check for one of them then throw and dump all available headers in the error message.
I have read around that Application Request Routing module can drop these headers. I tried adding this to the website's web.config but still doesn't work:
<system.webServer>
<rewrite>
<allowedServerVariables>
<add name="HTTP_X_HEADER_1" />
<add name="HTTP_X_HEADER_2" />
</allowedServerVariables>
</rewrite>
</system.webServer>
Any idea how I can whitelist my headers to let ARR/Azure let them through?
Update 1
Here is some more info.
This works locally on my dev box. I set up the site in IIS and point it to the project folder and headers are coming in and processed as expected.
It is an ASP.NET MVC website.
Here is the part of the code that reads the header. Again, this works locally.
public class BaseController : Controller
{
public AppControllerBase(...)
{
}
protected override void Initialize(RequestContext requestContext)
{
var header1Value = requestContext.HttpContext.Request.Headers["X-HEADER-1"];
if (string.IsNullOrEmpty(header1Value))
{
var stringBuilder = new StringBuilder();
// append all headers to stringBuilder
var errorMessage = string.Format("SiteId header is not set. Headers: {0}", stringBuilder);
throw new HttpRequestException(errorMessage);
}
base.Initialize(requestContext);
}
...
}
Update 2
I just deployed the same app as an azure cloud service and it worked well. The headers were received and the app read them successfully. Something with web apps is not letting those headers through.
The answer that worked for me was in the comments. Credit goes to #Tarek Ayna.
The custom headers are transmitted when you set X-LiveUpgrade to 0.
For example:
<httpProtocol>
<customHeaders>
<add name="X-LiveUpgrade" value="0" />**
<!-- Prevent iframes -->
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="X-XSS-Protection" value="1" />
</customHeaders>
</httpProtocol>
One possibility is to disable ARR if your services are stateless... to do that:
(Inside web.config)
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Arr-Disable-Session-Affinity" value="True" />
</customHeaders>
</httpProtocol>
</system.webServer>

Disable IIS Request Filtering for certain paths

Is there any way I can have IIS 7.0+ (or 7.5+) configured such that for certain paths Request Filtering is completely disabled. That is,
http://host.local/foo/bar.cs
is forbidden (since serving *.cs files is explicitly forbidden in applicationHost.config), but
http://host.local/foo/allow-all/bar.cs
is allowed.
In your allow-all directory, you can create a web.config file with the following configuration:
<configuration>
<system.webServer>
<security>
<requestFiltering>
<fileExtensions>
<remove fileExtension=".cs" />
</fileExtensions>
</requestFiltering>
</security>
<staticContent>
<mimeMap fileExtension=".cs" mimeType="text/plain" />
</staticContent>
</system.webServer>
</configuration>
This configuration removes the .cs extension from the request filtering. Additionally, for IIS to properly serve content, it needs a MIME type, so the .cs extension is added as text/plain.
These changes will also apply to all child directories of allow-all. This configuration works with an Integrated App Pool. Classic may require additional changes since there are HTTP handlers that explicitly disallow .cs as well.

Resources