Bug 1376496 - Part 2 - Don't request FD from parent when JAR file is cached. r=mayhemer
MozReview-Commit-ID: 6xooCVnBehj
--- 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