fixes bug 209560 "Secure JS doesn't work from https JARs" r=dougt sr=alecf

This commit is contained in:
darin%netscape.com 2003-06-23 22:58:28 +00:00
parent 7b3142ec4c
commit 0692f0b9d0
10 changed files with 291 additions and 222 deletions

View File

@ -225,7 +225,12 @@ nsJAR::Open()
NS_IMETHODIMP
nsJAR::Close()
{
#ifdef STANDALONE
// nsZipReadState::CloseArchive closes the file descriptor
#else
if (mFd)
PR_Close(mFd);
#endif
mFd = nsnull;
PRInt32 err = mZip.CloseArchive();
return ziperr2nsresult(err);

View File

@ -29,6 +29,7 @@
static NS_DEFINE_CID(kScriptSecurityManagerCID, NS_SCRIPTSECURITYMANAGER_CID);
static NS_DEFINE_CID(kInputStreamChannelCID, NS_INPUTSTREAMCHANNEL_CID);
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
//-----------------------------------------------------------------------------
@ -63,7 +64,12 @@ public:
{
NS_ASSERTION(mJarFile, "no jar file");
}
virtual ~nsJARInputThunk() {}
virtual ~nsJARInputThunk()
{
if (!mJarCache && mJarReader)
mJarReader->Close();
}
void GetJarReader(nsIZipReader **result)
{
@ -96,8 +102,18 @@ nsJARInputThunk::EnsureJarStream()
return NS_OK;
nsresult rv;
rv = mJarCache->GetZip(mJarFile, getter_AddRefs(mJarReader));
if (mJarCache)
rv = mJarCache->GetZip(mJarFile, getter_AddRefs(mJarReader));
else {
// create an uncached jar reader
mJarReader = do_CreateInstance(kZipReaderCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = mJarReader->Init(mJarFile);
if (NS_FAILED(rv)) return rv;
rv = mJarReader->Open();
}
if (NS_FAILED(rv)) return rv;
rv = mJarReader->GetInputStream(mJarEntry.get(),
@ -205,7 +221,7 @@ nsJARChannel::Init(nsIURI *uri)
}
nsresult
nsJARChannel::CreateJarInput()
nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache)
{
// important to pass a clone of the file since the nsIFile impl is not
// necessarily MT-safe
@ -213,7 +229,7 @@ nsJARChannel::CreateJarInput()
nsresult rv = mJarFile->Clone(getter_AddRefs(clonedFile));
if (NS_FAILED(rv)) return rv;
mJarInput = new nsJARInputThunk(clonedFile, mJarEntry, gJarHandler->JarCache());
mJarInput = new nsJARInputThunk(clonedFile, mJarEntry, jarCache);
if (!mJarInput)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mJarInput);
@ -242,7 +258,7 @@ nsJARChannel::EnsureJarInput(PRBool blocking)
}
if (mJarFile) {
rv = CreateJarInput();
rv = CreateJarInput(gJarHandler->JarCache());
}
else if (blocking) {
NS_NOTREACHED("need sync downloader");
@ -250,9 +266,11 @@ nsJARChannel::EnsureJarInput(PRBool blocking)
}
else {
// kick off an async download of the base URI...
rv = NS_NewDownloader(getter_AddRefs(mDownloader),
mJarBaseURI, this, nsnull, PR_FALSE,
mLoadGroup, mCallbacks, mLoadFlags);
rv = NS_NewDownloader(getter_AddRefs(mDownloader), this);
if (NS_SUCCEEDED(rv))
rv = NS_OpenURI(mDownloader, nsnull, mJarBaseURI, nsnull,
mLoadGroup, mCallbacks,
mLoadFlags & ~LOAD_DOCUMENT_URI);
}
return rv;
@ -606,14 +624,13 @@ nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
NS_IMETHODIMP
nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
nsISupports *closure,
nsresult status,
nsIFile *file)
nsresult status,
nsIFile *file)
{
if (NS_SUCCEEDED(status)) {
mJarFile = file;
nsresult rv = CreateJarInput();
nsresult rv = CreateJarInput(nsnull);
if (NS_SUCCEEDED(rv)) {
// create input stream pump
rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput);
@ -628,7 +645,6 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
OnStopRequest(nsnull, nsnull, status);
}
mDownloader = 0;
return NS_OK;
}
@ -665,6 +681,7 @@ nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
mPump = 0;
NS_IF_RELEASE(mJarInput);
mIsPending = PR_FALSE;
mDownloader = 0; // this may delete the underlying jar file
return NS_OK;
}

View File

@ -44,6 +44,7 @@
#include "nsIInterfaceRequestor.h"
#include "nsIProgressEventSink.h"
#include "nsIStreamListener.h"
#include "nsIZipReader.h"
#include "nsIDownloader.h"
#include "nsILoadGroup.h"
#include "nsIFile.h"
@ -75,7 +76,7 @@ public:
nsresult Init(nsIURI *uri);
private:
nsresult CreateJarInput();
nsresult CreateJarInput(nsIZipReaderCache *);
nsresult EnsureJarInput(PRBool blocking);
#if defined(PR_LOGGING)
@ -98,8 +99,8 @@ private:
PRBool mIsPending;
nsJARInputThunk *mJarInput;
nsCOMPtr<nsIStreamListener> mDownloader;
nsCOMPtr<nsIInputStreamPump> mPump;
nsCOMPtr<nsIDownloader> mDownloader;
nsCOMPtr<nsIFile> mJarFile;
nsCOMPtr<nsIURI> mJarBaseURI;
nsCString mJarEntry;

View File

@ -1,65 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIRequest.idl"
#include "nsIStreamListener.idl"
interface nsIURI;
interface nsILoadGroup;
interface nsIInterfaceRequestor;
interface nsIFile;
interface nsIDownloader;
interface nsIDownloadObserver;
[scriptable, uuid(6e0fc962-4a6f-4fa6-831f-8c26c554407f)]
/**
* nsIDownloader
*
* A downloader is a special implementation of a nsIStreamListener that will
* make the contents of the stream available as a file. This may utilize the
* disk cache as an optimization to avoid an extra copy of the data on disk.
* The resulting file is valid from the time the downloader completes until
* the last reference to the downloader is released.
*/
[scriptable, uuid(fafe41a9-a531-4d6d-89bc-588a6522fb4e)]
interface nsIDownloader : nsIStreamListener
{
/**
* Initialize this downloader
*
* @param observer
* the observer to be notified when the download completes.
* @param downloadLocation
* the location where the stream contents should be written.
* if null, the downloader will select a location and the
* resulting file will be deleted (or otherwise made invalid)
* when the downloader object is destroyed. if an explicit
* download location is specified then the resulting file will
* not be deleted, and it will be the callers responsibility
* to keep track of the file, etc.
*/
void init(in nsIDownloadObserver observer,
in nsIFile downloadLocation);
};
[scriptable, uuid(814bd098-4dfb-46dd-8305-9052c998ed94)]
interface nsIDownloadObserver : nsISupports
{
/**
* Called to signal a download that has completed.
*/
void onDownloadComplete(in nsIDownloader downloader,
in nsISupports ctxt,
in nsresult status,
in nsIFile result);
};
[scriptable, uuid(9632cc0d-864d-4f92-b7e5-bd8097c4e9a5)]
interface nsIDownloader : nsISupports
{
void init(in nsIURI uri,
in nsIDownloadObserver completionObserver,
in nsISupports ctxt,
in boolean synchronous,
in nsILoadGroup loadGroup,
in nsIInterfaceRequestor notificationCallbacks,
in nsLoadFlags loadAttributes);
in nsresult status,
in nsIFile result);
};

View File

@ -366,24 +366,17 @@ NS_NewLoadGroup(nsILoadGroup **result,
return rv;
}
inline nsresult
NS_NewDownloader(nsIDownloader **result,
nsIURI *uri,
nsIDownloadObserver *observer,
nsISupports *context = nsnull,
PRBool synchronous = PR_FALSE,
nsILoadGroup *loadGroup = nsnull,
nsIInterfaceRequestor *callbacks = nsnull,
PRUint32 loadFlags = nsIRequest::LOAD_NORMAL)
NS_NewDownloader(nsIStreamListener **result,
nsIDownloadObserver *observer,
nsIFile *downloadLocation = nsnull)
{
nsresult rv;
static NS_DEFINE_CID(kDownloaderCID, NS_DOWNLOADER_CID);
nsCOMPtr<nsIDownloader> downloader =
do_CreateInstance(kDownloaderCID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = downloader->Init(uri, observer, context, synchronous, loadGroup,
callbacks, loadFlags);
rv = downloader->Init(observer, downloadLocation);
if (NS_SUCCEEDED(rv))
NS_ADDREF(*result = downloader);
}

View File

@ -1,147 +1,162 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDownloader.h"
#include "nsIInputStream.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIChannel.h"
#include "nsIFileChannel.h"
#include "nsICachingChannel.h"
#include "nsProxiedService.h"
#include "nsIFile.h"
#include "nsIFileURL.h"
#include "nsXPIDLString.h"
#include "nsIInputStream.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsNetUtil.h"
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
// XXX this code is ripped from profile/src/nsProfile.cpp and is further
// duplicated in uriloader/exthandler. this should probably be moved
// into xpcom or some other shared library.
#include <stdlib.h>
#define TABLE_SIZE 36
static const char table[] =
{ 'a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t',
'u','v','w','x','y','z','0','1','2','3',
'4','5','6','7','8','9' };
static void
MakeRandomString(char *buf, PRInt32 bufLen)
{
// turn PR_Now() into milliseconds since epoch
// and salt rand with that.
double fpTime;
LL_L2D(fpTime, PR_Now());
srand((uint)(fpTime * 1e-6 + 0.5)); // use 1e-6, granularity of PR_Now() on the mac is seconds
// XXX this API seems all wrong for "sync" downloading
PRInt32 i;
for (i=0;i<bufLen;i++) {
*buf++ = table[rand()%TABLE_SIZE];
}
*buf = 0;
}
// XXX
nsDownloader::~nsDownloader()
{
if (mLocation && mLocationIsTemp) {
// release the sink first since it may still hold an open file
// descriptor to mLocation. this needs to happen before the
// file can be removed otherwise the Remove call will fail.
mSink = 0;
nsresult rv = mLocation->Remove(PR_FALSE);
if (NS_FAILED(rv))
NS_ERROR("unable to remove temp file");
}
}
NS_IMPL_ISUPPORTS3(nsDownloader,
nsIDownloader,
nsIStreamListener,
nsIRequestObserver)
NS_IMETHODIMP
nsDownloader::Init(nsIURI* aURL,
nsIDownloadObserver* aObserver,
nsISupports* aContext,
PRBool aIsSynchronous,
nsILoadGroup* aGroup,
nsIInterfaceRequestor* aCallbacks,
nsLoadFlags aLoadFlags)
nsDownloader::Init(nsIDownloadObserver *observer, nsIFile *location)
{
NS_ENSURE_ARG_POINTER(aObserver);
nsresult rv;
mObserver = aObserver;
mContext = aContext;
nsCOMPtr<nsIFile> file;
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURL);
if (fileURL)
fileURL->GetFile(getter_AddRefs(file));
if (file) {
if (aIsSynchronous)
return mObserver->OnDownloadComplete(this, mContext, rv, file);
// If the open failed or the file is local, call the observer.
// don't callback synchronously as it puts the caller
// in a recursive situation and breaks the asynchronous
// semantics of nsIDownloader
nsCOMPtr<nsIProxyObjectManager> pIProxyObjectManager =
do_GetService(kProxyObjectManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDownloadObserver> pObserver;
rv = pIProxyObjectManager->GetProxyForObject(NS_CURRENT_EVENTQ,
NS_GET_IID(nsIDownloadObserver), mObserver,
PROXY_ASYNC | PROXY_ALWAYS, getter_AddRefs(pObserver));
if (NS_FAILED(rv)) return rv;
return pObserver->OnDownloadComplete(this, mContext, NS_OK, file);
}
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull,
aGroup, aCallbacks, aLoadFlags);
if (NS_FAILED(rv)) return rv;
return channel->AsyncOpen(this, aContext);
mObserver = observer;
mLocation = location;
return NS_OK;
}
NS_METHOD
nsDownloader::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter) return NS_ERROR_NO_AGGREGATION;
nsDownloader* it = new nsDownloader();
if (it == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(it);
nsresult rv = it->QueryInterface(aIID, aResult);
NS_RELEASE(it);
return rv;
}
NS_IMPL_ISUPPORTS3(nsDownloader, nsIDownloader,
nsIRequestObserver, nsIStreamListener)
NS_IMETHODIMP
nsDownloader::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
nsresult rv;
nsCOMPtr<nsICachingChannel> caching = do_QueryInterface(request, &rv);
if (caching)
rv = caching->SetCacheAsFile(PR_TRUE);
// Returning failure from here will cancel the load
return rv;
nsresult rv = NS_ERROR_FAILURE;
if (!mLocation) {
nsCOMPtr<nsICachingChannel> caching = do_QueryInterface(request, &rv);
if (NS_SUCCEEDED(rv))
rv = caching->SetCacheAsFile(PR_TRUE);
}
if (NS_FAILED(rv)) {
// OK, we will need to stream the data to disk ourselves. Make
// sure mLocation exists.
if (!mLocation) {
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mLocation));
if (NS_FAILED(rv)) return rv;
char buf[13];
MakeRandomString(buf, 8);
memcpy(buf+8, ".tmp", 5);
rv = mLocation->AppendNative(nsDependentCString(buf, 12));
if (NS_FAILED(rv)) return rv;
rv = mLocation->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv)) return rv;
mLocationIsTemp = PR_TRUE;
}
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mSink), mLocation);
if (NS_FAILED(rv)) return rv;
// we could wrap this output stream with a buffered output stream,
// but it shouldn't be necessary since we will be writing large
// chunks given to us via OnDataAvailable.
}
return rv;
}
NS_IMETHODIMP
nsDownloader::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
nsresult aStatus)
nsDownloader::OnStopRequest(nsIRequest *request,
nsISupports *ctxt,
nsresult status)
{
nsCOMPtr<nsIFile> file;
if (NS_SUCCEEDED(aStatus))
{
nsCOMPtr<nsICachingChannel> caching = do_QueryInterface(request, &aStatus);
if (caching)
aStatus = caching->GetCacheFile(getter_AddRefs(file));
}
if (!mSink && NS_SUCCEEDED(status)) {
nsCOMPtr<nsICachingChannel> caching = do_QueryInterface(request, &status);
if (NS_SUCCEEDED(status)) {
status = caching->GetCacheFile(getter_AddRefs(mLocation));
if (NS_SUCCEEDED(status)) {
NS_ASSERTION(mLocation, "success without a cache file");
// ok, then we need to hold a reference to the cache token in
// order to ensure that the cache file remains valid until we
// get destroyed.
caching->GetCacheToken(getter_AddRefs(mCacheToken));
}
}
}
return mObserver->OnDownloadComplete(this, mContext, aStatus, file);
mObserver->OnDownloadComplete(this, status, mLocation);
mObserver = nsnull;
return NS_OK;
}
NS_METHOD
@ -152,17 +167,19 @@ nsDownloader::ConsumeData(nsIInputStream* in,
PRUint32 count,
PRUint32 *writeCount)
{
*writeCount = count;
return NS_OK;
nsDownloader *self = (nsDownloader *) closure;
if (self->mSink)
return self->mSink->Write(fromRawSegment, count, writeCount);
*writeCount = count;
return NS_OK;
}
NS_IMETHODIMP
nsDownloader::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
nsIInputStream *inStr,
PRUint32 sourceOffset, PRUint32 count)
nsIInputStream *inStr,
PRUint32 sourceOffset, PRUint32 count)
{
// This function simply disposes of the data as it's read in.
// We assume it's already been cached and that's what we're interested in.
PRUint32 lenRead;
return inStr->ReadSegments(nsDownloader::ConsumeData, nsnull, count, &lenRead);
PRUint32 n;
return inStr->ReadSegments(ConsumeData, this, count, &n);
}

View File

@ -1,37 +1,37 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
@ -39,36 +39,35 @@
#define nsDownloader_h__
#include "nsIDownloader.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIFile.h"
#include "nsCOMPtr.h"
#include "nsString.h"
class nsDownloader : public nsIDownloader,
public nsIStreamListener
class nsDownloader : public nsIDownloader
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOWNLOADER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_ISUPPORTS
NS_DECL_NSIDOWNLOADER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
nsDownloader() { } ;
virtual ~nsDownloader() {};
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
nsDownloader() : mLocationIsTemp(PR_FALSE) {}
protected:
static NS_METHOD ConsumeData(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount);
virtual ~nsDownloader();
nsCOMPtr<nsIDownloadObserver> mObserver;
nsCOMPtr<nsISupports> mContext; // the observer's context
static NS_METHOD ConsumeData(nsIInputStream *in,
void *closure,
const char *fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount);
nsCOMPtr<nsIDownloadObserver> mObserver;
nsCOMPtr<nsIFile> mLocation;
nsCOMPtr<nsIOutputStream> mSink;
nsCOMPtr<nsISupports> mCacheToken;
PRBool mLocationIsTemp;
};
#endif // nsDownloader_h__

View File

@ -51,7 +51,6 @@
#include "nsLoadGroup.h"
#include "nsStreamLoader.h"
#include "nsUnicharStreamLoader.h"
#include "nsDownloader.h"
#include "nsAsyncStreamListener.h"
#include "nsFileStreams.h"
#include "nsBufferedStreams.h"
@ -95,6 +94,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsInputStreamPump)
#include "nsInputStreamChannel.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsInputStreamChannel)
#include "nsDownloader.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloader)
///////////////////////////////////////////////////////////////////////////////
#include "nsStreamConverterService.h"
@ -606,7 +608,7 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
{ NS_DOWNLOADER_CLASSNAME,
NS_DOWNLOADER_CID,
NS_DOWNLOADER_CONTRACTID,
nsDownloader::Create },
nsDownloaderConstructor },
{ NS_REQUESTOBSERVERPROXY_CLASSNAME,
NS_REQUESTOBSERVERPROXY_CID,
NS_REQUESTOBSERVERPROXY_CONTRACTID,

View File

@ -29,6 +29,7 @@
static NS_DEFINE_CID(kScriptSecurityManagerCID, NS_SCRIPTSECURITYMANAGER_CID);
static NS_DEFINE_CID(kInputStreamChannelCID, NS_INPUTSTREAMCHANNEL_CID);
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
//-----------------------------------------------------------------------------
@ -63,7 +64,12 @@ public:
{
NS_ASSERTION(mJarFile, "no jar file");
}
virtual ~nsJARInputThunk() {}
virtual ~nsJARInputThunk()
{
if (!mJarCache && mJarReader)
mJarReader->Close();
}
void GetJarReader(nsIZipReader **result)
{
@ -96,8 +102,18 @@ nsJARInputThunk::EnsureJarStream()
return NS_OK;
nsresult rv;
rv = mJarCache->GetZip(mJarFile, getter_AddRefs(mJarReader));
if (mJarCache)
rv = mJarCache->GetZip(mJarFile, getter_AddRefs(mJarReader));
else {
// create an uncached jar reader
mJarReader = do_CreateInstance(kZipReaderCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = mJarReader->Init(mJarFile);
if (NS_FAILED(rv)) return rv;
rv = mJarReader->Open();
}
if (NS_FAILED(rv)) return rv;
rv = mJarReader->GetInputStream(mJarEntry.get(),
@ -205,7 +221,7 @@ nsJARChannel::Init(nsIURI *uri)
}
nsresult
nsJARChannel::CreateJarInput()
nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache)
{
// important to pass a clone of the file since the nsIFile impl is not
// necessarily MT-safe
@ -213,7 +229,7 @@ nsJARChannel::CreateJarInput()
nsresult rv = mJarFile->Clone(getter_AddRefs(clonedFile));
if (NS_FAILED(rv)) return rv;
mJarInput = new nsJARInputThunk(clonedFile, mJarEntry, gJarHandler->JarCache());
mJarInput = new nsJARInputThunk(clonedFile, mJarEntry, jarCache);
if (!mJarInput)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mJarInput);
@ -242,7 +258,7 @@ nsJARChannel::EnsureJarInput(PRBool blocking)
}
if (mJarFile) {
rv = CreateJarInput();
rv = CreateJarInput(gJarHandler->JarCache());
}
else if (blocking) {
NS_NOTREACHED("need sync downloader");
@ -250,9 +266,11 @@ nsJARChannel::EnsureJarInput(PRBool blocking)
}
else {
// kick off an async download of the base URI...
rv = NS_NewDownloader(getter_AddRefs(mDownloader),
mJarBaseURI, this, nsnull, PR_FALSE,
mLoadGroup, mCallbacks, mLoadFlags);
rv = NS_NewDownloader(getter_AddRefs(mDownloader), this);
if (NS_SUCCEEDED(rv))
rv = NS_OpenURI(mDownloader, nsnull, mJarBaseURI, nsnull,
mLoadGroup, mCallbacks,
mLoadFlags & ~LOAD_DOCUMENT_URI);
}
return rv;
@ -606,14 +624,13 @@ nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
NS_IMETHODIMP
nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
nsISupports *closure,
nsresult status,
nsIFile *file)
nsresult status,
nsIFile *file)
{
if (NS_SUCCEEDED(status)) {
mJarFile = file;
nsresult rv = CreateJarInput();
nsresult rv = CreateJarInput(nsnull);
if (NS_SUCCEEDED(rv)) {
// create input stream pump
rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput);
@ -628,7 +645,6 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
OnStopRequest(nsnull, nsnull, status);
}
mDownloader = 0;
return NS_OK;
}
@ -665,6 +681,7 @@ nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
mPump = 0;
NS_IF_RELEASE(mJarInput);
mIsPending = PR_FALSE;
mDownloader = 0; // this may delete the underlying jar file
return NS_OK;
}

View File

@ -44,6 +44,7 @@
#include "nsIInterfaceRequestor.h"
#include "nsIProgressEventSink.h"
#include "nsIStreamListener.h"
#include "nsIZipReader.h"
#include "nsIDownloader.h"
#include "nsILoadGroup.h"
#include "nsIFile.h"
@ -75,7 +76,7 @@ public:
nsresult Init(nsIURI *uri);
private:
nsresult CreateJarInput();
nsresult CreateJarInput(nsIZipReaderCache *);
nsresult EnsureJarInput(PRBool blocking);
#if defined(PR_LOGGING)
@ -98,8 +99,8 @@ private:
PRBool mIsPending;
nsJARInputThunk *mJarInput;
nsCOMPtr<nsIStreamListener> mDownloader;
nsCOMPtr<nsIInputStreamPump> mPump;
nsCOMPtr<nsIDownloader> mDownloader;
nsCOMPtr<nsIFile> mJarFile;
nsCOMPtr<nsIURI> mJarBaseURI;
nsCString mJarEntry;