Backout changeset 1bce26e37922 (bug 719180 part 1) for possible orange
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 06 Sep 2012 18:51:54 -0400
changeset 104523 d37cd3f56b32a85a3599b395f425584f0eeed21e
parent 104522 d6e4864101e12ba77751d00d059e9875791eacd2
child 104524 9368efb05a0727b4b392d5e9cf3c6bcc50143c56
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs719180
milestone18.0a1
backs out1bce26e379224a0b961d772ec684170a2f8bd286
Backout changeset 1bce26e37922 (bug 719180 part 1) for possible orange
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -52,58 +52,67 @@ class nsJARInputThunk : public nsIInputS
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
 
     nsJARInputThunk(nsIZipReader *zipReader,
                     nsIURI* fullJarURI,
                     const nsACString &jarEntry,
-                    bool usingJarCache)
-        : mUsingJarCache(usingJarCache)
+                    nsIZipReaderCache *jarCache)
+        : mJarCache(jarCache)
         , mJarReader(zipReader)
         , mJarEntry(jarEntry)
         , mContentLength(-1)
     {
         if (fullJarURI) {
 #ifdef DEBUG
             nsresult rv =
 #endif
                 fullJarURI->GetAsciiSpec(mJarDirSpec);
             NS_ASSERTION(NS_SUCCEEDED(rv), "this shouldn't fail");
         }
     }
 
     virtual ~nsJARInputThunk()
     {
-        Close();
+        if (!mJarCache && mJarReader)
+            mJarReader->Close();
+    }
+
+    void GetJarReader(nsIZipReader **result)
+    {
+        NS_IF_ADDREF(*result = mJarReader);
     }
 
     int32_t GetContentLength()
     {
         return mContentLength;
     }
 
-    nsresult Init();
+    nsresult EnsureJarStream();
 
 private:
 
-    bool                        mUsingJarCache;
+    nsCOMPtr<nsIZipReaderCache> mJarCache;
     nsCOMPtr<nsIZipReader>      mJarReader;
     nsCString                   mJarDirSpec;
     nsCOMPtr<nsIInputStream>    mJarStream;
     nsCString                   mJarEntry;
     int32_t                     mContentLength;
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputThunk, nsIInputStream)
 
 nsresult
-nsJARInputThunk::Init()
+nsJARInputThunk::EnsureJarStream()
 {
+    if (mJarStream)
+        return NS_OK;
+
     nsresult rv;
     if (ENTRY_IS_DIRECTORY(mJarEntry)) {
         // A directory stream also needs the Spec of the FullJarURI
         // because is included in the stream data itself.
 
         NS_ENSURE_STATE(!mJarDirSpec.IsEmpty());
 
         rv = mJarReader->GetInputStreamWithSpec(mJarDirSpec,
@@ -130,38 +139,37 @@ nsJARInputThunk::Init()
     mContentLength = avail < PR_INT32_MAX ? (int32_t) avail : -1;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARInputThunk::Close()
 {
-    nsresult rv = NS_OK;
-
     if (mJarStream)
-        rv = mJarStream->Close();
+        return mJarStream->Close();
 
-    if (!mUsingJarCache && mJarReader)
-        mJarReader->Close();
-
-    mJarReader = nullptr;
-
-    return rv;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARInputThunk::Available(uint64_t *avail)
 {
+    nsresult rv = EnsureJarStream();
+    if (NS_FAILED(rv)) return rv;
+
     return mJarStream->Available(avail);
 }
 
 NS_IMETHODIMP
 nsJARInputThunk::Read(char *buf, uint32_t count, uint32_t *countRead)
 {
+    nsresult rv = EnsureJarStream();
+    if (NS_FAILED(rv)) return rv;
+
     return mJarStream->Read(buf, count, countRead);
 }
 
 NS_IMETHODIMP
 nsJARInputThunk::ReadSegments(nsWriteSegmentFun writer, void *closure,
                               uint32_t count, uint32_t *countRead)
 {
     // stream transport does only calls Read()
@@ -183,28 +191,32 @@ nsJARInputThunk::IsNonBlocking(bool *non
 nsJARChannel::nsJARChannel()
     : mOpened(false)
     , mAppURI(nullptr)
     , mContentLength(-1)
     , mLoadFlags(LOAD_NORMAL)
     , mStatus(NS_OK)
     , mIsPending(false)
     , mIsUnsafe(true)
+    , mJarInput(nullptr)
 {
 #if defined(PR_LOGGING)
     if (!gJarProtocolLog)
         gJarProtocolLog = PR_NewLogModule("nsJarProtocol");
 #endif
 
     // hold an owning reference to the jar handler
     NS_ADDREF(gJarHandler);
 }
 
 nsJARChannel::~nsJARChannel()
 {
+    // with the exception of certain error cases mJarInput will already be null.
+    NS_IF_RELEASE(mJarInput);
+
     // release owning reference to the jar handler
     nsJARProtocolHandler *handler = gJarHandler;
     NS_RELEASE(handler); // NULL parameter
 }
 
 NS_IMPL_ISUPPORTS_INHERITED6(nsJARChannel,
                              nsHashPropertyBag,
                              nsIRequest,
@@ -244,32 +256,30 @@ nsJARChannel::Init(nsIURI *uri)
 
 #if defined(PR_LOGGING)
     mJarURI->GetSpec(mSpec);
 #endif
     return rv;
 }
 
 nsresult
-nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resultInput)
+nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache)
 {
-    MOZ_ASSERT(resultInput);
-
     // important to pass a clone of the file since the nsIFile impl is not
     // necessarily MT-safe
     nsCOMPtr<nsIFile> clonedFile;
     nsresult rv = mJarFile->Clone(getter_AddRefs(clonedFile));
     if (NS_FAILED(rv))
         return rv;
 
     nsCOMPtr<nsIZipReader> reader;
     if (jarCache) {
         if (mInnerJarEntry.IsEmpty())
             rv = jarCache->GetZip(mJarFile, getter_AddRefs(reader));
-        else
+        else 
             rv = jarCache->GetInnerZip(mJarFile, mInnerJarEntry,
                                        getter_AddRefs(reader));
     } else {
         // create an uncached jar reader
         nsCOMPtr<nsIZipReader> outerReader = do_CreateInstance(kZipReaderCID, &rv);
         if (NS_FAILED(rv))
             return rv;
 
@@ -285,47 +295,36 @@ nsJARChannel::CreateJarInput(nsIZipReade
                 return rv;
 
             rv = reader->OpenInner(outerReader, mInnerJarEntry);
         }
     }
     if (NS_FAILED(rv))
         return rv;
 
-    nsRefPtr<nsJARInputThunk> input = new nsJARInputThunk(reader,
-                                                          mJarURI,
-                                                          mJarEntry,
-                                                          jarCache != nullptr
-                                                          );
-    rv = input->Init();
-    if (NS_FAILED(rv))
-        return rv;
-
-    // Make GetContentLength meaningful
-    mContentLength = input->GetContentLength();
-
-    input.forget(resultInput);
+    mJarInput = new nsJARInputThunk(reader, mJarURI, mJarEntry, jarCache);
+    if (!mJarInput)
+        return NS_ERROR_OUT_OF_MEMORY;
+    NS_ADDREF(mJarInput);
     return NS_OK;
 }
 
 nsresult
-nsJARChannel::LookupFile()
+nsJARChannel::EnsureJarInput(bool blocking)
 {
-    LOG(("nsJARChannel::LookupFile [this=%x %s]\n", this, mSpec.get()));
+    LOG(("nsJARChannel::EnsureJarInput [this=%x %s]\n", this, mSpec.get()));
 
     nsresult rv;
     nsCOMPtr<nsIURI> uri;
 
     rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI));
-    if (NS_FAILED(rv))
-        return rv;
+    if (NS_FAILED(rv)) return rv;
 
     rv = mJarURI->GetJAREntry(mJarEntry);
-    if (NS_FAILED(rv))
-        return rv;
+    if (NS_FAILED(rv)) return rv;
 
     // The name of the JAR entry must not contain URL-escaped characters:
     // we're moving from URL domain to a filename domain here. nsStandardURL
     // does basic escaping by default, which breaks reading zipped files which
     // have e.g. spaces in their filenames.
     NS_UnescapeURL(mJarEntry);
 
     // try to get a nsIFile directly from the url, which will often succeed.
@@ -345,17 +344,37 @@ nsJARChannel::LookupFile()
                 fileURL = do_QueryInterface(innerJarURI);
             if (fileURL) {
                 fileURL->GetFile(getter_AddRefs(mJarFile));
                 jarURI->GetJAREntry(mInnerJarEntry);
             }
         }
     }
 
+    if (mJarFile) {
+        mIsUnsafe = false;
+
+        // NOTE: we do not need to deal with mSecurityInfo here,
+        // because we're loading from a local file
+        rv = CreateJarInput(gJarHandler->JarCache());
+    }
+    else if (blocking) {
+        NS_NOTREACHED("need sync downloader");
+        rv = NS_ERROR_NOT_IMPLEMENTED;
+    }
+    else {
+        // kick off an async download of the base URI...
+        rv = NS_NewDownloader(getter_AddRefs(mDownloader), this);
+        if (NS_SUCCEEDED(rv))
+            rv = NS_OpenURI(mDownloader, nullptr, mJarBaseURI, nullptr,
+                            mLoadGroup, mCallbacks,
+                            mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS));
+    }
     return rv;
+
 }
 
 //-----------------------------------------------------------------------------
 // nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsJARChannel::GetName(nsACString &result)
@@ -605,16 +624,20 @@ nsJARChannel::GetContentDispositionHeade
 
     aContentDispositionHeader = mContentDispositionHeader;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::GetContentLength(int32_t *result)
 {
+    // if content length is unknown, query mJarInput...
+    if (mContentLength < 0 && mJarInput)
+        mContentLength = mJarInput->GetContentLength();
+
     *result = mContentLength;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::SetContentLength(int32_t aContentLength)
 {
     // XXX does this really make any sense at all?
@@ -622,96 +645,77 @@ nsJARChannel::SetContentLength(int32_t a
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::Open(nsIInputStream **stream)
 {
     LOG(("nsJARChannel::Open [this=%x]\n", this));
 
-    NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
+    NS_ENSURE_TRUE(!mJarInput, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
 
     mJarFile = nullptr;
     mIsUnsafe = true;
 
-    nsresult rv = LookupFile();
-    if (NS_FAILED(rv))
-        return rv;
+    nsresult rv = EnsureJarInput(true);
+    if (NS_FAILED(rv)) return rv;
+
+    if (!mJarInput)
+        return NS_ERROR_UNEXPECTED;
 
-    // If mJarInput was not set by LookupFile, the JAR is a remote jar.
-    if (!mJarFile) {
-        NS_NOTREACHED("need sync downloader");
-        return NS_ERROR_NOT_IMPLEMENTED;
-    }
+    // force load the jar file now so GetContentLength will return a
+    // meaningful value once we return.
+    rv = mJarInput->EnsureJarStream();
+    if (NS_FAILED(rv)) return rv;
 
-    nsCOMPtr<nsJARInputThunk> input;
-    rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
-    if (NS_FAILED(rv))
-        return rv;
+    NS_ADDREF(*stream = mJarInput);
 
-    input.forget(stream);
     mOpened = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
 {
     LOG(("nsJARChannel::AsyncOpen [this=%x]\n", this));
 
     NS_ENSURE_ARG_POINTER(listener);
-    NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
 
     mJarFile = nullptr;
     mIsUnsafe = true;
 
     // Initialize mProgressSink
     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
 
-    nsresult rv = LookupFile();
-    if (NS_FAILED(rv))
-        return rv;
+    nsresult rv = EnsureJarInput(false);
+    if (NS_FAILED(rv)) return rv;
 
     // These variables must only be set if we're going to trigger an
     // OnStartRequest, either from AsyncRead or OnDownloadComplete.
-    // 
-    // That means: Do not add early return statements beyond this point!
     mListener = listener;
     mListenerContext = ctx;
     mIsPending = true;
-
-    if (!mJarFile) {
-        // Not a local file...
-        // kick off an async download of the base URI...
-        rv = NS_NewDownloader(getter_AddRefs(mDownloader), this);
+    if (mJarInput) {
+        // create input stream pump and call AsyncRead as a block
+        rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput);
         if (NS_SUCCEEDED(rv))
-            rv = NS_OpenURI(mDownloader, nullptr, mJarBaseURI, nullptr,
-                            mLoadGroup, mCallbacks,
-                            mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS));
-    }
-    else {
-        nsCOMPtr<nsJARInputThunk> input;
-        rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
-        if (NS_SUCCEEDED(rv)) {
-            // create input stream pump and call AsyncRead as a block
-            rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input);
-            if (NS_SUCCEEDED(rv))
-                rv = mPump->AsyncRead(this, nullptr);
+            rv = mPump->AsyncRead(this, nullptr);
+
+        // If we failed to create the pump or initiate the AsyncRead,
+        // then we need to clear these variables.
+        if (NS_FAILED(rv)) {
+            mIsPending = false;
+            mListenerContext = nullptr;
+            mListener = nullptr;
+            return rv;
         }
     }
 
-    if (NS_FAILED(rv)) {
-        mIsPending = false;
-        mListenerContext = nullptr;
-        mListener = nullptr;
-        return rv;
-    }
-
     if (mLoadGroup)
         mLoadGroup->AddRequest(this, nullptr);
 
     mOpened = true;
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
@@ -821,22 +825,21 @@ nsJARChannel::OnDownloadComplete(nsIDown
         nsCOMPtr<nsIViewSourceChannel> viewSource = do_QueryInterface(channel);
         if (viewSource) {
             status = NS_ERROR_UNSAFE_CONTENT_TYPE;
         }
     }
 
     if (NS_SUCCEEDED(status)) {
         mJarFile = file;
-
-        nsCOMPtr<nsJARInputThunk> input;
-        rv = CreateJarInput(nullptr, getter_AddRefs(input));
+    
+        rv = CreateJarInput(nullptr);
         if (NS_SUCCEEDED(rv)) {
             // create input stream pump
-            rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input);
+            rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput);
             if (NS_SUCCEEDED(rv))
                 rv = mPump->AsyncRead(this, nullptr);
         }
         status = rv;
     }
 
     if (NS_FAILED(status)) {
         mStatus = status;
@@ -873,16 +876,17 @@ nsJARChannel::OnStopRequest(nsIRequest *
         mListener = 0;
         mListenerContext = 0;
     }
 
     if (mLoadGroup)
         mLoadGroup->RemoveRequest(this, nullptr, status);
 
     mPump = 0;
+    NS_IF_RELEASE(mJarInput);
     mIsPending = false;
     mDownloader = 0; // this may delete the underlying jar file
 
     // Drop notification callbacks to prevent cycles.
     mCallbacks = 0;
     mProgressSink = 0;
 
     return NS_OK;
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -41,18 +41,18 @@ public:
     NS_DECL_NSISTREAMLISTENER
 
     nsJARChannel();
     virtual ~nsJARChannel();
 
     nsresult Init(nsIURI *uri);
 
 private:
-    nsresult CreateJarInput(nsIZipReaderCache *, nsJARInputThunk **);
-    nsresult LookupFile();
+    nsresult CreateJarInput(nsIZipReaderCache *);
+    nsresult EnsureJarInput(bool blocking);
 
 #if defined(PR_LOGGING)
     nsCString                       mSpec;
 #endif
 
     bool                            mOpened;
 
     nsCOMPtr<nsIJARURI>             mJarURI;
@@ -72,16 +72,17 @@ private:
      * empty */
     uint32_t                        mContentDisposition;
     int32_t                         mContentLength;
     uint32_t                        mLoadFlags;
     nsresult                        mStatus;
     bool                            mIsPending;
     bool                            mIsUnsafe;
 
+    nsJARInputThunk                *mJarInput;
     nsCOMPtr<nsIStreamListener>     mDownloader;
     nsCOMPtr<nsIInputStreamPump>    mPump;
     nsCOMPtr<nsIFile>               mJarFile;
     nsCOMPtr<nsIURI>                mJarBaseURI;
     nsCString                       mJarEntry;
     nsCString                       mInnerJarEntry;
 };