--- 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;