I noticed on fiddler that [RequireHttps] does status code 302 redirects instead of 301. I'm not sure how this makes sense...
If you are saying that a controller [RequireHttps], then you never-ever want people to go visit the Http version of that page. So why isn't a permanent redirect... telling the search engines "please update your links permanantly to the https version of this page".
If this makes sense, and i'm right, is there a way to change it to 301 redirect?
Dulan's solution put me on the right path, but the code sample didn't stop the 302 redirect from the core RequireHttpsAttribute implementation. So, I looked up the code of RequireHttpsAttribute and hacked it. Here's what I came up with:
Dulan's answer is close, but it does not work, at least with our MVC 4+ solution. But after some trial and error, we did get ours working with 301's instead of 302's. Here is the new class:
The reason Dulan's answer didn't work seems to be because the
Permanent
property of the filterContext.Result is readonly and can only be set when theRedirectResult()
is called, and the problem is thatRedirectResult()
is called in thebase.OnAuthorization()
method. So just call the base method, then override thefilterContext.Result
below with the second parameter of true to make the result Permanent. After doing this, we began to see 301 codes in Fiddler2.It seems as if the choice to go with 302 over 301 was a little arbitrary to begin with. However, it does not necessarily follow that every URL is going to "have" to utilize the HTTPS scheme. There very well could be a page that allows access from both HTTP or HTTPS even if it may encourage the latter. An implementation where this may occur could have some code wired up to determine whether or not to use HTTPS based on some special criteria.
As a case scenario, take a look at Gmail. Within the settings, one is capable of allowing or disallowing the HTTPS protocol throughout large portions of the application. Which code should be returned then? 301 wouldn't be accurate, as it isn't "permanent"...only a change at the behest of the user. Sadly, 302 isn't quite accurate either because a 302 error implies that there is intent to change the link back at some point in the future (related reference http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).
Granted, Gmail is a rough example because the portions of the site that allow that option are not typically indexed by a search engine, but the possibility still exists.
And to answer your final question, if you want a different status code in ASP.NET MVC (which I assume you're using from the small syntax example), it is possible to change with a simple, custom attribute:
Now all actions that implement the attribute should return a 301 status code when accessed via the HTTP protocol.
Just a quick note that the RequireHttpsAttribute also throws an InvalidOperationException if the request is anything but a GET request. This is better served by returning a 405 Method Not Allowed, which is a much more appropriate error.
In my implementation below, I also give the user of the attribute the option of whether or not they want to redirect permanently (301) or temporarily (302). As said by @Dulan, You should perform a 301 permanent redirect if the page can only ever be accessed by HTTPS and a 302 temporary redirect if the page can be accessed over HTTP or HTTPS.