How do I configure ASP.Net OutputCache to vary by http vs https?
Asked Answered
G

3

14

Here is the scenario, a user opens up non-secure page from our WebApp, let's call it PageA, in their browser and then clicks a link in there that takes them to a secure instance of PageB. Once in PageB the user can subsequently click a link that takes them back to a secure instance of PageA (which they already viewed and is in OutputCache). I observed that even though PageA is being accessed over a different URL after visiting PageB (the secure one) it's actually pulling the prior cached copy rather making a fresh one. I verified this behavior in a debugging session, and was surprised that ASP.Net used the same OutputCache item for a secure copy of the page.

My question is why is it this way? And how do I tell the ASP.Net OutPutCache to treat access from secure URL as a different/unique item than the non-secure equivalent?

[Background]

We recently switched our Web Sites images over to use Scene7/Akamai for all images. As a result of this we added code to use different Scene7 url's when viewing a given page on a secure connection. This OutputCache issue is not allowing for the logic that outputs the secure url's to execute, and is resulting in ugly browser warnings.

Gasaway answered 14/7, 2009 at 0:17 Comment(0)
S
8

I think that you can do a VaryByCustom="scheme" and add this to your Global.asax.cs file (inlcuding a couple other others that I use as well app version & user):

    public override string GetVaryByCustomString(HttpContext context, string custom)
    {
        if (custom.Equals("version", StringComparison.CurrentCultureIgnoreCase))
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            string[] parts = asm.FullName.Split(',');
            string version = parts[1].Trim().ToLower();
            return version;
        }
        else if (custom.Equals("user", StringComparison.CurrentCultureIgnoreCase))
        {
            var user = Membership.Users.CurrentUser;
            return null == user ? string.Empty : user.Id.ToString();
        }
        else if (custom.Equals("scheme", StringComparison.CurrentCultureIgnoreCase))
        {
            var scheme = context.Request.IsSecureConnection ? "https" : "http";
            return scheme;
        }
        else
            return base.GetVaryByCustomString(context, custom);
    }
Subjugate answered 19/12, 2009 at 17:15 Comment(1)
+1. Exactly what I needed. In my case the user shouldn't be going to HTTPS for my particular page. But in case they do, I have redirection code in place to send them to HTTP. However, this redirection code wouldn't work until I varied by "scheme" as in your example.Cheju
C
13

This doesn't answer the question as worded but it may eliminate your need to vary by scheme. If you are hard coding the "http://" for the Scene7 urls you can change them to scheme-relative urls.

<img src="http://site.scene7.com/images/someimage.jpg" />
=>
<img src="//site.scene7.com/images/someimage.jpg" />

That will cause the browser to automatically ask for the resource with the same scheme as the referring page. That's assuming you have an SSL certificate for your scene7 domain of course.

Cutup answered 29/9, 2009 at 14:0 Comment(2)
+1 - would do more if I could...this should be marked as the answer.Subjugate
However, avoid protocol relatives for CSS in IE: stevesouders.com/blog/2010/02/10/…Kessel
S
8

I think that you can do a VaryByCustom="scheme" and add this to your Global.asax.cs file (inlcuding a couple other others that I use as well app version & user):

    public override string GetVaryByCustomString(HttpContext context, string custom)
    {
        if (custom.Equals("version", StringComparison.CurrentCultureIgnoreCase))
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            string[] parts = asm.FullName.Split(',');
            string version = parts[1].Trim().ToLower();
            return version;
        }
        else if (custom.Equals("user", StringComparison.CurrentCultureIgnoreCase))
        {
            var user = Membership.Users.CurrentUser;
            return null == user ? string.Empty : user.Id.ToString();
        }
        else if (custom.Equals("scheme", StringComparison.CurrentCultureIgnoreCase))
        {
            var scheme = context.Request.IsSecureConnection ? "https" : "http";
            return scheme;
        }
        else
            return base.GetVaryByCustomString(context, custom);
    }
Subjugate answered 19/12, 2009 at 17:15 Comment(1)
+1. Exactly what I needed. In my case the user shouldn't be going to HTTPS for my particular page. But in case they do, I have redirection code in place to send them to HTTP. However, this redirection code wouldn't work until I varied by "scheme" as in your example.Cheju
D
1

I've never tried it but you might be able to use the Outputcache VaryByHeader property and the "host" header, which specifies the Internet host and port number of the resource being requested.

The question I'd have is why are you redirecting to PageA over secure after from PageB. If its a non-secure page, couldn't you fix the PageB redirect to always redirect to non-secure.

Dykstra answered 14/7, 2009 at 3:5 Comment(1)
+1 Thanks for the response. My example is much simpler than my reality. In fact, I have many pageB's and many pageA's. To change all links back to pageA's as non-secure from pageB's would be too much work, I'm hoping there is an simpler way.Gasaway

© 2022 - 2024 — McMap. All rights reserved.