Bug 1376496 - Part 2 - Don't request FD from parent when JAR file is cached. r=mayhemer draft
authorHaik Aftandilian <haftandilian@mozilla.com>
Fri, 21 Jul 2017 15:19:09 -0700
changeset 615950 e8045206d5b5196d26109967966d91476470b058
parent 615949 c45070e38ce6582f3743bfb4c61f7398d1617e73
child 615951 15f727760ab8e37dea2db5024bca6f5dde8ef81b
push id70534
push userhaftandilian@mozilla.com
push dateWed, 26 Jul 2017 15:49:48 +0000
reviewersmayhemer
bugs1376496
milestone56.0a1
Bug 1376496 - Part 2 - Don't request FD from parent when JAR file is cached. r=mayhemer MozReview-Commit-ID: 6xooCVnBehj
modules/libjar/nsIJARChannel.idl
modules/libjar/nsIZipReader.idl
modules/libjar/nsJAR.cpp
modules/libjar/nsJAR.h
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
netwerk/protocol/res/ExtensionProtocolHandler.cpp
--- a/modules/libjar/nsIJARChannel.idl
+++ b/modules/libjar/nsIJARChannel.idl
@@ -27,9 +27,20 @@ interface nsIJARChannel : nsIChannel
      */
     attribute nsIFile jarFile;
 
     /**
      * Returns the zip entry if the file is synchronously accessible.
      * This will work even without opening the channel.
      */
     readonly attribute nsIZipEntry zipEntry;
+
+    /**
+     * If the JAR file is cached in the JAR cache, returns true and
+     * holds a reference to the cached zip reader to be used when
+     * the channel is read from, ensuring the cached reader will be used.
+     * For a successful read from the cached reader, close() should not
+     * be called on the reader--per nsIZipReader::getZip() documentation.
+     * Returns false if the JAR file is not cached. Calling this method
+     * after the channel has been opened is not permitted.
+     */
+    boolean ensureCached();
 };
--- a/modules/libjar/nsIZipReader.idl
+++ b/modules/libjar/nsIZipReader.idl
@@ -229,16 +229,26 @@ interface nsIZipReaderCache : nsISupport
      * returned.
      *
      * @note If someone called close() on the shared nsIZipReader, this method 
      *       will return the closed zip reader.
      */
     nsIZipReader getZip(in nsIFile zipFile);
 
     /**
+     * Like getZip(), returns a (possibly shared) nsIZipReader for an nsIFile,
+     * but if a zip reader for the given file is not in the cache, returns
+     * error NS_ERROR_CACHE_KEY_NOT_FOUND rather than creating a new reader.
+     *
+     * @note If someone called close() on the shared nsIZipReader, this method
+     *       will return the closed zip reader.
+     */
+    nsIZipReader getZipIfCached(in nsIFile zipFile);
+
+    /**
      * returns true if this zipreader already has this file cached
      */
     bool isCached(in nsIFile zipFile);
 
     /**
      * Returns a (possibly shared) nsIZipReader for a zip inside another zip
      *
      * See getZip
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -1115,18 +1115,19 @@ nsZipReaderCache::IsCached(nsIFile* zipF
     return rv;
 
   uri.Insert(NS_LITERAL_CSTRING("file:"), 0);
 
   *aResult = mZips.Contains(uri);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
+nsresult
+nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result,
+                         bool failOnMiss)
 {
   NS_ENSURE_ARG_POINTER(zipFile);
   nsresult rv;
   MutexAutoLock lock(mLock);
 
 #ifdef ZIP_CACHE_HIT_RATE
   mZipCacheLookups++;
 #endif
@@ -1140,31 +1141,47 @@ nsZipReaderCache::GetZip(nsIFile* zipFil
   RefPtr<nsJAR> zip;
   mZips.Get(uri, getter_AddRefs(zip));
   if (zip) {
 #ifdef ZIP_CACHE_HIT_RATE
     mZipCacheHits++;
 #endif
     zip->ClearReleaseTime();
   } else {
+    if (failOnMiss) {
+      return NS_ERROR_CACHE_KEY_NOT_FOUND;
+    }
+
     zip = new nsJAR();
     zip->SetZipReaderCache(this);
     rv = zip->Open(zipFile);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     MOZ_ASSERT(!mZips.Contains(uri));
     mZips.Put(uri, zip);
   }
   zip.forget(result);
   return rv;
 }
 
 NS_IMETHODIMP
+nsZipReaderCache::GetZipIfCached(nsIFile* zipFile, nsIZipReader* *result)
+{
+  return GetZip(zipFile, result, true);
+}
+
+NS_IMETHODIMP
+nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
+{
+  return GetZip(zipFile, result, false);
+}
+
+NS_IMETHODIMP
 nsZipReaderCache::GetInnerZip(nsIFile* zipFile, const nsACString &entry,
                               nsIZipReader* *result)
 {
   NS_ENSURE_ARG_POINTER(zipFile);
 
   nsCOMPtr<nsIZipReader> outerZipReader;
   nsresult rv = GetZip(zipFile, getter_AddRefs(outerZipReader));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/modules/libjar/nsJAR.h
+++ b/modules/libjar/nsJAR.h
@@ -209,13 +209,15 @@ protected:
 
 #ifdef ZIP_CACHE_HIT_RATE
   uint32_t              mZipCacheLookups;
   uint32_t              mZipCacheHits;
   uint32_t              mZipCacheFlushes;
   uint32_t              mZipSyncMisses;
 #endif
 
+private:
+  nsresult GetZip(nsIFile* zipFile, nsIZipReader* *result, bool failOnMiss);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 #endif /* nsJAR_h_ */
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -267,17 +267,19 @@ nsJARChannel::CreateJarInput(nsIZipReade
     nsresult rv = NS_OK;
     if (mJarFile) {
         rv = mJarFile->Clone(getter_AddRefs(clonedFile));
         if (NS_FAILED(rv))
             return rv;
     }
 
     nsCOMPtr<nsIZipReader> reader;
-    if (jarCache) {
+    if (mPreCachedJarReader) {
+      reader = mPreCachedJarReader;
+    } else if (jarCache) {
         MOZ_ASSERT(mJarFile);
         if (mInnerJarEntry.IsEmpty())
             rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader));
         else
             rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry,
                                        getter_AddRefs(reader));
     } else {
         // create an uncached jar reader
@@ -896,16 +898,66 @@ nsJARChannel::SetJarFile(nsIFile *aFile)
 {
     if (mOpened) {
         return NS_ERROR_IN_PROGRESS;
     }
     mJarFileOverride = aFile;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsJARChannel::EnsureCached(bool *aIsCached)
+{
+    nsresult rv;
+    *aIsCached = false;
+
+    if (mOpened) {
+        return NS_ERROR_ALREADY_OPENED;
+    }
+
+    if (mPreCachedJarReader) {
+        // We've already been called and found the JAR is cached
+        *aIsCached = true;
+        return NS_OK;
+    }
+
+    nsCOMPtr<nsIURI> innerFileURI;
+    rv = mJarURI->GetJARFile(getter_AddRefs(innerFileURI));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFileURL> innerFileURL = do_QueryInterface(innerFileURI, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> jarFile;
+    rv = innerFileURL->GetFile(getter_AddRefs(jarFile));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIProtocolHandler> handler;
+    rv = ioService->GetProtocolHandler("jar", getter_AddRefs(handler));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIJARProtocolHandler> jarHandler = do_QueryInterface(handler);
+    MOZ_ASSERT(jarHandler);
+
+    nsCOMPtr<nsIZipReaderCache> jarCache;
+    rv = jarHandler->GetJARCache(getter_AddRefs(jarCache));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = jarCache->GetZipIfCached(jarFile, getter_AddRefs(mPreCachedJarReader));
+    if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) {
+        return NS_OK;
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    *aIsCached = true;
+    return NS_OK;
+}
 
 NS_IMETHODIMP
 nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
 {
     nsresult rv = LookupFile(false);
     if (NS_FAILED(rv))
         return rv;
 
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -96,16 +96,17 @@ private:
 
     mozilla::net::MemoryDownloader::Data mTempMem;
     nsCOMPtr<nsIInputStreamPump>    mPump;
     // mRequest is only non-null during OnStartRequest, so we'll have a pointer
     // to the request if we get called back via RetargetDeliveryTo.
     nsCOMPtr<nsIRequest>            mRequest;
     nsCOMPtr<nsIFile>               mJarFile;
     nsCOMPtr<nsIFile>               mJarFileOverride;
+    nsCOMPtr<nsIZipReader>          mPreCachedJarReader;
     nsCOMPtr<nsIURI>                mJarBaseURI;
     nsCString                       mJarEntry;
     nsCString                       mInnerJarEntry;
 
     // True if this channel should not download any remote files.
     bool                            mBlockRemoteFiles;
 };
 
--- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -773,16 +773,25 @@ Result<Ok, nsresult>
 ExtensionProtocolHandler::SubstituteRemoteJarChannel(nsIURI* aURI,
                                                      nsILoadInfo* aLoadinfo,
                                                      nsACString& aResolvedSpec,
                                                      nsIChannel** aRetVal)
 {
   MOZ_ASSERT(IsNeckoChild());
   nsresult rv;
 
+  nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(*aRetVal, &rv);
+  NS_TRY(rv);
+
+  bool isCached = false;
+  NS_TRY(jarChannel->EnsureCached(&isCached));
+  if (isCached) {
+    return Ok();
+  }
+
   // Build a JAR URI for this jar:file:// URI and use it to extract the
   // inner file URI.
   nsCOMPtr<nsIURI> uri;
   NS_TRY(NS_NewURI(getter_AddRefs(uri), aResolvedSpec));
 
   nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(uri, &rv);
   NS_TRY(rv);
 
@@ -790,19 +799,16 @@ ExtensionProtocolHandler::SubstituteRemo
   NS_TRY(jarURI->GetJARFile(getter_AddRefs(innerFileURI)));
 
   nsCOMPtr<nsIFileURL> innerFileURL = do_QueryInterface(innerFileURI, &rv);
   NS_TRY(rv);
 
   nsCOMPtr<nsIFile> jarFile;
   NS_TRY(innerFileURL->GetFile(getter_AddRefs(jarFile)));
 
-  nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(*aRetVal, &rv);
-  NS_TRY(rv);
-
   RefPtr<ExtensionStreamGetter> streamGetter =
     new ExtensionStreamGetter(aURI, aLoadinfo, jarChannel.forget(), jarFile);
 
   NewSimpleChannel(aURI, aLoadinfo, streamGetter, aRetVal);
   return Ok();
 }
 
 #undef NS_TRY