Question

I have an ASPX page that issues a Response.Redirect that points to an image file.

The redirect response headers look like this:

HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Location: https://www.site.com/folder/file.jpg
Server: Microsoft-IIS/8.0
Date: Tue, 29 Apr 2014 08:29:58 GMT
Content-Length: 241

Is it possible to force the client and any proxy servers to cache this response for say 30 days? Should I do this with Cache-Control, ETags or both? If so, how?

Was it helpful?

Solution

I have figured this out and tested it. The following code adds the ETags and cache-control:

protected void Page_Load(object sender, EventArgs e)
{
    var absoluteUrl = GetUrlFromDatabase(Request["fileId"]);
    CacheResponse(absoluteUrl);
    Response.Redirect(absoluteUrl);
}

private static void CacheResponse(string absoluteLocation)
{
    // you need to clear the headers that ASP.NET automatically adds
    HttpContext.Current.Response.ClearHeaders();

    // now get the etag (hash the 
    var etag = GetETag(absoluteLocation);

    // see if the etag matches what was sent
    var requestedETag = HttpContext.Current.Request.Headers["If-None-Match"];
    if (requestedETag == etag)
    {
        HttpContext.Current.Response.Status = "304 Not Modified";
        HttpContext.Current.ApplicationInstance.CompleteRequest();

        return;
    }

    // otherwise set cacheability and etag.
    HttpContext.Current.Response.Cache.SetValidUntilExpires(true);
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
    HttpContext.Current.Response.Cache.SetExpires(DateTime.Now.AddMonths(1));
    HttpContext.Current.Response.Cache.SetLastModified(DateTime.UtcNow);
    HttpContext.Current.Response.Cache.SetETag("\"" + etag + "\"");
}

private static string GetETag(string url)
{
    var guid = StringToGuid(url);
    var etag = new ShortGuid(guid); // see reference to ShortGuid below
    return etag.Value.Replace("-", string.Empty);
}

private static Guid StringToGuid(string value)
{
    // Create a new instance of the MD5CryptoServiceProvider object.
    var md5Hasher = MD5.Create();

    // Convert the input string to a byte array and compute the hash.
    var data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(value));
    return new Guid(data);
}

Reference: ShortGuid.

The initial HTTP response headers are now:

HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Expires: Thu, 29 May 2014 09:07:41 GMT
Last-Modified: Tue, 29 Apr 2014 09:07:41 GMT
ETag: "k28kbGNuxkWzP6gmLO2xQ"
Location: https://www.site.com/folder/file.jpg
Date: Tue, 29 Apr 2014 09:07:41 GMT
Content-Length: 241
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top