Bug 552605 - Set cache expiry and validation on both OnStartRequest and OnRedirectVerifyCallback so that our image cache entries have the union of all cache headers. r=jrmuizel
authorJoe Drew <joe@drew.ca>
Fri, 01 Jul 2011 13:03:33 -0400
changeset 72712 3a7f41ccc2267c45c15562a101fa7a94505b7e29
parent 72711 e8f2637924374e30b6ad10ac0168d24f2d3fda15
child 72713 35aa54f107aca6a4de3ac98775c83f6694993d17
push id159
push usereakhgari@mozilla.com
push dateTue, 16 Aug 2011 17:53:11 +0000
treeherdermozilla-beta@8786e3e49240 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs552605
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 552605 - Set cache expiry and validation on both OnStartRequest and OnRedirectVerifyCallback so that our image cache entries have the union of all cache headers. r=jrmuizel
modules/libpr0n/src/imgRequest.cpp
modules/libpr0n/src/imgRequest.h
--- a/modules/libpr0n/src/imgRequest.cpp
+++ b/modules/libpr0n/src/imgRequest.cpp
@@ -502,16 +502,75 @@ void imgRequest::UpdateCacheEntrySize()
 #ifdef DEBUG_joe
     nsCAutoString url;
     mURI->GetSpec(url);
     printf("CACHEPUT: %d %s %d\n", time(NULL), url.get(), imageSize);
 #endif
   }
 }
 
+void imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry, nsIRequest* aRequest)
+{
+  /* get the expires info */
+  if (aCacheEntry) {
+    nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aRequest));
+    if (cacheChannel) {
+      nsCOMPtr<nsISupports> cacheToken;
+      cacheChannel->GetCacheToken(getter_AddRefs(cacheToken));
+      if (cacheToken) {
+        nsCOMPtr<nsICacheEntryInfo> entryDesc(do_QueryInterface(cacheToken));
+        if (entryDesc) {
+          PRUint32 expiration;
+          /* get the expiration time from the caching channel's token */
+          entryDesc->GetExpirationTime(&expiration);
+
+          // Expiration time defaults to 0. We set the expiration time on our
+          // entry if it hasn't been set yet.
+          if (aCacheEntry->GetExpiryTime() == 0)
+            aCacheEntry->SetExpiryTime(expiration);
+        }
+      }
+    }
+
+    //
+    // Determine whether the cache entry must be revalidated when it expires.
+    // If so, then the cache entry must *not* be used during HISTORY loads if
+    // it has expired.
+    //
+    // Currently, only HTTP specifies this information...
+    //
+    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
+    if (httpChannel) {
+      PRBool bMustRevalidate = PR_FALSE;
+
+      httpChannel->IsNoStoreResponse(&bMustRevalidate);
+
+      if (!bMustRevalidate) {
+        httpChannel->IsNoCacheResponse(&bMustRevalidate);
+      }
+
+      if (!bMustRevalidate) {
+        nsCAutoString cacheHeader;
+
+        httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Cache-Control"),
+                                            cacheHeader);
+        if (PL_strcasestr(cacheHeader.get(), "must-revalidate")) {
+          bMustRevalidate = PR_TRUE;
+        }
+      }
+
+      // Cache entries default to not needing to validate. We ensure that
+      // multiple calls to this function don't override an earlier decision to
+      // validate by making validation a one-way decision.
+      if (bMustRevalidate)
+        aCacheEntry->SetMustValidateIfExpired(bMustRevalidate);
+    }
+  }
+}
+
 nsresult
 imgRequest::LockImage()
 {
   return mImage->LockImage();
 }
 
 nsresult
 imgRequest::UnlockImage()
@@ -745,18 +804,16 @@ NS_IMETHODIMP imgRequest::OnDiscard(imgI
   return NS_OK;
 }
 
 /** nsIRequestObserver methods **/
 
 /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
 NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
 {
-  nsresult rv;
-
   LOG_SCOPE(gImgLog, "imgRequest::OnStartRequest");
 
   // Figure out if we're multipart
   nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
   if (mpchan)
       mIsMultiPartChannel = PR_TRUE;
 
   // If we're not multipart, we shouldn't have an image yet
@@ -818,65 +875,17 @@ NS_IMETHODIMP imgRequest::OnStartRequest
       // Tell all of our proxies that we have a principal.
       nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
       while (iter.HasMore()) {
         iter.GetNext()->SetPrincipal(mPrincipal);
       }
     }
   }
 
-  /* get the expires info */
-  if (mCacheEntry) {
-    nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aRequest));
-    if (cacheChannel) {
-      nsCOMPtr<nsISupports> cacheToken;
-      cacheChannel->GetCacheToken(getter_AddRefs(cacheToken));
-      if (cacheToken) {
-        nsCOMPtr<nsICacheEntryInfo> entryDesc(do_QueryInterface(cacheToken));
-        if (entryDesc) {
-          PRUint32 expiration;
-          /* get the expiration time from the caching channel's token */
-          entryDesc->GetExpirationTime(&expiration);
-
-          /* set the expiration time on our entry */
-          mCacheEntry->SetExpiryTime(expiration);
-        }
-      }
-    }
-    //
-    // Determine whether the cache entry must be revalidated when it expires.
-    // If so, then the cache entry must *not* be used during HISTORY loads if
-    // it has expired.
-    //
-    // Currently, only HTTP specifies this information...
-    //
-    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
-    if (httpChannel) {
-      PRBool bMustRevalidate = PR_FALSE;
-
-      rv = httpChannel->IsNoStoreResponse(&bMustRevalidate);
-
-      if (!bMustRevalidate) {
-        rv = httpChannel->IsNoCacheResponse(&bMustRevalidate);
-      }
-
-      if (!bMustRevalidate) {
-        nsCAutoString cacheHeader;
-
-        rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Cache-Control"),
-                                            cacheHeader);
-        if (PL_strcasestr(cacheHeader.get(), "must-revalidate")) {
-          bMustRevalidate = PR_TRUE;
-        }
-      }
-
-      mCacheEntry->SetMustValidateIfExpired(bMustRevalidate);
-    }
-  }
-
+  SetCacheValidation(mCacheEntry, aRequest);
 
   // Shouldn't we be dead already if this gets hit?  Probably multipart/x-mixed-replace...
   if (mObservers.IsEmpty()) {
     this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
   }
 
   return NS_OK;
 }
@@ -1234,16 +1243,18 @@ NS_IMETHODIMP
 imgRequest::AsyncOnChannelRedirect(nsIChannel *oldChannel,
                                    nsIChannel *newChannel, PRUint32 flags,
                                    nsIAsyncVerifyRedirectCallback *callback)
 {
   NS_ASSERTION(mRequest && mChannel, "Got a channel redirect after we nulled out mRequest!");
   NS_ASSERTION(mChannel == oldChannel, "Got a channel redirect for an unknown channel!");
   NS_ASSERTION(newChannel, "Got a redirect to a NULL channel!");
 
+  SetCacheValidation(mCacheEntry, oldChannel);
+
   // Prepare for callback
   mRedirectCallback = callback;
   mNewRedirectChannel = newChannel;
 
   nsCOMPtr<nsIChannelEventSink> sink(do_GetInterface(mPrevChannelSink));
   if (sink) {
     nsresult rv = sink->AsyncOnChannelRedirect(oldChannel, newChannel, flags,
                                                this);
--- a/modules/libpr0n/src/imgRequest.h
+++ b/modules/libpr0n/src/imgRequest.h
@@ -124,16 +124,22 @@ public:
   inline void SetWindowID(PRUint64 aWindowId) {
     mWindowId = aWindowId;
   }
 
   inline PRUint64 WindowID() const {
     return mWindowId;
   }
 
+  // Set the cache validation information (expiry time, whether we must
+  // validate, etc) on the cache entry based on the request information.
+  // If this function is called multiple times, the information set earliest
+  // wins.
+  static void SetCacheValidation(imgCacheEntry* aEntry, nsIRequest* aRequest);
+
 private:
   friend class imgCacheEntry;
   friend class imgRequestProxy;
   friend class imgLoader;
   friend class imgCacheValidator;
   friend class imgStatusTracker;
   friend class imgCacheExpirationTracker;
   friend class imgRequestNotifyRunnable;