title: OutputCache is sending wrong Vary header when the call hits the cache
body: <p>I have an action method that I want to cache:</p>
  
  <pre><code>[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="index")]
  public ActionResult Index()
  {
      return View();
  }
  </code></pre>
  
  <p>With this approach:</p>
  
  <pre><code>public override string GetVaryByCustomString(HttpContext context, string custom)
  {
      context.Response.Cache.SetOmitVaryStar(true);
      context.Response.Cache.VaryByHeaders["Cookie"] = true;
  
      if (User.Identity.IsAuthenticated)
      {
          Debug.Print("Authenticated");
          context.Response.Cache.SetNoServerCaching();
          context.Response.Cache.SetCacheability(HttpCacheability.Private);
          return null;
      }
      else
      {
          Debug.Print("Non authenticated");
          return custom;
      }
  }
  </code></pre>
  
  <p>The idea was to <a href="https://stackoverflow.com/questions/9180954/cache-home-page-for-non-authenticated-users-in-asp-net-mvc-3">keep a cached version of the page for non-authenticated users, but avoid caching for authenticated ones</a>.</p>
  
  <p>I thought it will always return a <code>Vary:Cookie</code> HTTP header, but it is not. 
  Doing a test with Fiddler and issuing twice the same request, in the first HTTP call it goes good:</p>
  
  <pre><code>HTTP/1.1 200 OK
  Cache-Control: public, max-age=300
  Content-Type: text/html; charset=utf-8
  Expires: Thu, 09 Feb 2012 10:53:36 GMT
  Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
  Vary: Cookie
  Server: Microsoft-IIS/7.5
  X-AspNetMvc-Version: 3.0
  X-AspNet-Version: 4.0.30319
  X-Powered-By: ASP.NET
  Date: Thu, 09 Feb 2012 10:48:37 GMT
  Content-Length: 441
  </code></pre>
  
  <p>But in the second one, it overwrites the header:</p>
  
  <pre><code>HTTP/1.1 200 OK
  Cache-Control: public, max-age=297
  Content-Type: text/html; charset=utf-8
  Expires: Thu, 09 Feb 2012 10:53:36 GMT
  Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
  Vary: *
  Server: Microsoft-IIS/7.5
  X-AspNetMvc-Version: 3.0
  X-AspNet-Version: 4.0.30319
  X-Powered-By: ASP.NET
  Date: Thu, 09 Feb 2012 10:48:39 GMT
  Content-Length: 441
  </code></pre>
  
  <p>So, as far as I know, browsers won't cache the request even if it is public, since <code>Vary:*</code> means that the request has been generated with parameters that are not in the URL nor in the HTTP headers. Is there a way to fix this?</p>
  
  <p>Regards.</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>In a similar way, when I send two identical authenticated requests, the first call gets the <code>private</code> modifier, but not the <code>Vary</code> header:</p>
  
  <pre><code>HTTP/1.1 200 OK
  Cache-Control: private, max-age=300
  Content-Type: text/html; charset=utf-8
  Expires: Thu, 09 Feb 2012 12:43:14 GMT
  Last-Modified: Thu, 09 Feb 2012 12:38:14 GMT
  Server: Microsoft-IIS/7.5
  X-AspNetMvc-Version: 3.0
  X-AspNet-Version: 4.0.30319
  X-Powered-By: ASP.NET
  Date: Thu, 09 Feb 2012 12:38:14 GMT
  Content-Length: 443
  </code></pre>
  
  <p>But the second one gets the same response that a non-authenticated request:</p>
  
  <pre><code>HTTP/1.1 200 OK
  Cache-Control: public, max-age=298
  Content-Type: text/html; charset=utf-8
  Expires: Thu, 09 Feb 2012 12:44:32 GMT
  Last-Modified: Thu, 09 Feb 2012 12:39:32 GMT
  Vary: *
  Server: Microsoft-IIS/7.5
  X-AspNetMvc-Version: 3.0
  X-AspNet-Version: 4.0.30319
  X-Powered-By: ASP.NET
  Date: Thu, 09 Feb 2012 12:39:33 GMT
  Content-Length: 443
  </code></pre>
  
  <p>I have uploaded a <a href="http://vtortola.net/files/PageCachingForAnonymousMVC.zip" rel="nofollow noreferrer">test project showing the issue</a> so may be you want to give it a try.</p>
  
  <p>Please be aware that there is an <code>IHttpModule</code> that sets a request as authenticated or not depending on if the request has a cookie or not, this is not a "real life" approach, it is just for testing purposes.</p>
  
  <p>The project contains only a web page with a link to itself, a link that logs you in, and another link that logs you out:</p>
  
  <ul>
  <li>LogIn : Sends a cookie in a <code>HTTP 302</code> redirection to the home page again.</li>
  <li>LogOut: Sends a expired cookie in a <code>HTTP 302</code> recirection to the home page again.</li>
  </ul>
  
  <p>The <strong>expected/ideal</strong> behaviour would be:</p>
  
  <ol>
  <li>User access Index, and get the page from the server. The page show date "A".</li>
  <li>User access Index again, and the browser shows the cached version.The page show date "A".</li>
  <li>Clean browser cache.</li>
  <li>User access Index again, and the browser shows the server cached version. The page show date "A".</li>
  <li>User clicks login, and the broswer gets a new page, that show date "B".</li>
  <li>User clicks logout, and the browser gets the server cached page. The page show date "A" again.</li>
  </ol>
  
  <p>But this is the behaviour so far:</p>
  
  <ol>
  <li>User access Index, and get the page from the server. The page show date "A".</li>
  <li>User access Index again, and the browser shows the cached version.The page show date "A".</li>
  <li>Clean browser cache.</li>
  <li>User access Index again, and the browser shows the server cached version. The page show date "A".</li>
  <li>User clicks login, and the broswer gets a new page, that show date "B".</li>
  <li>User clicks logout, and the browser <strong>should get the server cached page, but it does not</strong>. The page show date "B" again from the browser cache. This is because the lack of the <code>Vary</code> header in the authenticated response.</li>
  </ol>
  
  <p>I don't know if I get something wrong about caching, just missing some detail or the <code>OutputCache</code> does not work very well, but I would appreciate any guidance.</p>
  
  <p>Cheers.</p>
  
  <p><strong>UPDATE 2:</strong></p>
  
  <p>My intention is to use the HTTP cache semantics to:</p>
  
  <ol>
  <li>Allow browsers and proxys to cache the "public" version of the page.</li>
  <li>Allow browsers to cache the "authenticated" version of the page for its user.</li>
  </ol>
  
  <p>If I change the OutputCache declaration to do the caching only on the server and prevent the downstream and client caching:</p>
  
  <pre><code>[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")]
  </code></pre>
  
  <p>it behaves as expected, but the downstream and client cache is prevented, and that is not what I want.</p>