I'm trying to add a Vary: Accept-Encoding
header to the response to files that I compress, as advised earlier.
However, for some reason this is not possible - either from the Visual Studio test server, or an IIS server.
I have the following code:
if (url.Contains(".js") || url.Contains(".aspx") || url.Contains(".css"))
{
app.Response.AppendHeader("Vary", "Accept-Encoding");
app.Response.AppendHeader("Varye", "Accept-Encoding"); // for testing
app.Response.AppendHeader("Varye", "Accept-Things"); // for testing
app.Response.AppendHeader("Vary", "Accept-Stuff"); // for testing
app.Response.AppendHeader("Var", "Accept-Items"); // for testing
encodings = encodings.ToLower();
if (encodings.Contains("gzip") || encodings == "*")
{
app.Response.Filter = new GZipStream(baseStream, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "gzip");
}
}
this results in the following response header:
Status=OK - 200
Server=ASP.NET Development Server/10.0.0.0
Date=Fri, 21 Oct 2011 12:24:11 GMT
X-AspNet-Version=4.0.30319
Varye=Accept-Encoding, Accept-Things
Var=Accept-Items
Content-Encoding=gzip
Cache-Control=public
Etag="1CC8F2E9D772300"
Content-Type=text/css
Content-Length=16200
Connection=Close
As you can see, the Vary
header is not present. Meaningless headers with similar syntax are present, so there must be something, somewhere, taking out the Vary header before it is sent.
I don't know if it is relevant, but here is where I define my compression module in web.config:
<httpModules>
<add name="CompressionModule" type="Utility.HttpCompressionModule"/>
</httpModules>
(Where Utility.HttpCompressionModule is the class which the code excerpt I provided above belongs to.)
Why is it that I can't add the Vary
header?
EDIT: Eric C's solution has left me with code like this:
if (url.Contains(".js") || url.Contains(".aspx") || url.Contains(".css"))
{
app.Response.Cache.SetVaryByCustom("Accept-Encoding");
encodings = encodings.ToLower();
if (encodings.Contains("gzip") || encodings == "*")
{
app.Response.Filter = new GZipStream(baseStream, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "gzip");
}
But, the headers look like this:
Status=OK - 200
Server=ASP.NET Development Server/10.0.0.0
Date=Mon, 24 Oct 2011 09:26:37 GMT
Content-Encoding=gzip
Cache-Control=public
Etag="1CC7A09FDE77300"
Vary=*
Content-Type=application/x-javascript
Content-Length=44447
Connection=Close
(No idea why this is application/x-javascript
as its set in the HTML as text/javascript
, but this is irrelevant.)
As you can see, I now have a vary header, but it is set as Vary=*
rather than Vary=Accept-Encoding
, as you would expect from my code in the compression module.
What is going on here? How do I get the Vary
header set correctly?
Second Edit: I'm going to paste the source code for the whole class. There isn't much more to it than I have already posted, but it might help to give a grasp of exactly what I'm doing:
public class HttpCompressionModule : IHttpModule
{
/// <summary>
/// Initializes a new instance of the <see cref="AjaxHttpCompressionModule"/> class.
/// </summary>
public HttpCompressionModule()
{
}
#region IHttpModule Members
/// <summary>
/// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
/// </summary>
void IHttpModule.Dispose()
{
}
/// <summary>
/// Initializes a module and prepares it to handle requests.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += (new EventHandler(this.context_BeginRequest));
}
#endregion
/// <summary>
/// Handles the BeginRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
string encodings = app.Request.Headers.Get("Accept-Encoding");
Stream baseStream = app.Response.Filter;
if (string.IsNullOrEmpty(encodings))
return;
string url = app.Request.RawUrl.ToLower();
if (url.Contains(".js") || url.Contains(".css") || url.Contains("ajax.ashx"))
{
app.Response.Cache.SetVaryByCustom("Accept-Encoding");
encodings = encodings.ToLower();
if (encodings.Contains("gzip") || encodings == "*")
{
app.Response.Filter = new GZipStream(baseStream, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "gzip");
}
else if (encodings.Contains("deflate"))
{
app.Response.Filter = new DeflateStream(baseStream, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "deflate");
}
}
}
}
Further, here is the System.Web section of my web.config file:
<system.web>
<!--<compilation debug="true"></compilation>-->
<trace enabled="true" traceMode="SortByTime"/>
<httpRuntime executionTimeout="180"/>
<globalization culture="en-GB" uiCulture="en-GB"/>
<!-- custom errors-->
<customErrors mode="Off">
</customErrors>
<!-- Membership -->
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<clear/>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SQLServerAuth" applicationName="mycompany" minRequiredPasswordLength="4" minRequiredNonalphanumericCharacters="0" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed" maxInvalidPasswordAttempts="1024"/>
</providers>
</membership>
<!-- Roles -->
<roleManager enabled="true" cacheRolesInCookie="true" defaultProvider="SqlProvider">
<providers>
<clear/>
<add connectionStringName="SQLServerAuth" applicationName="mycompany" name="SqlProvider" type="System.Web.Security.SqlRoleProvider"/>
</providers>
</roleManager>
<!-- Authentication -->
<anonymousIdentification enabled="false"/>
<authentication mode="Forms">
<forms name=".AUTH" protection="All" timeout="2" path="/">
</forms>
</authentication>
<httpModules>
<add name="CompressionModule" type="Utility.HttpCompressionModule"/>
</httpModules>
</system.web>
There isn't much more to say. There is no other non-standard stuff that we are doing with the site, that I know about. Any ideas?