diff --git a/mozilla/content/html/document/public/nsIWyciwygChannel.idl b/mozilla/content/html/document/public/nsIWyciwygChannel.idl index 71069b58115..c879483b124 100644 --- a/mozilla/content/html/document/public/nsIWyciwygChannel.idl +++ b/mozilla/content/html/document/public/nsIWyciwygChannel.idl @@ -56,5 +56,5 @@ interface nsIWyciwygChannel : nsIChannel /** * Close the cache entry; subsequent writes have undefined behavior. */ - void closeCacheEntry(); + void closeCacheEntry(in nsresult reason); }; diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp index b232927cbf8..a01267dabdf 100644 --- a/mozilla/content/html/document/src/nsHTMLDocument.cpp +++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp @@ -4029,7 +4029,7 @@ nsHTMLDocument::RemoveWyciwygChannel(void) // note there can be a write request without a load group if // this is a synchronously constructed about:blank document if (loadGroup && mWyciwygChannel) { - mWyciwygChannel->CloseCacheEntry(); + mWyciwygChannel->CloseCacheEntry(NS_OK); rv = loadGroup->RemoveRequest(mWyciwygChannel, nsnull, NS_OK); if (NS_FAILED(rv)) return rv; } diff --git a/mozilla/content/html/document/src/nsWyciwygChannel.cpp b/mozilla/content/html/document/src/nsWyciwygChannel.cpp index a4b643e8859..0c10571d5d9 100644 --- a/mozilla/content/html/document/src/nsWyciwygChannel.cpp +++ b/mozilla/content/html/document/src/nsWyciwygChannel.cpp @@ -32,12 +32,14 @@ PRLogModuleInfo * gWyciwygLog = nsnull; #define wyciwyg_TYPE "text/html" +#define LOG(args) PR_LOG(gWyciwygLog, 4, args) // nsWyciwygChannel methods nsWyciwygChannel::nsWyciwygChannel() - : mStatus(NS_OK), - mLoadFlags(LOAD_NORMAL), - mIsPending(PR_FALSE) + : mContentLength(-1) + , mLoadFlags(LOAD_NORMAL) + , mStatus(NS_OK) + , mIsPending(PR_FALSE) { } @@ -45,47 +47,22 @@ nsWyciwygChannel::~nsWyciwygChannel() { } -NS_IMPL_THREADSAFE_ISUPPORTS8(nsWyciwygChannel, nsIChannel, nsIRequest, - nsIStreamListener, nsICacheListener, - nsIInterfaceRequestor, nsIWyciwygChannel, - nsIRequestObserver, nsIProgressEventSink) +NS_IMPL_ISUPPORTS6(nsWyciwygChannel, + nsIChannel, + nsIRequest, + nsIStreamListener, + nsIRequestObserver, + nsICacheListener, + nsIWyciwygChannel) nsresult nsWyciwygChannel::Init(nsIURI* uri) { - if (!uri) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(uri); mURI = uri; return NS_OK; } -//----------------------------------------------------------------------------- -// nsHttpChannel::nsIInterfaceRequestor -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsWyciwygChannel::GetInterface(const nsIID &aIID, void **aResult) -{ - - if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) { - // - // we return ourselves as the progress event sink so we can intercept - // notifications and set the correct request and context parameters. - // but, if we don't have a progress sink to forward those messages - // to, then there's no point in handing out a reference to ourselves. - // - if (!mProgressSink) - return NS_ERROR_NO_INTERFACE; - - return QueryInterface(aIID, aResult); - } - - if (mCallbacks) - return mCallbacks->GetInterface(aIID, aResult); - - return NS_ERROR_NO_INTERFACE; -} - /////////////////////////////////////////////////////////////////////////////// // nsIRequest methods: /////////////////////////////////////////////////////////////////////////////// @@ -106,39 +83,38 @@ nsWyciwygChannel::IsPending(PRBool *aIsPending) NS_IMETHODIMP nsWyciwygChannel::GetStatus(nsresult *aStatus) { - *aStatus = mStatus; + if (NS_SUCCEEDED(mStatus) && mPump) + mPump->GetStatus(aStatus); + else + *aStatus = mStatus; return NS_OK; } NS_IMETHODIMP -nsWyciwygChannel::Cancel(nsresult aStatus) +nsWyciwygChannel::Cancel(nsresult status) { - LOG(("nsWyciwygChannel::Cancel [this=%x status=%x]\n", this, aStatus)); - NS_ASSERTION(NS_FAILED(aStatus), "shouldn't cancel with a success code"); - - mStatus = aStatus; - if (mCacheReadRequest) - mCacheReadRequest->Cancel(aStatus); - // Clear out all cache handles. - CloseCacheEntry(); + mStatus = status; + if (mPump) + mPump->Cancel(status); + // else we're waiting for OnCacheEntryAvailable return NS_OK; } NS_IMETHODIMP -nsWyciwygChannel::Suspend(void) +nsWyciwygChannel::Suspend() { - LOG(("nsWyciwygChannel::Suspend [this=%x]\n", this)); - if (mCacheReadRequest) - return mCacheReadRequest->Suspend(); + if (mPump) + mPump->Suspend(); + // XXX else, we'll ignore this ... and that's probably bad! return NS_OK; } NS_IMETHODIMP -nsWyciwygChannel::Resume(void) +nsWyciwygChannel::Resume() { - LOG(("nsWyciwygChannel::Resume [this=%x]\n", this)); - if (mCacheReadRequest) - return mCacheReadRequest->Resume(); + if (mPump) + mPump->Resume(); + // XXX else, we'll ignore this ... and that's probably bad! return NS_OK; } @@ -176,6 +152,7 @@ nsWyciwygChannel::GetLoadFlags(PRUint32 * aLoadFlags) //////////////////////////////////////////////////////////////////////////////// // nsIChannel methods: /////////////////////////////////////////////////////////////////////////////// + NS_IMETHODIMP nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI) { @@ -205,36 +182,24 @@ nsWyciwygChannel::GetURI(nsIURI* *aURI) } NS_IMETHODIMP -nsWyciwygChannel::GetOwner(nsISupports* *aOwner) +nsWyciwygChannel::GetOwner(nsISupports **aOwner) { nsresult rv = NS_OK; + if (!mOwner) { // Create codebase principal with URI of original document, not our URI - NS_ASSERTION(mOriginalURI, - "nsWyciwygChannel::GetOwner without an owner or an original URI!"); - if (mOriginalURI) { - nsIPrincipal* pIPrincipal = nsnull; - nsCOMPtr secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); - if (secMan) { - rv = secMan->GetCodebasePrincipal(mOriginalURI, &pIPrincipal); - if (NS_SUCCEEDED(rv)) { - mOwner = pIPrincipal; - NS_RELEASE(pIPrincipal); - } - } - } else { - // Uh oh, must set originalURI before we can return an owner! - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(mOriginalURI, NS_ERROR_FAILURE); // without an owner or an original URI! + + nsCOMPtr principal; + nsCOMPtr secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); + if (secMan) { + rv = secMan->GetCodebasePrincipal(mOriginalURI, getter_AddRefs(principal)); + if (NS_SUCCEEDED(rv)) + mOwner = principal; } } - NS_ASSERTION(mOriginalURI, - "nsWyciwygChannel::GetOwner unable to get owner!"); - if (mOwner) { - *aOwner = mOwner.get(); - NS_IF_ADDREF(*aOwner); - } else { - *aOwner = nsnull; - } + + NS_IF_ADDREF(*aOwner = mOwner); return rv; } @@ -312,30 +277,39 @@ nsWyciwygChannel::Open(nsIInputStream ** aReturn) } NS_IMETHODIMP -nsWyciwygChannel::AsyncOpen(nsIStreamListener * aListener, nsISupports * aContext) +nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) { LOG(("nsWyciwygChannel::AsyncOpen [this=%x]\n", this)); - NS_ENSURE_ARG_POINTER(aListener); NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + NS_ENSURE_ARG_POINTER(listener); - //XXX Should I worry about Port safety? + nsCAutoString spec; + mURI->GetSpec(spec); + + // open a cache entry for this channel... + PRBool delayed = PR_FALSE; + nsresult rv = OpenCacheEntry(spec.get(), nsICache::ACCESS_READ, &delayed); + if (NS_FAILED(rv)) { + LOG(("nsWyciwygChannel::OpenCacheEntry failed [rv=%x]\n", rv)); + return rv; + } + + if (!delayed) { + rv = ReadFromCache(); + if (NS_FAILED(rv)) { + LOG(("nsWyciwygChannel::ReadFromCache failed [rv=%x]\n", rv)); + return rv; + } + } mIsPending = PR_TRUE; - mListener = aListener; - mListenerContext = aContext; + mListener = listener; + mListenerContext = ctx; - // add ourselves to the load group. From this point forward, we'll report - // all failures asynchronously. if (mLoadGroup) mLoadGroup->AddRequest(this, nsnull); - nsresult rv = Connect(PR_TRUE); - if (NS_FAILED(rv)) { - LOG(("nsWyciwygChannel::AsyncOpen Connect failed [rv=%x]\n", rv)); - CloseCacheEntry(); - AsyncAbort(rv); - } return NS_OK; } @@ -357,12 +331,8 @@ nsWyciwygChannel::WriteToCacheEntry(const nsACString &aScript) } if (!mCacheOutputStream) { - //Get the transport from cache - rv = mCacheEntry->GetTransport(getter_AddRefs(mCacheTransport)); - if (NS_FAILED(rv)) return rv; - - // Get the outputstream from the transport. - rv = mCacheTransport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(mCacheOutputStream)); + // Get the outputstream from the cache entry. + rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream)); if (NS_FAILED(rv)) return rv; } @@ -372,20 +342,19 @@ nsWyciwygChannel::WriteToCacheEntry(const nsACString &aScript) NS_IMETHODIMP -nsWyciwygChannel::CloseCacheEntry() +nsWyciwygChannel::CloseCacheEntry(nsresult reason) { - nsresult rv = NS_OK; if (mCacheEntry) { LOG(("nsWyciwygChannel::CloseCacheEntry [this=%x ]", this)); - // make sure the cache transport isn't holding a reference back to us - if (mCacheTransport) - mCacheTransport->SetNotificationCallbacks(nsnull, 0); - mCacheReadRequest = 0; - mCacheTransport = 0; mCacheOutputStream = 0; + mCacheInputStream = 0; + + if (NS_FAILED(reason)) + mCacheEntry->Doom(); + mCacheEntry = 0; } - return rv; + return NS_OK; } ////////////////////////////////////////////////////////////////////////////// @@ -403,26 +372,39 @@ nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor * aCacheEntry, n return NS_OK; // otherwise, we have to handle this event. - if (NS_SUCCEEDED(aStatus)) { - mCacheEntry = aCacheEntry; - } + if (NS_SUCCEEDED(aStatus)) + mCacheEntry = aCacheEntry; + else if (NS_SUCCEEDED(mStatus)) + mStatus = aStatus; nsresult rv; - if (NS_FAILED(mStatus)) { LOG(("channel was canceled [this=%x status=%x]\n", this, mStatus)); rv = mStatus; } - else // advance to the next state... - rv = Connect(PR_FALSE); + else { // advance to the next state... + rv = ReadFromCache(); + } // a failure from Connect means that we have to abort the channel. if (NS_FAILED(rv)) { - CloseCacheEntry(); - AsyncAbort(rv); + CloseCacheEntry(rv); + + if (mListener) { + mListener->OnStartRequest(this, mListenerContext); + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; + } + + mIsPending = PR_FALSE; + + // Remove ourselves from the load group. + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, mStatus); } - return rv; + return NS_OK; } //----------------------------------------------------------------------------- @@ -430,24 +412,21 @@ nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor * aCacheEntry, n //----------------------------------------------------------------------------- NS_IMETHODIMP -nsWyciwygChannel::OnDataAvailable(nsIRequest *aRequest, nsISupports *aCtxt, - nsIInputStream *aInput, - PRUint32 aOffset, PRUint32 aCount) +nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx, + nsIInputStream *input, + PRUint32 offset, PRUint32 count) { LOG(("nsWyciwygChannel::OnDataAvailable [this=%x request=%x offset=%u count=%u]\n", - this, aRequest, aOffset, aCount)); + this, request, offset, count)); - // if the request is for something we no longer reference, then simply - // drop this event. - if (aRequest != mCacheReadRequest) { - NS_WARNING("nsWyciwygChannel::OnDataAvailable got stale request... why wasn't it cancelled?"); - return NS_BASE_STREAM_CLOSED; - } + nsresult rv; + + rv = mListener->OnDataAvailable(this, mListenerContext, input, offset, count); - if (mListener) - return mListener->OnDataAvailable((nsIRequest *)this, mListenerContext, aInput, aOffset, aCount); + if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND)) + mProgressSink->OnProgress(this, nsnull, offset + count, mContentLength); - return NS_BASE_STREAM_CLOSED; + return rv; // let the pump cancel on failure } ////////////////////////////////////////////////////////////////////////////// @@ -455,70 +434,41 @@ nsWyciwygChannel::OnDataAvailable(nsIRequest *aRequest, nsISupports *aCtxt, ////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP -nsWyciwygChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aCtxt) +nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx) { - nsresult rv = NS_ERROR_FAILURE; LOG(("nsWyciwygChannel::OnStartRequest [this=%x request=%x\n", - this, aRequest)); + this, request)); - // capture the request's status, so our consumers will know ASAP of any - // connection failures, etc. - aRequest->GetStatus(&mStatus); - if (mListener) - rv = mListener->OnStartRequest(this, mListenerContext); - return rv; + return mListener->OnStartRequest(this, mListenerContext); } NS_IMETHODIMP -nsWyciwygChannel::OnStopRequest(nsIRequest *aRequest, nsISupports *aCtxt, nsresult aStatus) +nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status) { LOG(("nsWyciwygChannel::OnStopRequest [this=%x request=%x status=%d\n", - this, aRequest, (PRUint32)aStatus)); - - mIsPending = PR_FALSE; - mStatus = aStatus; - CloseCacheEntry(); - if (mListener) { - mListener->OnStopRequest(this, mListenerContext, aStatus); - mListener = 0; - mListenerContext = 0; - } - + this, request, status)); + + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; + if (mLoadGroup) - mLoadGroup->RemoveRequest(this, nsnull, aStatus); + mLoadGroup->RemoveRequest(this, nsnull, mStatus); + CloseCacheEntry(mStatus); + mPump = 0; + mIsPending = PR_FALSE; return NS_OK; } -////////////////////////////////////////////////////////////////////////////// -// nsIProgressEventSink -////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsWyciwygChannel::OnStatus(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatus, - const PRUnichar *aStatusText) -{ - if (mProgressSink) - mProgressSink->OnStatus(this, mListenerContext, aStatus, aStatusText); - - return NS_OK; -} - -NS_IMETHODIMP -nsWyciwygChannel::OnProgress(nsIRequest *aRequest, nsISupports *aContext, - PRUint32 aProgress, PRUint32 aProgressMax) -{ - if (mProgressSink) - mProgressSink->OnProgress(this, mListenerContext, aProgress, aProgressMax); - - return NS_OK; -} - - ////////////////////////////////////////////////////////////////////////////// // Helper functions ////////////////////////////////////////////////////////////////////////////// + nsresult nsWyciwygChannel::OpenCacheEntry(const char * aCacheKey, nsCacheAccessMode aAccessMode, PRBool * aDelayFlag ) { @@ -567,77 +517,25 @@ nsWyciwygChannel::OpenCacheEntry(const char * aCacheKey, nsCacheAccessMode aAcce return rv; } -nsresult -nsWyciwygChannel::Connect(PRBool aFirstTime) -{ - nsresult rv = NS_ERROR_FAILURE; - - LOG(("nsWyciwygChannel::Connect [this=%x]\n", this)); - - // true when called from AsyncOpen - if (aFirstTime) { - PRBool delayed = PR_FALSE; - - nsCAutoString spec; - mURI->GetSpec(spec); - // open a cache entry for this channel... - rv = OpenCacheEntry(spec.get(), nsICache::ACCESS_READ, &delayed); - - if (NS_FAILED(rv)) { - LOG(("nsWyciwygChannel::Connect OpenCacheEntry failed [rv=%x]\n", rv)); - return rv; - } - - if (NS_SUCCEEDED(rv) && delayed) - return NS_OK; - } - - // Read the script from cache. - if (mCacheEntry) - return ReadFromCache(); - return rv; -} - nsresult nsWyciwygChannel::ReadFromCache() { - nsresult rv; - - NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE); LOG(("nsWyciwygChannel::ReadFromCache [this=%x] ", this)); - // Get a transport to the cached data... - rv = mCacheEntry->GetTransport(getter_AddRefs(mCacheTransport)); - if (NS_FAILED(rv) || !mCacheTransport) - return rv; + NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE); + nsresult rv; - // Hookup the notification callbacks interface to the new transport... - mCacheTransport->SetNotificationCallbacks(this, - ((mLoadFlags & nsIRequest::LOAD_BACKGROUND) - ? nsITransport::DONT_REPORT_PROGRESS - : 0)); + // Get a transport to the cached data... + rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream)); + if (NS_FAILED(rv)) + return rv; + NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED); + + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream, -1); + if (NS_FAILED(rv)) return rv; // Pump the cache data downstream - return mCacheTransport->AsyncRead(this, nsnull, - 0, PRUint32(-1), 0, - getter_AddRefs(mCacheReadRequest)); + return mPump->AsyncRead(this, nsnull); } - - - -// called when Connect fails -nsresult -nsWyciwygChannel::AsyncAbort(nsresult aStatus) -{ - LOG(("nsWyciwygChannel::AsyncAbort [this=%x status=%x]\n", this, aStatus)); - - mStatus = aStatus; - mIsPending = PR_FALSE; - - // Remove ourselves from the load group. - if (mLoadGroup) - mLoadGroup->RemoveRequest((nsIRequest *)this, nsnull, aStatus); - - return NS_OK; -} +// vim: ts=2 sw=2 diff --git a/mozilla/content/html/document/src/nsWyciwygChannel.h b/mozilla/content/html/document/src/nsWyciwygChannel.h index 4713940f9a3..ea61ecad79f 100644 --- a/mozilla/content/html/document/src/nsWyciwygChannel.h +++ b/mozilla/content/html/document/src/nsWyciwygChannel.h @@ -23,76 +23,73 @@ #ifndef nsWyciwygChannel_h___ #define nsWyciwygChannel_h___ -#include "nsIWyciwygChannel.h" -#include "nsString.h" -#include "nsILoadGroup.h" -#include "nsIInputStream.h" -#include "nsIInterfaceRequestor.h" -#include "nsCOMPtr.h" -#include "nsXPIDLString.h" -#include "nsIChannel.h" -#include "nsIURI.h" #include "nsWyciwygProtocolHandler.h" +#include "nsXPIDLString.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "prlog.h" + +#include "nsIWyciwygChannel.h" +#include "nsILoadGroup.h" +#include "nsIOutputStream.h" +#include "nsIInputStream.h" +#include "nsIInputStreamPump.h" +#include "nsIInterfaceRequestor.h" +#include "nsIProgressEventSink.h" #include "nsIStreamListener.h" #include "nsICacheListener.h" -#include "nsITransport.h" #include "nsICacheEntryDescriptor.h" -#include "nsIOutputStream.h" -#include "nsIProgressEventSink.h" -#include "prlog.h" +#include "nsIURI.h" extern PRLogModuleInfo * gWyciwygLog; -#define LOG(args) PR_LOG(gWyciwygLog, 4, args) +//----------------------------------------------------------------------------- -class nsWyciwygChannel: public nsIWyciwygChannel, +class nsWyciwygChannel: public nsIWyciwygChannel, public nsIStreamListener, - public nsIInterfaceRequestor, - public nsICacheListener, - public nsIProgressEventSink + public nsICacheListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL NS_DECL_NSIWYCIWYGCHANNEL + NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSICACHELISTENER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSIPROGRESSEVENTSINK // nsWyciwygChannel methods: nsWyciwygChannel(); virtual ~nsWyciwygChannel(); - nsresult Init(nsIURI* uri); + nsresult Init(nsIURI *uri); protected: - nsresult AsyncAbort(nsresult rv); - nsresult Connect(PRBool firstTime); nsresult ReadFromCache(); nsresult OpenCacheEntry(const char * aCacheKey, nsCacheAccessMode aWriteAccess, PRBool * aDelayFlag = nsnull); - nsCOMPtr mCallbacks; - nsCOMPtr mLoadGroup; + nsCOMPtr mURI; nsCOMPtr mOriginalURI; nsCOMPtr mOwner; + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; + nsCOMPtr mLoadGroup; nsCOMPtr mListener; nsCOMPtr mListenerContext; - nsCOMPtr mURI; - nsCOMPtr mProgressSink; + nsCString mContentType; + nsCString mContentCharset; + PRInt32 mContentLength; + PRUint32 mLoadFlags; + nsresult mStatus; + PRBool mIsPending; + + // reuse as much of this channel implementation as we can + nsCOMPtr mPump; // Cache related stuff - nsCOMPtr mCacheTransport; - nsCOMPtr mCacheReadRequest; nsCOMPtr mCacheEntry; nsCOMPtr mCacheOutputStream; - - // flags - PRUint32 mStatus; - PRUint32 mLoadFlags; - PRPackedBool mIsPending; + nsCOMPtr mCacheInputStream; }; #endif /* nsWyciwygChannel_h___ */ diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index f2943ba7b37..1f93e3e03ac 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -729,13 +729,12 @@ nsDocShell::LoadURI(nsIURI * aURI, } NS_IMETHODIMP -nsDocShell::LoadStream(nsIInputStream * aStream, nsIURI * aURI, - const char *aContentType, PRInt32 aContentLen, +nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI, + const nsACString &aContentType, + const nsACString &aContentCharset, nsIDocShellLoadInfo * aLoadInfo) { NS_ENSURE_ARG(aStream); - NS_ENSURE_ARG(aContentType); - NS_ENSURE_ARG(aContentLen); // if the caller doesn't pass in a URI we need to create a dummy URI. necko // currently requires a URI in various places during the load. Some consumers @@ -770,9 +769,8 @@ nsDocShell::LoadStream(nsIInputStream * aStream, nsIURI * aURI, nsCOMPtr channel; NS_ENSURE_SUCCESS(NS_NewInputStreamChannel (getter_AddRefs(channel), uri, aStream, - nsDependentCString(aContentType), - NS_LITERAL_CSTRING(""), - aContentLen), NS_ERROR_FAILURE); + aContentType, aContentCharset), + NS_ERROR_FAILURE); nsCOMPtr uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); diff --git a/mozilla/docshell/base/nsIDocShell.idl b/mozilla/docshell/base/nsIDocShell.idl index 619d514bea1..897c8a0da9a 100644 --- a/mozilla/docshell/base/nsIDocShell.idl +++ b/mozilla/docshell/base/nsIDocShell.idl @@ -77,23 +77,23 @@ interface nsIDocShell : nsISupports * here however, the URL dispatched will go through its normal process of * content loading. * - * @param aStream - The input stream that provides access to the data - * to be loaded. - * @param aURI - The URI representing the stream, or null. - * @param aContentType - The type (MIME) of data being loaded. - * @param aContentLen - The length (in bytes) of the stream. If you don't - * know the length of the stream this can be -1. - * @param aLoadInfo - This is the extended load info for this load. This - * most often will be null, but if you need to do - * additional setup for this load you can get a - * loadInfo object by calling createLoadInfo. Once - * you have this object you can set the needed - * properties on it and then pass it to loadStream. + * @param aStream - The input stream that provides access to the data + * to be loaded. This must be a blocking, threadsafe + * stream implementation. + * @param aURI - The URI representing the stream, or null. + * @param aContentType - The type (MIME) of data being loaded (empty if unknown). + * @param aContentCharset - The charset of the data being loaded (empty if unknown). + * @param aLoadInfo - This is the extended load info for this load. This + * most often will be null, but if you need to do + * additional setup for this load you can get a + * loadInfo object by calling createLoadInfo. Once + * you have this object you can set the needed + * properties on it and then pass it to loadStream. */ [noscript]void loadStream(in nsIInputStream aStream, in nsIURI aURI, - in string aContentType, - in long aContentLen, + in ACString aContentType, + in ACString aContentCharset, in nsIDocShellLoadInfo aLoadInfo); /** diff --git a/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp b/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp index 4531656efd0..a9db5b93537 100644 --- a/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp +++ b/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp @@ -57,7 +57,7 @@ #include "nsICodebasePrincipal.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIByteArrayInputStream.h" +#include "nsIStringStream.h" #include "nsIWindowMediator.h" #include "nsIDOMWindowInternal.h" #include "nsIDOMDocument.h" @@ -72,13 +72,13 @@ static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID); -class nsJSThunk : public nsIStreamIO +class nsJSThunk : public nsIInputStream { public: nsJSThunk(); NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMIO + NS_FORWARD_SAFE_NSIINPUTSTREAM(mInnerStream) nsresult Init(nsIURI* uri); nsresult EvaluateScript(nsIChannel *aChannel); @@ -88,24 +88,21 @@ protected: virtual ~nsJSThunk(); nsCOMPtr mURI; - char* mResult; - PRUint32 mLength; + nsCOMPtr mInnerStream; }; // // nsISupports implementation... // -NS_IMPL_THREADSAFE_ISUPPORTS1(nsJSThunk, nsIStreamIO); +NS_IMPL_THREADSAFE_ISUPPORTS1(nsJSThunk, nsIInputStream); nsJSThunk::nsJSThunk() - : mResult(nsnull), mLength(0) { } nsJSThunk::~nsJSThunk() { - (void)Close(NS_BASE_STREAM_CLOSED); } nsresult nsJSThunk::Init(nsIURI* uri) @@ -289,9 +286,9 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel) rv = NS_ERROR_DOM_RETVAL_UNDEFINED; } else { + // NS_NewStringInputStream calls ToNewCString // XXXbe this should not decimate! pass back UCS-2 to necko - mResult = ToNewCString(result); - mLength = result.Length(); + rv = NS_NewStringInputStream(getter_AddRefs(mInnerStream), result); } return rv; } @@ -325,87 +322,6 @@ nsresult nsJSThunk::BringUpConsole(nsIDOMWindow *aDomWindow) return rv; } -// -// nsIStreamIO implementation... -// -NS_IMETHODIMP -nsJSThunk::Open() -{ - return NS_OK; -} - -NS_IMETHODIMP -nsJSThunk::GetContentType(nsACString &aContentType) -{ - // - // At this point the script has already been evaluated... - // The resulting string (if any) is stored in mResult. - // - // If the resultant script evaluation actually does return a value, we - // treat it as html. - // - aContentType = NS_LITERAL_CSTRING("text/html"); - return NS_OK; -} - -NS_IMETHODIMP -nsJSThunk::GetContentCharset(nsACString &aContentCharset) -{ - aContentCharset.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -nsJSThunk::GetContentLength(PRInt32 *result) -{ - *result = mLength; - return NS_OK; -} - -NS_IMETHODIMP -nsJSThunk::Close(nsresult status) -{ - if (mResult) { - nsCRT::free(mResult); - mResult = nsnull; - } - mLength = 0; - return NS_OK; -} - -NS_IMETHODIMP -nsJSThunk::GetInputStream(nsIInputStream* *aInputStream) -{ - nsresult rv; - nsIByteArrayInputStream* str; - - rv = NS_NewByteArrayInputStream(&str, mResult, mLength); - if (NS_SUCCEEDED(rv)) { - mResult = nsnull; // XXX Whackiness. The input stream takes ownership - *aInputStream = str; - } - else { - *aInputStream = nsnull; - } - return rv; -} - -NS_IMETHODIMP -nsJSThunk::GetOutputStream(nsIOutputStream* *aOutputStream) -{ - // should never be called - NS_NOTREACHED("nsJSThunk::GetOutputStream"); - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsJSThunk::GetName(nsACString &aName) -{ - return mURI->GetSpec(aName); -} - - - //////////////////////////////////////////////////////////////////////////////// class nsJSChannel : public nsIChannel @@ -454,17 +370,21 @@ nsresult nsJSChannel::Init(nsIURI *aURI) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(mIOThunk); - // Create a stock nsIStreamIOChannel... + // Create a stock input stream channel... // Remember, until AsyncOpen is called, the script will not be evaluated // and the underlying Input Stream will not be created... - nsCOMPtr channel; + nsCOMPtr channel; - rv = NS_NewStreamIOChannel(getter_AddRefs(channel), aURI, mIOThunk); + // If the resultant script evaluation actually does return a value, we + // treat it as html. + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, mIOThunk, + NS_LITERAL_CSTRING("text/html"), + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; rv = mIOThunk->Init(aURI); if (NS_SUCCEEDED(rv)) { - mStreamChannel = do_QueryInterface(channel); + mStreamChannel = channel; } return rv; diff --git a/mozilla/embedding/browser/gtk/src/EmbedStream.cpp b/mozilla/embedding/browser/gtk/src/EmbedStream.cpp index 7200e406de3..b53e91b37bb 100644 --- a/mozilla/embedding/browser/gtk/src/EmbedStream.cpp +++ b/mozilla/embedding/browser/gtk/src/EmbedStream.cpp @@ -117,8 +117,7 @@ EmbedStream::OpenStream(const char *aBaseURI, const char *aContentType) rv = NS_NewInputStreamChannel(getter_AddRefs(mChannel), uri, NS_STATIC_CAST(nsIInputStream *, this), nsDependentCString(aContentType), - NS_LITERAL_CSTRING(""), - 1024); /* len */ + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; diff --git a/mozilla/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp b/mozilla/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp index 28b1ad97189..880a86576bf 100644 --- a/mozilla/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp +++ b/mozilla/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp @@ -35,7 +35,6 @@ #include "nsNetUtil.h" #include "nsComponentManagerUtils.h" -#include "nsIFileTransportService.h" #include "nsIStorageStream.h" #include "nsIHttpChannel.h" #include "nsIEncodedChannel.h" @@ -85,7 +84,7 @@ #include "nsIDOMHTMLDocument.h" #include "ftpCore.h" -#include "nsISocketTransportService.h" +#include "nsISocketTransport.h" #include "nsIStringBundle.h" #include "nsWebBrowserPersist.h" @@ -900,7 +899,6 @@ NS_IMETHODIMP nsWebBrowserPersist::OnStatus( case NS_NET_STATUS_CONNECTED_TO: case NS_NET_STATUS_SENDING_TO: case NS_NET_STATUS_RECEIVING_FROM: - case NS_NET_STATUS_READ_FROM: break; default: diff --git a/mozilla/extensions/datetime/Makefile.in b/mozilla/extensions/datetime/Makefile.in index f72515d7380..18e9b04774b 100644 --- a/mozilla/extensions/datetime/Makefile.in +++ b/mozilla/extensions/datetime/Makefile.in @@ -51,6 +51,7 @@ MODULE_NAME = datetime REQUIRES = xpcom \ string \ necko \ + mimetype \ $(NULL) CPPSRCS = \ diff --git a/mozilla/extensions/datetime/nsDateTimeChannel.cpp b/mozilla/extensions/datetime/nsDateTimeChannel.cpp index c5b89a766c9..bc927138a43 100644 --- a/mozilla/extensions/datetime/nsDateTimeChannel.cpp +++ b/mozilla/extensions/datetime/nsDateTimeChannel.cpp @@ -1,122 +1,111 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * - * 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. + * 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 Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. + * The Initial Developer of the Original Code is Brian Ryner. + * Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner. + * All Rights Reserved. * - * Contributor(s): - * - * 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 - * 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 - * 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. - * - * ***** END LICENSE BLOCK ***** */ + * Contributor(s): + * Brian Ryner + */ -// datetime implementation +// DateTime implementation #include "nsDateTimeChannel.h" -#include "nsNetUtil.h" #include "nsIServiceManager.h" #include "nsILoadGroup.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsXPIDLString.h" #include "nsISocketTransportService.h" -#include "nsITransport.h" +#include "nsIStringStream.h" +#include "nsMimeTypes.h" +#include "nsIStreamConverterService.h" +#include "nsITXTToHTMLConv.h" #include "nsIProgressEventSink.h" +#include "nsEventQueueUtils.h" +#include "nsNetUtil.h" +#include "nsCRT.h" + +static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); +static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); // nsDateTimeChannel methods -nsDateTimeChannel::nsDateTimeChannel() { - mContentLength = -1; - mPort = -1; +nsDateTimeChannel::nsDateTimeChannel() + : mLoadFlags(LOAD_NORMAL) + , mStatus(NS_OK) + , mPort(-1) +{ } -nsDateTimeChannel::~nsDateTimeChannel() { +nsDateTimeChannel::~nsDateTimeChannel() +{ } NS_IMPL_ISUPPORTS4(nsDateTimeChannel, nsIChannel, - nsIRequest, + nsIRequest, nsIStreamListener, nsIRequestObserver) nsresult -nsDateTimeChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo) +nsDateTimeChannel::Init(nsIURI *uri, nsIProxyInfo *proxyInfo) { nsresult rv; NS_ASSERTION(uri, "no uri"); - mUrl = uri; + mURI = uri; mProxyInfo = proxyInfo; - rv = mUrl->GetPort(&mPort); + rv = mURI->GetPort(&mPort); if (NS_FAILED(rv) || mPort < 1) mPort = DATETIME_PORT; - rv = mUrl->GetPath(mHost); + rv = mURI->GetPath(mHost); if (NS_FAILED(rv)) return rv; - if (!*(const char *)mHost) return NS_ERROR_NOT_INITIALIZED; + if (mHost.IsEmpty()) + return NS_ERROR_MALFORMED_URI; + mContentType = NS_LITERAL_CSTRING(TEXT_HTML); // expected content-type return NS_OK; } -NS_METHOD -nsDateTimeChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) -{ - nsDateTimeChannel* dc = new nsDateTimeChannel(); - if (dc == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(dc); - nsresult rv = dc->QueryInterface(aIID, aResult); - NS_RELEASE(dc); - return rv; -} - //////////////////////////////////////////////////////////////////////////////// // nsIRequest methods: NS_IMETHODIMP nsDateTimeChannel::GetName(nsACString &result) { - return NS_ERROR_NOT_IMPLEMENTED; + return mURI->GetSpec(result); } NS_IMETHODIMP nsDateTimeChannel::IsPending(PRBool *result) { - NS_NOTREACHED("nsDateTimeChannel::IsPending"); - return NS_ERROR_NOT_IMPLEMENTED; + *result = (mPump != nsnull); + return NS_OK; } NS_IMETHODIMP nsDateTimeChannel::GetStatus(nsresult *status) { - *status = NS_OK; + if (NS_SUCCEEDED(mStatus) && mPump) + mPump->GetStatus(status); + else + *status = mStatus; return NS_OK; } @@ -124,22 +113,28 @@ NS_IMETHODIMP nsDateTimeChannel::Cancel(nsresult status) { NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); - NS_NOTREACHED("nsDateTimeChannel::Cancel"); - return NS_ERROR_NOT_IMPLEMENTED; + + mStatus = status; + if (mPump) + mPump->Cancel(status); + + return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -nsDateTimeChannel::Suspend(void) +nsDateTimeChannel::Suspend() { - NS_NOTREACHED("nsDateTimeChannel::Suspend"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mPump) + mPump->Suspend(); + return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -nsDateTimeChannel::Resume(void) +nsDateTimeChannel::Resume() { - NS_NOTREACHED("nsDateTimeChannel::Resume"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mPump) + mPump->Resume(); + return NS_ERROR_UNEXPECTED; } //////////////////////////////////////////////////////////////////////////////// @@ -148,7 +143,7 @@ nsDateTimeChannel::Resume(void) NS_IMETHODIMP nsDateTimeChannel::GetOriginalURI(nsIURI* *aURI) { - *aURI = mOriginalURI ? mOriginalURI : mUrl; + *aURI = mOriginalURI ? mOriginalURI : mURI; NS_ADDREF(*aURI); return NS_OK; } @@ -163,7 +158,7 @@ nsDateTimeChannel::SetOriginalURI(nsIURI* aURI) NS_IMETHODIMP nsDateTimeChannel::GetURI(nsIURI* *aURI) { - *aURI = mUrl; + *aURI = mURI; NS_IF_ADDREF(*aURI); return NS_OK; } @@ -171,58 +166,84 @@ nsDateTimeChannel::GetURI(nsIURI* *aURI) NS_IMETHODIMP nsDateTimeChannel::Open(nsIInputStream **_retval) { - nsresult rv = NS_OK; - rv = NS_CheckPortSafety(mPort, "datetime"); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr sts = - do_GetService("@mozilla.org/network/socket-transport-service;1", &rv); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr transport; - rv = sts->CreateTransport(mHost, - mPort, - mProxyInfo, - 32, - 32, - getter_AddRefs(transport)); - if (NS_FAILED(rv)) return rv; - - transport->SetNotificationCallbacks(mCallbacks, - (mLoadFlags & LOAD_BACKGROUND)); - - return transport->OpenInputStream(0, PRUint32(-1), 0, _retval); + NS_NOTREACHED("nsDateTimeChannel::Open"); + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDateTimeChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) { nsresult rv = NS_OK; + rv = NS_CheckPortSafety(mPort, "datetime"); - if (NS_FAILED(rv)) - return rv; + if (NS_FAILED(rv)) return rv; + nsCOMPtr eventQ; + rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) return rv; + + // + // create transport + // nsCOMPtr sts = - do_GetService("@mozilla.org/network/socket-transport-service;1", &rv); + do_GetService(kSocketTransportServiceCID, &rv); if (NS_FAILED(rv)) return rv; - nsCOMPtr transport; - rv = sts->CreateTransport(mHost, - mPort, - mProxyInfo, - 32, - 32, - getter_AddRefs(transport)); + rv = sts->CreateTransport(nsnull, 0, mHost, mPort, mProxyInfo, + getter_AddRefs(mTransport)); if (NS_FAILED(rv)) return rv; - transport->SetNotificationCallbacks(mCallbacks, - (mLoadFlags & LOAD_BACKGROUND)); + // not fatal if these fail + mTransport->SetSecurityCallbacks(mCallbacks); + mTransport->SetEventSink(this, eventQ); + + // + // create TXT to HTML stream converter + // + nsCOMPtr scs = + do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + NS_NAMED_LITERAL_STRING(fromStr, "text/plain"); + NS_NAMED_LITERAL_STRING(toStr, "text/html"); + + nsCOMPtr convListener; + rv = scs->AsyncConvertData(fromStr.get(), toStr.get(), this, nsnull, + getter_AddRefs(convListener)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr conv = do_QueryInterface(convListener); + if (conv) { + nsCAutoString userHost; + rv = mURI->GetPath(userHost); + + nsAutoString title; + title = NS_LITERAL_STRING("DateTime according to ") + + NS_ConvertUTF8toUCS2(mHost); + + conv->SetTitle(title.get()); + conv->PreFormatHTML(PR_TRUE); + } + + // + // open input stream, and create input stream pump... + // + nsCOMPtr sockIn; + rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(sockIn)); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), sockIn); + if (NS_FAILED(rv)) return rv; + + rv = mPump->AsyncRead(convListener, nsnull); + if (NS_FAILED(rv)) return rv; + + if (mLoadGroup) + mLoadGroup->AddRequest(this, nsnull); mListener = aListener; - - nsCOMPtr request; - return transport->AsyncRead(this, ctxt, 0, PRUint32(-1), 0, getter_AddRefs(request)); + mListenerContext = ctxt; + return NS_OK; } NS_IMETHODIMP @@ -239,49 +260,46 @@ nsDateTimeChannel::SetLoadFlags(PRUint32 aLoadFlags) return NS_OK; } -#define DATETIME_TYPE "text/plain" - NS_IMETHODIMP nsDateTimeChannel::GetContentType(nsACString &aContentType) { - aContentType = NS_LITERAL_CSTRING(DATETIME_TYPE); + aContentType = mContentType; return NS_OK; } NS_IMETHODIMP nsDateTimeChannel::SetContentType(const nsACString &aContentType) { - // It doesn't make sense to set the content-type on this type - // of channel... - return NS_ERROR_FAILURE; + mContentType = aContentType; + return NS_OK; } NS_IMETHODIMP nsDateTimeChannel::GetContentCharset(nsACString &aContentCharset) { - aContentCharset.Truncate(); + aContentCharset = mContentCharset; return NS_OK; } NS_IMETHODIMP nsDateTimeChannel::SetContentCharset(const nsACString &aContentCharset) { - NS_NOTREACHED("nsDateTimeChannel::SetContentCharset"); - return NS_ERROR_NOT_IMPLEMENTED; + mContentCharset = aContentCharset; + return NS_OK; } NS_IMETHODIMP nsDateTimeChannel::GetContentLength(PRInt32 *aContentLength) { - *aContentLength = mContentLength; + *aContentLength = -1; return NS_OK; } NS_IMETHODIMP nsDateTimeChannel::SetContentLength(PRInt32 aContentLength) { - NS_NOTREACHED("nsDateTimeChannel::SetContentLength"); - return NS_ERROR_NOT_IMPLEMENTED; + // silently ignore this... + return NS_OK; } NS_IMETHODIMP @@ -295,13 +313,7 @@ nsDateTimeChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) NS_IMETHODIMP nsDateTimeChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) { - if (mLoadGroup) // if we already had a load group remove ourselves... - (void)mLoadGroup->RemoveRequest(this, nsnull, NS_OK); - mLoadGroup = aLoadGroup; - if (mLoadGroup) { - return mLoadGroup->AddRequest(this, nsnull); - } return NS_OK; } @@ -332,40 +344,73 @@ NS_IMETHODIMP nsDateTimeChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) { mCallbacks = aNotificationCallbacks; + mProgressSink = do_GetInterface(mCallbacks); return NS_OK; } -NS_IMETHODIMP -nsDateTimeChannel::GetSecurityInfo(nsISupports **sec) +NS_IMETHODIMP +nsDateTimeChannel::GetSecurityInfo(nsISupports **aSecurityInfo) { - NS_ENSURE_ARG_POINTER(sec); - *sec = nsnull; + if (mTransport) + return mTransport->GetSecurityInfo(aSecurityInfo); + + *aSecurityInfo = nsnull; return NS_OK; } +//----------------------------------------------------------------------------- // nsIRequestObserver methods +//----------------------------------------------------------------------------- + NS_IMETHODIMP -nsDateTimeChannel::OnStartRequest(nsIRequest *request, nsISupports *aContext) { - return mListener->OnStartRequest(this, aContext); +nsDateTimeChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx) +{ + return mListener->OnStartRequest(this, mListenerContext); } +NS_IMETHODIMP +nsDateTimeChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) +{ + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, mStatus); + + mPump = 0; + mTransport = 0; + return NS_OK; +} NS_IMETHODIMP -nsDateTimeChannel::OnStopRequest(nsIRequest *request, nsISupports* aContext, - nsresult aStatus) { - if (mLoadGroup) { - nsresult rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus); - if (NS_FAILED(rv)) return rv; +nsDateTimeChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, PRUint32 offset, + PRUint32 count) +{ + return mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); +} + +//----------------------------------------------------------------------------- +// nsITransportEventSink methods +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsDateTimeChannel::OnTransportStatus(nsITransport *trans, nsresult status, + PRUint32 progress, PRUint32 progressMax) +{ + // suppress status notification if channel is no longer pending! + if (mProgressSink && mPump && !(mLoadFlags & LOAD_BACKGROUND)) { + NS_ConvertUTF8toUCS2 host(mHost); + mProgressSink->OnStatus(this, nsnull, status, host.get()); + + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + status == nsISocketTransport::STATUS_SENDING_TO) { + mProgressSink->OnProgress(this, nsnull, progress, progressMax); + } } - return mListener->OnStopRequest(this, aContext, aStatus); -} - - -// nsIStreamListener method -NS_IMETHODIMP -nsDateTimeChannel::OnDataAvailable(nsIRequest *request, nsISupports* aContext, - nsIInputStream *aInputStream, PRUint32 aSourceOffset, - PRUint32 aLength) { - mContentLength = aLength; - return mListener->OnDataAvailable(this, aContext, aInputStream, aSourceOffset, aLength); + return NS_OK; } diff --git a/mozilla/extensions/datetime/nsDateTimeChannel.h b/mozilla/extensions/datetime/nsDateTimeChannel.h index 2ca6cbb1660..8efbbf63be5 100644 --- a/mozilla/extensions/datetime/nsDateTimeChannel.h +++ b/mozilla/extensions/datetime/nsDateTimeChannel.h @@ -1,95 +1,85 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * - * 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. + * 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 Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. + * The Initial Developer of the Original Code is Brian Ryner. + * Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner. + * All Rights Reserved. * - * Contributor(s): - * - * 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 - * 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 - * 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. - * - * ***** END LICENSE BLOCK ***** */ + * Contributor(s): + * Darin Fisher + */ -// A datetime channel retrieves date time information from -// RFC 867 compliant datetime servers. The date/time returned -// to the caller is of MIME type "text/plain". - -#ifndef nsDateTimeChannel_h___ -#define nsDateTimeChannel_h___ +#ifndef nsDateTimeChannel_h__ +#define nsDateTimeChannel_h__ +#include "nsDateTimeHandler.h" #include "nsString.h" +#include "nsCOMPtr.h" + #include "nsILoadGroup.h" #include "nsIInputStream.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsCOMPtr.h" -#include "nsXPIDLString.h" +#include "nsIProgressEventSink.h" +#include "nsIInputStreamPump.h" #include "nsIChannel.h" #include "nsIURI.h" -#include "nsDateTimeHandler.h" #include "nsIStreamListener.h" +#include "nsISocketTransport.h" #include "nsIProxyInfo.h" -class nsDateTimeChannel -: public nsIChannel, - public nsIStreamListener { +//----------------------------------------------------------------------------- +class nsDateTimeChannel : public nsIChannel + , public nsIStreamListener + , public nsITransportEventSink +{ public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSITRANSPORTEVENTSINK // nsDateTimeChannel methods: nsDateTimeChannel(); virtual ~nsDateTimeChannel(); - - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); - nsresult Init(nsIURI* uri, nsIProxyInfo* proxyInfo); + nsresult Init(nsIURI *uri, nsIProxyInfo *proxyInfo); protected: - nsCOMPtr mCallbacks; + + nsCOMPtr mURI; nsCOMPtr mOriginalURI; - nsCOMPtr mUrl; - nsCOMPtr mListener; - PRUint32 mLoadFlags; + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; + nsCOMPtr mOwner; nsCOMPtr mLoadGroup; + nsCOMPtr mListener; + nsCOMPtr mListenerContext; nsCString mContentType; - PRInt32 mContentLength; - nsCOMPtr mOwner; + nsCString mContentCharset; + PRUint32 mLoadFlags; + nsresult mStatus; + + nsCOMPtr mPump; + nsCOMPtr mTransport; nsCOMPtr mProxyInfo; + nsCString mHost; PRInt32 mPort; - nsXPIDLCString mHost; }; -#endif /* nsDateTimeChannel_h___ */ +#endif // !nsDateTimeChannel_h__ diff --git a/mozilla/extensions/datetime/nsDateTimeHandler.cpp b/mozilla/extensions/datetime/nsDateTimeHandler.cpp index 36c6831e768..687a4ce2975 100644 --- a/mozilla/extensions/datetime/nsDateTimeHandler.cpp +++ b/mozilla/extensions/datetime/nsDateTimeHandler.cpp @@ -128,17 +128,18 @@ nsDateTimeHandler::NewProxiedChannel(nsIURI* url, nsIProxyInfo* proxyInfo, { nsresult rv; - nsDateTimeChannel* channel; - rv = nsDateTimeChannel::Create(nsnull, NS_GET_IID(nsIChannel), (void**)&channel); - if (NS_FAILED(rv)) return rv; + nsDateTimeChannel *chan = new nsDateTimeChannel(); + if (!chan) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(chan); - rv = channel->Init(url, proxyInfo); + rv = chan->Init(url, proxyInfo); if (NS_FAILED(rv)) { - NS_RELEASE(channel); + NS_RELEASE(chan); return rv; } - *result = channel; + *result = chan; return NS_OK; } diff --git a/mozilla/extensions/finger/nsFingerChannel.cpp b/mozilla/extensions/finger/nsFingerChannel.cpp index cac18bad160..40e3e132058 100644 --- a/mozilla/extensions/finger/nsFingerChannel.cpp +++ b/mozilla/extensions/finger/nsFingerChannel.cpp @@ -17,7 +17,8 @@ * All Rights Reserved. * * Contributor(s): - * Brian Ryner + * Brian Ryner + * Darin Fisher */ // finger implementation @@ -34,6 +35,7 @@ #include "nsIStreamConverterService.h" #include "nsITXTToHTMLConv.h" #include "nsIProgressEventSink.h" +#include "nsEventQueueUtils.h" #include "nsNetUtil.h" #include "nsCRT.h" @@ -45,31 +47,31 @@ static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); // nsFingerChannel methods nsFingerChannel::nsFingerChannel() - : mContentLength(-1), - mActAsObserver(PR_TRUE), - mPort(-1), - mStatus(NS_OK) + : mLoadFlags(LOAD_NORMAL) + , mStatus(NS_OK) + , mPort(-1) { } -nsFingerChannel::~nsFingerChannel() { +nsFingerChannel::~nsFingerChannel() +{ } -NS_IMPL_THREADSAFE_ISUPPORTS4(nsFingerChannel, - nsIChannel, - nsIRequest, - nsIStreamListener, - nsIRequestObserver) +NS_IMPL_ISUPPORTS4(nsFingerChannel, + nsIChannel, + nsIRequest, + nsIStreamListener, + nsIRequestObserver) nsresult -nsFingerChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo) +nsFingerChannel::Init(nsIURI *uri, nsIProxyInfo *proxyInfo) { nsresult rv; nsCAutoString autoBuffer; NS_ASSERTION(uri, "no uri"); - mUrl = uri; + mURI = uri; mProxyInfo = proxyInfo; // For security reasons, we do not allow the user to specify a @@ -77,7 +79,7 @@ nsFingerChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo) mPort = FINGER_PORT; - rv = mUrl->GetPath(autoBuffer); // autoBuffer = user@host + rv = mURI->GetPath(autoBuffer); // autoBuffer = user@host if (NS_FAILED(rv)) return rv; // Now parse out the user and host @@ -86,49 +88,43 @@ nsFingerChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo) // Catch the case of just the host being given if (!pos) { + mUser.Truncate(); mHost.Assign(buf); } else { - mUser.Assign(buf,pos-buf); + mUser.Assign(buf, pos-buf); mHost.Assign(pos+1); // ignore '@' } - if (mHost.IsEmpty()) return NS_ERROR_NOT_INITIALIZED; + if (mHost.IsEmpty()) + return NS_ERROR_MALFORMED_URI; + mContentType = NS_LITERAL_CSTRING(TEXT_HTML); // expected content-type return NS_OK; } -NS_METHOD -nsFingerChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) -{ - nsFingerChannel* fc = new nsFingerChannel(); - if (fc == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(fc); - nsresult rv = fc->QueryInterface(aIID, aResult); - NS_RELEASE(fc); - return rv; -} - //////////////////////////////////////////////////////////////////////////////// // nsIRequest methods: NS_IMETHODIMP nsFingerChannel::GetName(nsACString &result) { - return NS_ERROR_NOT_IMPLEMENTED; + return mURI->GetSpec(result); } NS_IMETHODIMP nsFingerChannel::IsPending(PRBool *result) { - NS_NOTREACHED("nsFingerChannel::IsPending"); - return NS_ERROR_NOT_IMPLEMENTED; + *result = (mPump != nsnull); + return NS_OK; } NS_IMETHODIMP nsFingerChannel::GetStatus(nsresult *status) { - *status = mStatus; + if (NS_SUCCEEDED(mStatus) && mPump) + mPump->GetStatus(status); + else + *status = mStatus; return NS_OK; } @@ -136,27 +132,28 @@ NS_IMETHODIMP nsFingerChannel::Cancel(nsresult status) { NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); - nsresult rv = NS_ERROR_FAILURE; mStatus = status; - if (mTransportRequest) { - rv = mTransportRequest->Cancel(status); - } - return rv; + if (mPump) + mPump->Cancel(status); + + return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -nsFingerChannel::Suspend(void) +nsFingerChannel::Suspend() { - NS_NOTREACHED("nsFingerChannel::Suspend"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mPump) + mPump->Suspend(); + return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -nsFingerChannel::Resume(void) +nsFingerChannel::Resume() { - NS_NOTREACHED("nsFingerChannel::Resume"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mPump) + mPump->Resume(); + return NS_ERROR_UNEXPECTED; } //////////////////////////////////////////////////////////////////////////////// @@ -165,7 +162,7 @@ nsFingerChannel::Resume(void) NS_IMETHODIMP nsFingerChannel::GetOriginalURI(nsIURI* *aURI) { - *aURI = mOriginalURI ? mOriginalURI : mUrl; + *aURI = mOriginalURI ? mOriginalURI : mURI; NS_ADDREF(*aURI); return NS_OK; } @@ -180,7 +177,7 @@ nsFingerChannel::SetOriginalURI(nsIURI* aURI) NS_IMETHODIMP nsFingerChannel::GetURI(nsIURI* *aURI) { - *aURI = mUrl; + *aURI = mURI; NS_IF_ADDREF(*aURI); return NS_OK; } @@ -188,24 +185,8 @@ nsFingerChannel::GetURI(nsIURI* *aURI) NS_IMETHODIMP nsFingerChannel::Open(nsIInputStream **_retval) { - nsresult rv = NS_OK; - - rv = NS_CheckPortSafety(mPort, "finger"); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr socketService = - do_GetService(kSocketTransportServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = socketService->CreateTransport(mHost.get(), mPort, mProxyInfo, BUFFER_SEG_SIZE, - BUFFER_MAX_SIZE, getter_AddRefs(mTransport)); - if (NS_FAILED(rv)) return rv; - - mTransport->SetNotificationCallbacks(mCallbacks, - (mLoadFlags & LOAD_BACKGROUND)); - - return mTransport->OpenInputStream(0, PRUint32(-1), 0, _retval); + NS_NOTREACHED("nsFingerChannel::Open"); + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP @@ -214,24 +195,77 @@ nsFingerChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) nsresult rv = NS_OK; rv = NS_CheckPortSafety(mPort, "finger"); - if (NS_FAILED(rv)) - return rv; + if (NS_FAILED(rv)) return rv; - nsCOMPtr socketService = + nsCOMPtr eventQ; + rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) return rv; + + // + // create transport + // + nsCOMPtr sts = do_GetService(kSocketTransportServiceCID, &rv); if (NS_FAILED(rv)) return rv; - rv = socketService->CreateTransport(mHost.get(), mPort, mProxyInfo, BUFFER_SEG_SIZE, - BUFFER_MAX_SIZE, getter_AddRefs(mTransport)); + rv = sts->CreateTransport(nsnull, 0, mHost, mPort, mProxyInfo, + getter_AddRefs(mTransport)); if (NS_FAILED(rv)) return rv; - mTransport->SetNotificationCallbacks(mCallbacks, - (mLoadFlags & LOAD_BACKGROUND)); + // not fatal if these fail + mTransport->SetSecurityCallbacks(mCallbacks); + mTransport->SetEventSink(this, eventQ); + + rv = WriteRequest(mTransport); + if (NS_FAILED(rv)) return rv; + + // + // create TXT to HTML stream converter + // + nsCOMPtr scs = + do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + NS_NAMED_LITERAL_STRING(fromStr, "text/plain"); + NS_NAMED_LITERAL_STRING(toStr, "text/html"); + + nsCOMPtr convListener; + rv = scs->AsyncConvertData(fromStr.get(), toStr.get(), this, nsnull, + getter_AddRefs(convListener)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr conv = do_QueryInterface(convListener); + if (conv) { + nsCAutoString userHost; + rv = mURI->GetPath(userHost); + + nsAutoString title; + title = NS_LITERAL_STRING("Finger information for ") + + NS_ConvertUTF8toUCS2(userHost); + + conv->SetTitle(title.get()); + conv->PreFormatHTML(PR_TRUE); + } + + // + // open input stream, and create input stream pump... + // + nsCOMPtr sockIn; + rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(sockIn)); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), sockIn); + if (NS_FAILED(rv)) return rv; + + rv = mPump->AsyncRead(convListener, nsnull); + if (NS_FAILED(rv)) return rv; + + if (mLoadGroup) + mLoadGroup->AddRequest(this, nsnull); mListener = aListener; - mResponseContext = ctxt; - - return SendRequest(mTransport); + mListenerContext = ctxt; + return NS_OK; } NS_IMETHODIMP @@ -248,49 +282,46 @@ nsFingerChannel::SetLoadFlags(PRUint32 aLoadFlags) return NS_OK; } -#define FINGER_TYPE TEXT_HTML - NS_IMETHODIMP nsFingerChannel::GetContentType(nsACString &aContentType) { - aContentType = NS_LITERAL_CSTRING(FINGER_TYPE); + aContentType = mContentType; return NS_OK; } NS_IMETHODIMP nsFingerChannel::SetContentType(const nsACString &aContentType) { - //It doesn't make sense to set the content-type on this type - // of channel... - return NS_ERROR_FAILURE; + mContentType = aContentType; + return NS_OK; } NS_IMETHODIMP nsFingerChannel::GetContentCharset(nsACString &aContentCharset) { - aContentCharset.Truncate(); + aContentCharset = mContentCharset; return NS_OK; } NS_IMETHODIMP nsFingerChannel::SetContentCharset(const nsACString &aContentCharset) { - NS_NOTREACHED("nsFingerChannel::SetContentCharset"); - return NS_ERROR_NOT_IMPLEMENTED; + mContentCharset = aContentCharset; + return NS_OK; } NS_IMETHODIMP nsFingerChannel::GetContentLength(PRInt32 *aContentLength) { - *aContentLength = mContentLength; + *aContentLength = -1; return NS_OK; } NS_IMETHODIMP nsFingerChannel::SetContentLength(PRInt32 aContentLength) { - NS_NOTREACHED("nsFingerChannel::SetContentLength"); - return NS_ERROR_NOT_IMPLEMENTED; + // silently ignore this... + return NS_OK; } NS_IMETHODIMP @@ -335,117 +366,96 @@ NS_IMETHODIMP nsFingerChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) { mCallbacks = aNotificationCallbacks; + mProgressSink = do_GetInterface(mCallbacks); return NS_OK; } NS_IMETHODIMP -nsFingerChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) +nsFingerChannel::GetSecurityInfo(nsISupports **aSecurityInfo) { + if (mTransport) + return mTransport->GetSecurityInfo(aSecurityInfo); + *aSecurityInfo = nsnull; return NS_OK; } +//----------------------------------------------------------------------------- // nsIRequestObserver methods -NS_IMETHODIMP -nsFingerChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) { - if (!mActAsObserver) { - // acting as a listener - return mListener->OnStartRequest(this, mResponseContext); - } else { - // we don't want to pass our AsyncWrite's OnStart through - // we just ignore this - return NS_OK; - } -} - +//----------------------------------------------------------------------------- NS_IMETHODIMP -nsFingerChannel::OnStopRequest(nsIRequest *aRequest, nsISupports* aContext, - nsresult aStatus) +nsFingerChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx) { - nsresult rv = NS_OK; - - if (NS_FAILED(aStatus) || !mActAsObserver) { - if (mLoadGroup) { - rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus); - if (NS_FAILED(rv)) return rv; - } - rv = mListener->OnStopRequest(this, mResponseContext, aStatus); - mTransport = 0; - return rv; - } else { - // at this point we know the request has been sent. - // we're no longer acting as an observer. - - mActAsObserver = PR_FALSE; - nsCOMPtr converterListener; - - nsCOMPtr StreamConvService = - do_GetService(kStreamConverterServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - nsAutoString fromStr(NS_LITERAL_STRING("text/plain")); - nsAutoString toStr(NS_LITERAL_STRING("text/html")); - - rv = StreamConvService->AsyncConvertData(fromStr.get(), - toStr.get(), this, mResponseContext, - getter_AddRefs(converterListener)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr converter(do_QueryInterface(converterListener)); - if (converter) { - nsAutoString title(NS_LITERAL_STRING("Finger information for ")); - nsCAutoString userHost; - rv = mUrl->GetPath(userHost); - title.Append(NS_ConvertUTF8toUCS2(userHost)); - converter->SetTitle(title.get()); - converter->PreFormatHTML(PR_TRUE); - } - - return mTransport->AsyncRead(converterListener, mResponseContext, 0, PRUint32(-1), 0, - getter_AddRefs(mTransportRequest)); - } - + return mListener->OnStartRequest(this, mListenerContext); } - -// nsIStreamListener method NS_IMETHODIMP -nsFingerChannel::OnDataAvailable(nsIRequest *aRequest, nsISupports* aContext, - nsIInputStream *aInputStream, PRUint32 aSourceOffset, - PRUint32 aLength) { - mContentLength = aLength; - return mListener->OnDataAvailable(this, mResponseContext, aInputStream, aSourceOffset, aLength); +nsFingerChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) +{ + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, mStatus); + + mPump = 0; + mTransport = 0; + return NS_OK; } +NS_IMETHODIMP +nsFingerChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, PRUint32 offset, + PRUint32 count) +{ + return mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); +} + +//----------------------------------------------------------------------------- +// nsITransportEventSink methods +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsFingerChannel::OnTransportStatus(nsITransport *trans, nsresult status, + PRUint32 progress, PRUint32 progressMax) +{ + // suppress status notification if channel is no longer pending! + if (mProgressSink && mPump && !(mLoadFlags & LOAD_BACKGROUND)) { + NS_ConvertUTF8toUCS2 host(mHost); + mProgressSink->OnStatus(this, nsnull, status, host.get()); + + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + status == nsISocketTransport::STATUS_SENDING_TO) { + mProgressSink->OnProgress(this, nsnull, progress, progressMax); + } + } + return NS_OK; +} + +//----------------------------------------------------------------------------- + nsresult -nsFingerChannel::SendRequest(nsITransport* aTransport) { - // The text to send should already be in mUser +nsFingerChannel::WriteRequest(nsITransport *trans) +{ + // The text to send should already be in mUser + nsresult rv; - nsresult rv = NS_OK; - nsCOMPtr result; - nsCOMPtr charstream; - nsCString requestBuffer(mUser); + nsCAutoString requestBuf; + requestBuf = mUser + NS_LITERAL_CSTRING("\r\n"); - if (mLoadGroup) { - mLoadGroup->AddRequest(this, nsnull); - } + nsCOMPtr stream; + rv = trans->OpenOutputStream(0, requestBuf.Length(), 1, getter_AddRefs(stream)); + if (NS_FAILED(rv)) return rv; - requestBuffer.Append(CRLF); + PRUint32 n; + rv = stream->Write(requestBuf.get(), requestBuf.Length(), &n); + if (NS_FAILED(rv)) return rv; - mRequest.Assign(requestBuffer); - - rv = NS_NewCharInputStream(getter_AddRefs(result), mRequest); - if (NS_FAILED(rv)) return rv; - - charstream = do_QueryInterface(result, &rv); - if (NS_FAILED(rv)) return rv; - - rv = NS_AsyncWriteFromStream(getter_AddRefs(mTransportRequest), - aTransport, charstream, - 0, requestBuffer.Length(), 0, - this, nsnull); - return rv; + NS_ENSURE_TRUE(n == requestBuf.Length(), NS_ERROR_UNEXPECTED); + return NS_OK; } - - diff --git a/mozilla/extensions/finger/nsFingerChannel.h b/mozilla/extensions/finger/nsFingerChannel.h index cd95b103392..bca213cb333 100644 --- a/mozilla/extensions/finger/nsFingerChannel.h +++ b/mozilla/extensions/finger/nsFingerChannel.h @@ -17,75 +17,73 @@ * All Rights Reserved. * * Contributor(s): - * Brian Ryner + * Brian Ryner + * Darin Fisher */ -#ifndef nsFingerChannel_h___ -#define nsFingerChannel_h___ +#ifndef nsFingerChannel_h__ +#define nsFingerChannel_h__ +#include "nsFingerHandler.h" #include "nsString.h" +#include "nsCOMPtr.h" + #include "nsILoadGroup.h" #include "nsIInputStream.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsCOMPtr.h" -#include "nsXPIDLString.h" +#include "nsIProgressEventSink.h" +#include "nsIInputStreamPump.h" #include "nsIChannel.h" #include "nsIURI.h" -#include "nsFingerHandler.h" #include "nsIStreamListener.h" -#include "nsITransport.h" +#include "nsISocketTransport.h" #include "nsIProxyInfo.h" -class nsFingerChannel -: public nsIChannel, - public nsIStreamListener { +//----------------------------------------------------------------------------- +class nsFingerChannel : public nsIChannel + , public nsIStreamListener + , public nsITransportEventSink +{ public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSITRANSPORTEVENTSINK // nsFingerChannel methods: nsFingerChannel(); virtual ~nsFingerChannel(); - - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); - nsresult Init(nsIURI* uri, nsIProxyInfo* proxyInfo); + nsresult Init(nsIURI *uri, nsIProxyInfo *proxyInfo); protected: - nsCOMPtr mCallbacks; + + nsresult WriteRequest(nsITransport *transport); + + nsCOMPtr mURI; nsCOMPtr mOriginalURI; - nsCOMPtr mUrl; - nsCOMPtr mListener; - PRUint32 mLoadFlags; - nsCOMPtr mLoadGroup; - nsCString mContentType; - PRInt32 mContentLength; + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; nsCOMPtr mOwner; - PRUint32 mBufferSegmentSize; - PRUint32 mBufferMaxSize; - PRBool mActAsObserver; + nsCOMPtr mLoadGroup; + nsCOMPtr mListener; + nsCOMPtr mListenerContext; + nsCString mContentType; + nsCString mContentCharset; + PRUint32 mLoadFlags; + nsresult mStatus; + + nsCOMPtr mPump; + nsCOMPtr mTransport; + nsCOMPtr mProxyInfo; PRInt32 mPort; nsCString mHost; nsCString mUser; - - nsXPIDLCString mRequest; - - nsCOMPtr mResponseContext; - nsCOMPtr mTransport; - nsCOMPtr mTransportRequest; - nsCOMPtr mProxyInfo; - nsresult mStatus; - -protected: - nsresult SendRequest(nsITransport* aTransport); }; -#endif /* nsFingerChannel_h___ */ +#endif // !nsFingerChannel_h__ diff --git a/mozilla/extensions/finger/nsFingerHandler.cpp b/mozilla/extensions/finger/nsFingerHandler.cpp index 1f9569f7ebf..01de8afb230 100644 --- a/mozilla/extensions/finger/nsFingerHandler.cpp +++ b/mozilla/extensions/finger/nsFingerHandler.cpp @@ -113,17 +113,18 @@ nsFingerHandler::NewProxiedChannel(nsIURI* url, nsIProxyInfo* proxyInfo, { nsresult rv; - nsFingerChannel* channel; - rv = nsFingerChannel::Create(nsnull, NS_GET_IID(nsIChannel), (void**)&channel); - if (NS_FAILED(rv)) return rv; + nsFingerChannel *chan = new nsFingerChannel(); + if (!chan) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(chan); - rv = channel->Init(url, proxyInfo); + rv = chan->Init(url, proxyInfo); if (NS_FAILED(rv)) { - NS_RELEASE(channel); + NS_RELEASE(chan); return rv; } - *result = channel; + *result = chan; return NS_OK; } diff --git a/mozilla/extensions/irc/js/lib/connection-xpcom.js b/mozilla/extensions/irc/js/lib/connection-xpcom.js index c2aa5800001..b74f5de03be 100644 --- a/mozilla/extensions/irc/js/lib/connection-xpcom.js +++ b/mozilla/extensions/irc/js/lib/connection-xpcom.js @@ -93,29 +93,54 @@ function bc_connect(host, port, bind, tcp_flag, observer) var uri = ios.newURI(spec,null,null); var info = pps.examineForProxy(uri); - this._transport = this._sockService.createTransport (host, port, info, - 0, 0); - if (!this._transport) - throw ("Error creating transport."); + if (jsenv.HAS_STREAM_PROVIDER) + { + this._transport = this._sockService.createTransport (host, port, info, + 0, 0); + if (!this._transport) + throw ("Error creating transport."); - if (jsenv.HAS_NSPR_EVENTQ) - { /* we've got an event queue, so start up an async write */ - this._streamProvider = new StreamProvider (observer); - this._write_req = - this._transport.asyncWrite (this._streamProvider, this, - 0, -1, 0); + if (jsenv.HAS_NSPR_EVENTQ) + { /* we've got an event queue, so start up an async write */ + this._streamProvider = new StreamProvider (observer); + this._write_req = + this._transport.asyncWrite (this._streamProvider, this, + 0, -1, 0); + } + else + { /* no nspr event queues in this environment, we can't use async calls, + * so set up the streams. */ + this._outputStream = this._transport.openOutputStream(0, -1, 0); + if (!this._outputStream) + throw "Error getting output stream."; + this._inputStream = + toScriptableInputStream(this._transport.openInputStream (0, -1, 0)); + if (!this._inputStream) + throw "Error getting input stream."; + } } else - { /* no nspr event queues in this environment, we can't use async calls, - * so set up the streams. */ - this._outputStream = this._transport.openOutputStream(0, -1, 0); + { + /* use new necko interfaces */ + this._transport = this._sockService.createTransport(null, 0, host, port, info); + if (!this._transport) + throw ("Error creating transport."); + + /* if we don't have an event queue, then all i/o must be blocking */ + var openFlags; + if (jsenv.HAS_NSPR_EVENTQ) + openFlags = 0; + else + openFlags = Components.interfaces.nsITransport.OPEN_BLOCKING; + + /* no limit on the output stream buffer */ + this._outputStream = this._transport.openOutputStream(openFlags, 4096, -1); if (!this._outputStream) throw "Error getting output stream."; - this._inputStream = - toScriptableInputStream(this._transport.openInputStream (0, -1, 0)); + this._inputStream = this._transport.openInputStream(openFlags, 0, 0); if (!this._inputStream) throw "Error getting input stream."; - } + } this.connectDate = new Date(); this.isConnected = true; @@ -129,6 +154,8 @@ function bc_disconnect() { if ("_inputStream" in this && this._inputStream) this._inputStream.close(); + if ("_outputStream" in this && this._outputStream) + this._outputStream.close(); /* this._streamProvider.close(); if (this._streamProvider.isBlocked) @@ -142,7 +169,7 @@ function bc_senddata(str) if (!this.isConnected) throw "Not Connected."; - if (jsenv.HAS_NSPR_EVENTQ) + if (jsenv.HAS_NSPR_EVENTQ && jsenv.HAS_STREAM_PROVIDER) this.asyncWrite (str); else this.sendDataNow (str); @@ -158,7 +185,7 @@ function bc_readdata(timeout, count) try { - rv = this._inputStream.read (count); + rv = this._scriptableInputStream.read (count); } catch (ex) { @@ -173,7 +200,15 @@ function bc_readdata(timeout, count) CBSConnection.prototype.startAsyncRead = function bc_saread (observer) { - this._transport.asyncRead (new StreamListener (observer), this, 0, -1, 0); + if (jsenv.HAS_STREAM_PROVIDER) + this._transport.asyncRead (new StreamListener (observer), this, 0, -1, 0); + else + { + var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"]. + createInstance(Components.interfaces.nsIInputStreamPump); + pump.init(this._inputStream, -1, -1, 0, 0, false); + pump.asyncRead(new StreamListener(observer), this); + } } CBSConnection.prototype.asyncWrite = @@ -190,7 +225,10 @@ function bc_awrite (str) CBSConnection.prototype.hasPendingWrite = function bc_haspwrite () { - return (this._streamProvider.pendingData != ""); + if (jsenv.HAS_STREAM_PROVIDER) + return (this._streamProvider.pendingData != ""); + else + return false; /* data already pushed to necko */ } CBSConnection.prototype.sendDataNow = @@ -223,10 +261,14 @@ if (!jsenv.HAS_NSPR_EVENTQ) CBSConnection.prototype.startAsyncRead = _notimpl; CBSConnection.prototype.asyncWrite = _notimpl; } -else +else if (jsenv.HAS_STREAM_PROVIDER) { CBSConnection.prototype.sendDataNow = _notimpl; } +else +{ + CBSConnection.prototype.asyncWrite = _notimpl; +} delete _notimpl; @@ -314,8 +356,8 @@ function sl_dataavail (request, ctxt, inStr, sourceOffset, count) "StreamListener.onDataAvailable ***"); return; } - if (!ctxt._inputStream) - ctxt._inputStream = toScriptableInputStream (inStr); + if (!ctxt._scriptableInputStream) + ctxt._scriptableInputStream = toScriptableInputStream (inStr); if (this._observer) this._observer.onStreamDataAvailable(request, inStr, sourceOffset, diff --git a/mozilla/extensions/pref/autoconfig/src/nsReadConfig.cpp b/mozilla/extensions/pref/autoconfig/src/nsReadConfig.cpp index fb1fcfc1d37..b8edbdae8a3 100644 --- a/mozilla/extensions/pref/autoconfig/src/nsReadConfig.cpp +++ b/mozilla/extensions/pref/autoconfig/src/nsReadConfig.cpp @@ -44,7 +44,6 @@ #include "nsIAutoConfig.h" #include "nsIComponentManager.h" #include "nsIFile.h" -#include "nsIFileStreams.h" #include "nsIObserverService.h" #include "nsIPrefBranch.h" #include "nsIPrefService.h" @@ -52,6 +51,7 @@ #include "nsIServiceManager.h" #include "nsIStringBundle.h" #include "nsXPIDLString.h" +#include "nsNetUtil.h" #include "prmem.h" #include "nsString.h" #include "nsCRT.h" diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp b/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp index 43735f28a47..236d65a7b52 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp +++ b/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp @@ -34,7 +34,7 @@ #include "nsIDocumentViewer.h" #include "nsILocalFile.h" -#include "nsIFileStreams.h" +#include "nsNetUtil.h" #include "nsITextContent.h" diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermStream.cpp b/mozilla/extensions/xmlterm/base/mozXMLTermStream.cpp index 5dc650c1a34..d9387643a14 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermStream.cpp +++ b/mozilla/extensions/xmlterm/base/mozXMLTermStream.cpp @@ -204,13 +204,11 @@ NS_IMETHODIMP mozXMLTermStream::Open(nsIDOMWindowInternal* aDOMWindow, return result; // Create an input stream channel - PRInt32 contentLength = 1024; result = NS_NewInputStreamChannel(getter_AddRefs(mChannel), uri, inputStream, nsDependentCString(contentType), - NS_LITERAL_CSTRING(""), - contentLength); + NS_LITERAL_CSTRING("")); if (NS_FAILED(result)) return result; diff --git a/mozilla/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp b/mozilla/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp index fbba59b10d3..8564da18963 100644 --- a/mozilla/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp +++ b/mozilla/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp @@ -136,9 +136,7 @@ nsAddbookProtocolHandler::GenerateXMLOutputChannel( nsString &aOutput, NS_ENSURE_SUCCESS(rv, rv); rv = NS_NewInputStreamChannel(&channel, aURI, inStr, - NS_LITERAL_CSTRING("text/xml"), - NS_LITERAL_CSTRING(""), - utf8String.Length()); + NS_LITERAL_CSTRING("text/xml")); NS_ENSURE_SUCCESS(rv, rv); *_retval = channel; diff --git a/mozilla/mailnews/addrbook/src/nsAddressBook.cpp b/mozilla/mailnews/addrbook/src/nsAddressBook.cpp index 0128f6b9332..7f12427b854 100644 --- a/mozilla/mailnews/addrbook/src/nsAddressBook.cpp +++ b/mozilla/mailnews/addrbook/src/nsAddressBook.cpp @@ -45,7 +45,7 @@ #include "nsIAddrBookSession.h" #include "nsAddrDatabase.h" #include "nsIOutputStream.h" -#include "nsIFileStreams.h" +#include "nsNetUtil.h" #include "msgCore.h" #include "nsIImportService.h" #include "nsIStringBundle.h" diff --git a/mozilla/mailnews/base/public/nsIMsgFolder.idl b/mozilla/mailnews/base/public/nsIMsgFolder.idl index 90a94d8de80..6c46a56a8d1 100644 --- a/mozilla/mailnews/base/public/nsIMsgFolder.idl +++ b/mozilla/mailnews/base/public/nsIMsgFolder.idl @@ -376,7 +376,7 @@ const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is ne boolean shouldStoreMsgOffline(in nsMsgKey msgKey); boolean hasMsgOffline(in nsMsgKey msgKey); - nsITransport getOfflineFileTransport(in nsMsgKey msgKey, out PRUint32 offset, out PRUint32 size); + nsIInputStream getOfflineFileStream(in nsMsgKey msgKey, out PRUint32 offset, out PRUint32 size); readonly attribute nsIOutputStream offlineStoreOutputStream; readonly attribute nsIInputStream offlineStoreInputStream; void DownloadMessagesForOffline(in nsISupportsArray messages, in nsIMsgWindow window); diff --git a/mozilla/mailnews/base/search/src/nsMsgFilterList.cpp b/mozilla/mailnews/base/search/src/nsMsgFilterList.cpp index 5cc7b56da23..d38730a1502 100644 --- a/mozilla/mailnews/base/search/src/nsMsgFilterList.cpp +++ b/mozilla/mailnews/base/search/src/nsMsgFilterList.cpp @@ -53,8 +53,8 @@ #include "nsIImportService.h" #include "nsMsgBaseCID.h" #include "nsIMsgFilterService.h" -#include "nsIFileStreams.h" #include "nsISupportsObsolete.h" +#include "nsNetUtil.h" // unicode "%s" format string static const PRUnichar unicodeFormatter[] = { diff --git a/mozilla/mailnews/base/src/nsMessenger.cpp b/mozilla/mailnews/base/src/nsMessenger.cpp index dd806561530..c7c5b4d6d63 100644 --- a/mozilla/mailnews/base/src/nsMessenger.cpp +++ b/mozilla/mailnews/base/src/nsMessenger.cpp @@ -969,8 +969,7 @@ nsMessenger::SaveAs(const char* url, PRBool asFile, nsIMsgIdentity* identity, ns aURL, nsnull, // inputStream NS_LITERAL_CSTRING(""), // contentType - NS_LITERAL_CSTRING(""), // contentCharset - -1); // contentLength + NS_LITERAL_CSTRING("")); // contentCharset if (NS_FAILED(rv)) goto done; saveListener->m_outputFormat.AssignWithConversion(saveAsFileType == 1 ? TEXT_HTML : TEXT_PLAIN); diff --git a/mozilla/mailnews/base/src/nsSpamSettings.cpp b/mozilla/mailnews/base/src/nsSpamSettings.cpp index 816e84de31a..b2d6bf20cf3 100644 --- a/mozilla/mailnews/base/src/nsSpamSettings.cpp +++ b/mozilla/mailnews/base/src/nsSpamSettings.cpp @@ -42,9 +42,9 @@ #include "nsILocalFile.h" #include "plstr.h" #include "prmem.h" -#include "nsIFileStreams.h" #include "nsIMsgHdr.h" #include "nsEscape.h" +#include "nsNetUtil.h" #include "nsIMsgFolder.h" #include "nsMsgUtils.h" #include "nsMsgFolderFlags.h" diff --git a/mozilla/mailnews/base/util/nsMsgDBFolder.cpp b/mozilla/mailnews/base/util/nsMsgDBFolder.cpp index 5c4a261cf7c..30d3dc74ab9 100644 --- a/mozilla/mailnews/base/util/nsMsgDBFolder.cpp +++ b/mozilla/mailnews/base/util/nsMsgDBFolder.cpp @@ -42,7 +42,7 @@ #include "nsMsgFolderFlags.h" #include "nsIPrefBranch.h" #include "nsIPrefService.h" -#include "nsIFileChannel.h" +#include "nsNetUtil.h" #include "nsIMsgFolderCache.h" #include "nsIMsgFolderCacheElement.h" #include "nsMsgBaseCID.h" @@ -53,7 +53,6 @@ #include "nsIFileStream.h" #include "nsIChannel.h" #include "nsITransport.h" -#include "nsIFileTransportService.h" #include "nsIMsgFolderCompactor.h" #include "nsIDocShell.h" #include "nsIMsgWindow.h" @@ -520,50 +519,34 @@ NS_IMETHODIMP nsMsgDBFolder::GetOfflineStoreInputStream(nsIInputStream **stream) return rv; } -NS_IMETHODIMP nsMsgDBFolder::GetOfflineFileTransport(nsMsgKey msgKey, PRUint32 *offset, PRUint32 *size, nsITransport **aFileChannel) +NS_IMETHODIMP nsMsgDBFolder::GetOfflineFileStream(nsMsgKey msgKey, PRUint32 *offset, PRUint32 *size, nsIInputStream **aFileStream) { - NS_ENSURE_ARG(aFileChannel); + NS_ENSURE_ARG(aFileStream); *offset = *size = 0; nsresult rv; - rv = nsComponentManager::CreateInstance(NS_LOCALFILECHANNEL_CONTRACTID, nsnull, - NS_GET_IID(nsIFileChannel), (void **) aFileChannel); - if (*aFileChannel) + nsXPIDLCString nativePath; + mPath->GetNativePath(getter_Copies(nativePath)); + + nsCOMPtr localStore; + rv = NS_NewNativeLocalFile(nativePath, PR_TRUE, getter_AddRefs(localStore)); + if (NS_SUCCEEDED(rv) && localStore) { - nsXPIDLCString nativePath; - mPath->GetNativePath(getter_Copies(nativePath)); + rv = NS_NewLocalFileInputStream(aFileStream, localStore); - nsCOMPtr localStore; - rv = NS_NewNativeLocalFile(nativePath, PR_TRUE, getter_AddRefs(localStore)); - if (NS_SUCCEEDED(rv) && localStore) + if (NS_SUCCEEDED(rv)) { - NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - - if (NS_FAILED(rv)) - return rv; - - rv = fts->CreateTransport(localStore, - PR_RDWR | PR_CREATE_FILE, - 0664, - PR_TRUE, - aFileChannel); - if (NS_SUCCEEDED(rv)) + nsresult rv = GetDatabase(nsnull); + NS_ENSURE_SUCCESS(rv, NS_OK); + nsCOMPtr hdr; + rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(hdr)); + if (hdr && NS_SUCCEEDED(rv)) { - - nsresult rv = GetDatabase(nsnull); - NS_ENSURE_SUCCESS(rv, NS_OK); - nsCOMPtr hdr; - rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(hdr)); - if (hdr && NS_SUCCEEDED(rv)) - { - hdr->GetMessageOffset(offset); - hdr->GetOfflineMessageSize(size); - } + hdr->GetMessageOffset(offset); + hdr->GetOfflineMessageSize(size); } } } diff --git a/mozilla/mailnews/base/util/nsMsgDBFolder.h b/mozilla/mailnews/base/util/nsMsgDBFolder.h index 8d9ecba0180..572a06d97f0 100644 --- a/mozilla/mailnews/base/util/nsMsgDBFolder.h +++ b/mozilla/mailnews/base/util/nsMsgDBFolder.h @@ -105,7 +105,7 @@ public: NS_IMETHOD GetSupportsOffline(PRBool *aSupportsOffline); NS_IMETHOD ShouldStoreMsgOffline(nsMsgKey msgKey, PRBool *result); - NS_IMETHOD GetOfflineFileTransport(nsMsgKey msgKey, PRUint32 *offset, PRUint32 *size, nsITransport **_retval); + NS_IMETHOD GetOfflineFileStream(nsMsgKey msgKey, PRUint32 *offset, PRUint32 *size, nsIInputStream **_retval); NS_IMETHOD HasMsgOffline(nsMsgKey msgKey, PRBool *result); NS_IMETHOD DownloadMessagesForOffline(nsISupportsArray *messages, nsIMsgWindow *msgWindow); NS_IMETHOD DownloadAllForOffline(nsIUrlListener *listener, nsIMsgWindow *msgWindow); diff --git a/mozilla/mailnews/base/util/nsMsgProtocol.cpp b/mozilla/mailnews/base/util/nsMsgProtocol.cpp index bde39b47313..c53e727be66 100644 --- a/mozilla/mailnews/base/util/nsMsgProtocol.cpp +++ b/mozilla/mailnews/base/util/nsMsgProtocol.cpp @@ -39,7 +39,9 @@ #include "nsReadableUtils.h" #include "nsMsgProtocol.h" #include "nsIMsgMailNewsUrl.h" +#include "nsIStreamTransportService.h" #include "nsISocketTransportService.h" +#include "nsISocketTransport.h" #include "nsXPIDLString.h" #include "nsSpecialSystemDirectory.h" #include "nsILoadGroup.h" @@ -47,7 +49,6 @@ #include "nsNetUtil.h" #include "nsIFileURL.h" #include "nsFileStream.h" -#include "nsIFileTransportService.h" #include "nsIDNSService.h" #include "nsIMsgWindow.h" #include "nsIMsgStatusFeedback.h" @@ -58,10 +59,11 @@ #include "nsIStringBundle.h" #include "nsIProtocolProxyService.h" #include "nsIProxyInfo.h" +#include "nsEventQueueUtils.h" static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); +static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); -static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); NS_IMPL_THREADSAFE_ADDREF(nsMsgProtocol) NS_IMPL_THREADSAFE_RELEASE(nsMsgProtocol) @@ -72,6 +74,7 @@ NS_INTERFACE_MAP_BEGIN(nsMsgProtocol) NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) NS_INTERFACE_MAP_ENTRY(nsIChannel) NS_INTERFACE_MAP_ENTRY(nsIRequest) + NS_INTERFACE_MAP_ENTRY(nsITransportEventSink) NS_INTERFACE_MAP_END_THREADSAFE static PRUnichar *GetStringByID(PRInt32 stringID); @@ -81,7 +84,6 @@ static PRUnichar *FormatStringWithHostNameByID(PRInt32 stringID, nsIMsgMailNewsU nsMsgProtocol::nsMsgProtocol(nsIURI * aURL) { m_flags = 0; - m_startPosition = 0; m_readCount = 0; mLoadFlags = 0; m_socketIsOpen = PR_FALSE; @@ -125,15 +127,24 @@ nsMsgProtocol::OpenNetworkSocketWithInfo(const char * aHostName, // with socket connections we want to read as much data as arrives m_readCount = -1; - m_startPosition = 0; - rv = socketService->CreateTransportOfType(connectionType, aHostName, - aGetPort, aProxyInfo, 0, 0, - getter_AddRefs(m_transport)); + nsCOMPtr strans; + rv = socketService->CreateTransport(&connectionType, connectionType != nsnull, + nsDependentCString(aHostName), + aGetPort, aProxyInfo, + getter_AddRefs(strans)); if (NS_FAILED(rv)) return rv; - m_transport->SetNotificationCallbacks(callbacks, PR_FALSE); + strans->SetSecurityCallbacks(callbacks); + + // creates cyclic reference! + nsCOMPtr eventQ; + NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (eventQ) + strans->SetEventSink(this, eventQ); + m_socketIsOpen = PR_FALSE; + m_transport = strans; return SetupTransportState(); } @@ -220,37 +231,41 @@ nsresult nsMsgProtocol::OpenFileSocket(nsIURI * aURL, PRUint32 aStartPosition, P // rid of this method completely. nsresult rv = NS_OK; - m_startPosition = aStartPosition; m_readCount = aReadCount; nsCOMPtr file; rv = GetFileFromURL(aURL, getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); + nsCOMPtr stream; + rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file); if (NS_FAILED(rv)) return rv; - //we are always using this file socket to read data from the mailbox. - rv = fts->CreateTransport(file, PR_RDONLY, - 0664, PR_TRUE, getter_AddRefs(m_transport)); - m_socketIsOpen = PR_FALSE; + // create input stream transport + nsCOMPtr sts = + do_GetService(kStreamTransportServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = sts->CreateInputTransport(stream, aStartPosition, aReadCount, PR_TRUE, getter_AddRefs(m_transport)); + + m_socketIsOpen = PR_FALSE; return rv; } nsresult nsMsgProtocol::SetupTransportState() { - nsresult rv = NS_OK; - if (!m_socketIsOpen && m_transport) { - rv = m_transport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(m_outputStream)); + nsresult rv; + + // open buffered, blocking output stream + rv = m_transport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(m_outputStream)); + if (NS_FAILED(rv)) return rv; - NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create an output stream"); // we want to open the stream } // if m_transport - return rv; + return NS_OK; } nsresult nsMsgProtocol::CloseSocket() @@ -258,15 +273,24 @@ nsresult nsMsgProtocol::CloseSocket() nsresult rv = NS_OK; // release all of our socket state m_socketIsOpen = PR_FALSE; + m_inputStream = nsnull; m_outputStream = nsnull; - if (m_transport) - m_transport->SetNotificationCallbacks(nsnull, PR_FALSE); + if (m_transport) { + nsCOMPtr strans = do_QueryInterface(m_transport); + if (strans) { + strans->SetSecurityCallbacks(nsnull); + strans->SetEventSink(nsnull, nsnull); // break cyclic reference! + } + } // we need to call Cancel so that we remove the socket transport from the mActiveTransportList. see bug #30648 if (m_request) { rv = m_request->Cancel(NS_BINDING_ABORTED); } - m_request = 0; - m_transport = 0; + m_request = 0; + if (m_transport) { + m_transport->Close(NS_BINDING_ABORTED); + m_transport = 0; + } return rv; } @@ -434,8 +458,23 @@ nsresult nsMsgProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer) nsCOMPtr urlSupports = do_QueryInterface(aURL); if (m_transport) { + // don't open the input stream more than once + if (!m_inputStream) + { + // open buffered, asynchronous input stream + rv = m_transport->OpenInputStream(0, 0, 0, getter_AddRefs(m_inputStream)); + if (NS_FAILED(rv)) return rv; + } + + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), + m_inputStream, -1, m_readCount); + if (NS_FAILED(rv)) return rv; + + m_request = pump; // keep a reference to the pump so we can cancel it + // put us in a state where we are always notified of incoming data - rv = m_transport->AsyncRead(this, urlSupports, m_startPosition, m_readCount, 0, getter_AddRefs(m_request)); + rv = pump->AsyncRead(this, urlSupports); NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncRead failed"); m_socketIsOpen = PR_TRUE; // mark the channel as open } @@ -626,6 +665,24 @@ nsMsgProtocol::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCall return NS_OK; } +NS_IMETHODIMP +nsMsgProtocol::OnTransportStatus(nsITransport *transport, nsresult status, + PRUint32 progress, PRUint32 progressMax) +{ + if (mProgressEventSink && !(mLoadFlags & LOAD_BACKGROUND)) { + nsCAutoString host; + if (m_url) + m_url->GetHost(host); + mProgressEventSink->OnStatus(this, nsnull, status, NS_ConvertUTF8toUCS2(host).get()); + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + status == nsISocketTransport::STATUS_SENDING_TO || + status == nsITransport::STATUS_READING || + status == nsITransport::STATUS_WRITING) + mProgressEventSink->OnProgress(this, nsnull, progress, progressMax); + } + return NS_OK; +} + //////////////////////////////////////////////////////////////////////////////// // From nsIRequest //////////////////////////////////////////////////////////////////////////////// @@ -656,14 +713,20 @@ NS_IMETHODIMP nsMsgProtocol::Cancel(nsresult status) NS_IMETHODIMP nsMsgProtocol::Suspend() { - NS_NOTREACHED("Suspend"); - return NS_ERROR_NOT_IMPLEMENTED; + if (m_request) + return m_request->Suspend(); + + NS_WARNING("no request to suspend"); + return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsMsgProtocol::Resume() { - NS_NOTREACHED("Resume"); - return NS_ERROR_NOT_IMPLEMENTED; + if (m_request) + return m_request->Resume(); + + NS_WARNING("no request to resume"); + return NS_ERROR_NOT_AVAILABLE; } nsresult nsMsgProtocol::PostMessage(nsIURI* url, nsIFileSpec *fileSpec) @@ -780,7 +843,7 @@ nsresult nsMsgProtocol::PostMessage(nsIURI* url, nsIFileSpec *fileSpec) // nsMsgAsyncWriteProtocol subclass and related helper classes ///////////////////////////////////////////////////////////////////// -class nsMsgProtocolStreamProvider : public nsIStreamProvider +class nsMsgProtocolStreamProvider : public nsIOutputStreamNotify { public: NS_DECL_ISUPPORTS @@ -788,20 +851,16 @@ public: nsMsgProtocolStreamProvider() { } virtual ~nsMsgProtocolStreamProvider() {} - void Init(nsMsgAsyncWriteProtocol *aProtInstance, nsIInputStream *aInputStream) { mMsgProtocol = aProtInstance; mInStream = aInputStream;} + void Init(nsMsgAsyncWriteProtocol *aProtInstance, nsIInputStream *aInputStream) + { + mMsgProtocol = aProtInstance; + mInStream = aInputStream; + } // - // nsIRequestObserver implementation ... + // nsIOutputStreamNotify implementation ... // - NS_IMETHODIMP OnStartRequest(nsIRequest *chan, nsISupports *ctxt) { return NS_OK; } - NS_IMETHODIMP OnStopRequest(nsIRequest *chan, nsISupports *ctxt, nsresult status) { return NS_OK; } - - // - // nsIStreamProvider implementation ... - // - NS_IMETHODIMP OnDataWritable(nsIRequest *aChannel, nsISupports *aContext, - nsIOutputStream *aOutStream, - PRUint32 aOffset, PRUint32 aCount) + NS_IMETHODIMP OnOutputStreamReady(nsIAsyncOutputStream *aOutStream) { NS_ASSERTION(mInStream, "not initialized"); @@ -817,30 +876,37 @@ public: if (avail == 0) { + // ok, stop writing... mMsgProtocol->mSuspendedWrite = PR_TRUE; - return NS_BASE_STREAM_WOULD_BLOCK; + return NS_OK; } PRUint32 bytesWritten; - rv = aOutStream->WriteFrom(mInStream, PR_MIN(avail, aCount), &bytesWritten); + rv = aOutStream->WriteFrom(mInStream, PR_MIN(avail, 4096), &bytesWritten); // if were full at the time, the input stream may be backed up and we need to read any remains from the last ODA call // before we'll get more ODA calls if (mMsgProtocol->mSuspendedRead) mMsgProtocol->UnblockPostReader(); mMsgProtocol->UpdateProgress(bytesWritten); - return rv; + + // try to write again... + if (NS_SUCCEEDED(rv)) + rv = aOutStream->AsyncWait(this, 0, mMsgProtocol->mProviderEventQ); + + NS_ASSERTION(NS_SUCCEEDED(rv) || rv == NS_BINDING_ABORTED, "unexpected error writing stream"); + return NS_OK; } protected: nsMsgAsyncWriteProtocol * mMsgProtocol; - nsCOMPtr mInStream; + nsCOMPtr mInStream; }; -NS_IMPL_THREADSAFE_ISUPPORTS2(nsMsgProtocolStreamProvider, - nsIStreamProvider, - nsIRequestObserver) +// XXX this probably doesn't need to be threadsafe +NS_IMPL_THREADSAFE_ISUPPORTS1(nsMsgProtocolStreamProvider, + nsIOutputStreamNotify) class nsMsgFilePostHelper : public nsIStreamListener { @@ -874,18 +940,19 @@ nsresult nsMsgFilePostHelper::Init(nsIOutputStream * aOutStream, nsMsgAsyncWrite mOutStream = aOutStream; mProtInstance = aProtInstance; // mscott work out ref counting issue - - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); + nsCOMPtr stream; + rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), aFileToPost); if (NS_FAILED(rv)) return rv; - nsCOMPtr transport; - rv = fts->CreateTransport(aFileToPost, PR_RDONLY, 0664, PR_TRUE, getter_AddRefs(transport)); - if (transport) - { - rv = transport->AsyncRead(this, nsnull, 0, PRUint32(-1), 0, getter_AddRefs(mPostFileRequest)); - } - return rv; + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), stream); + if (NS_FAILED(rv)) return rv; + + rv = pump->AsyncRead(this, nsnull); + if (NS_FAILED(rv)) return rv; + + mPostFileRequest = pump; + return NS_OK; } NS_IMETHODIMP nsMsgFilePostHelper::OnStartRequest(nsIRequest * aChannel, nsISupports *ctxt) @@ -923,7 +990,8 @@ NS_IMETHODIMP nsMsgFilePostHelper::OnDataAvailable(nsIRequest * /* aChannel */, // data to write (i.e. the pipe went empty). So resume the channel to kick // things off again. mProtInstance->mSuspendedWrite = PR_FALSE; - mProtInstance->m_WriteRequest->Resume(); + mProtInstance->mAsyncOutStream->AsyncWait(mProtInstance->mProvider, 0, + mProtInstance->mProviderEventQ); } return NS_OK; @@ -954,8 +1022,8 @@ NS_IMETHODIMP nsMsgAsyncWriteProtocol::Cancel(nsresult status) if (m_request) m_request->Cancel(status); - if (m_WriteRequest) - m_WriteRequest->Cancel(status); + if (mAsyncOutStream) + mAsyncOutStream->CloseEx(status); return NS_OK; } @@ -1188,15 +1256,25 @@ nsresult nsMsgAsyncWriteProtocol::SetupTransportState() PR_TRUE, PR_TRUE); - nsCOMPtr provider; + rv = NS_GetCurrentEventQ(getter_AddRefs(mProviderEventQ)); + if (NS_FAILED(rv)) return rv; + + nsMsgProtocolStreamProvider *provider; NS_NEWXPCOM(provider, nsMsgProtocolStreamProvider); if (!provider) return NS_ERROR_OUT_OF_MEMORY; - NS_STATIC_CAST(nsMsgProtocolStreamProvider*, - NS_STATIC_CAST(nsIStreamProvider*, provider))->Init(this, mInStream); + provider->Init(this, mInStream); + mProvider = provider; // ADDREF - rv = m_transport->AsyncWrite(provider, nsnull, 0, 0, 0, getter_AddRefs(m_WriteRequest)); + nsCOMPtr stream; + rv = m_transport->OpenOutputStream(0, 0, 0, getter_AddRefs(stream)); if (NS_FAILED(rv)) return rv; + + mAsyncOutStream = do_QueryInterface(stream, &rv); + if (NS_FAILED(rv)) return rv; + + // wait for the output stream to become writable + rv = mAsyncOutStream->AsyncWait(mProvider, 0, mProviderEventQ); } // if m_transport return rv; @@ -1207,9 +1285,8 @@ nsresult nsMsgAsyncWriteProtocol::CloseSocket() nsresult rv = NS_OK; nsMsgProtocol::CloseSocket(); - // we need to call Cancel so that we remove the socket transport from the mActiveTransportList. see bug #30648 - if (m_WriteRequest) - rv = m_WriteRequest->Cancel(NS_BINDING_ABORTED); + if (mAsyncOutStream) + mAsyncOutStream->CloseEx(NS_BINDING_ABORTED); if (mFilePostHelper) { @@ -1217,7 +1294,9 @@ nsresult nsMsgAsyncWriteProtocol::CloseSocket() mFilePostHelper = nsnull; } - m_WriteRequest = 0; + mAsyncOutStream = 0; + mProvider = 0; + mProviderEventQ = 0; return rv; } @@ -1238,7 +1317,8 @@ void nsMsgAsyncWriteProtocol::UpdateProgress(PRUint32 aNewBytes) nsCOMPtr webProgressListener (do_QueryInterface(statusFeedback)); if (!webProgressListener) return; - webProgressListener->OnProgressChange(nsnull, m_WriteRequest, mNumBytesPosted, mFilePostSize, mNumBytesPosted, mFilePostSize); + // XXX not sure if m_request is correct here + webProgressListener->OnProgressChange(nsnull, m_request, mNumBytesPosted, mFilePostSize, mNumBytesPosted, mFilePostSize); } return; @@ -1258,7 +1338,7 @@ PRInt32 nsMsgAsyncWriteProtocol::SendData(nsIURI * aURL, const char * dataBuffer // data to write (i.e. the pipe went empty). So resume the channel to kick // things off again. mSuspendedWrite = PR_FALSE; - m_WriteRequest->Resume(); + mAsyncOutStream->AsyncWait(mProvider, 0, mProviderEventQ); } return NS_OK; } @@ -1325,3 +1405,5 @@ PRUnichar *FormatStringWithHostNameByID(PRInt32 stringID, nsIMsgMailNewsUrl *msg return (ptrv); } + +// vim: ts=2 sw=2 diff --git a/mozilla/mailnews/base/util/nsMsgProtocol.h b/mozilla/mailnews/base/util/nsMsgProtocol.h index 6aec6e61411..c930db273e7 100644 --- a/mozilla/mailnews/base/util/nsMsgProtocol.h +++ b/mozilla/mailnews/base/util/nsMsgProtocol.h @@ -48,9 +48,10 @@ #include "nsIFileSpec.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIStreamProvider.h" #include "nsIProgressEventSink.h" #include "nsITransport.h" +#include "nsIAsyncOutputStream.h" +#include "nsIEventQueue.h" #define UNKNOWN_ERROR 101 #define UNKNOWN_HOST_ERROR 102 @@ -67,7 +68,9 @@ class nsIProxyInfo; // it unifies the core networking code for the protocols. My hope is that // this will make unification with Necko easier as we'll only have to change // this class and not all of the mailnews protocols. -class NS_MSG_BASE nsMsgProtocol : public nsIStreamListener, public nsIChannel +class NS_MSG_BASE nsMsgProtocol : public nsIStreamListener + , public nsIChannel + , public nsITransportEventSink { public: nsMsgProtocol(nsIURI * aURL); @@ -80,6 +83,7 @@ public: NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSITRANSPORTEVENTSINK // LoadUrl -- A protocol typically overrides this function, sets up any local state for the url and // then calls the base class which opens the socket if it needs opened. If the socket is @@ -139,6 +143,7 @@ protected: // Ouput stream for writing commands to the socket nsCOMPtr m_outputStream; // this will be obtained from the transport interface + nsCOMPtr m_inputStream; // Ouput stream for writing commands to the socket nsCOMPtr m_transport; @@ -147,7 +152,7 @@ protected: PRBool m_socketIsOpen; // mscott: we should look into keeping this state in the nsSocketTransport... // I'm using it to make sure I open the socket the first time a URL is loaded into the connection PRUint32 m_flags; // used to store flag information - PRUint32 m_startPosition; + //PRUint32 m_startPosition; PRInt32 m_readCount; nsFileSpec m_tempMsgFileSpec; // we currently have a hack where displaying a msg involves writing it to a temp file first @@ -197,6 +202,9 @@ public: // if we suspended the asynch write while waiting for more data to write then this will be TRUE PRBool mSuspendedWrite; nsCOMPtr m_WriteRequest; + nsCOMPtr mAsyncOutStream; + nsCOMPtr mProvider; + nsCOMPtr mProviderEventQ; // because we are reading the post data in asychronously, it's possible that we aren't sending it // out fast enough and the reading gets blocked. The following set of state variables are used to diff --git a/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.cpp index fceb3d0ab2e..e6a7c107073 100644 --- a/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.cpp +++ b/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.cpp @@ -571,8 +571,7 @@ nsMsgAttachmentHandler::SnarfMsgAttachment(nsMsgCompFields *compFields) if (aURL) aURL->SetSpec(nsDependentCString(uri.get())); - rv = NS_NewInputStreamChannel(getter_AddRefs(m_converter_channel), aURL, nsnull, - NS_LITERAL_CSTRING(""), NS_LITERAL_CSTRING(""), -1); + rv = NS_NewInputStreamChannel(getter_AddRefs(m_converter_channel), aURL, nsnull); if (NS_FAILED(rv)) goto done; diff --git a/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.h b/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.h index 4dbe230e4d6..d59c8e6e689 100644 --- a/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.h +++ b/mozilla/mailnews/compose/src/nsMsgAttachmentHandler.h @@ -42,7 +42,7 @@ #include "nsIMimeConverter.h" #include "nsMsgCompFields.h" #include "nsIMsgStatusFeedback.h" -#include "nsIRequest.h" +#include "nsIChannel.h" #include "nsIMsgSend.h" #include "nsIFileStreams.h" #include "nsIStreamConverter.h" diff --git a/mozilla/mailnews/compose/src/nsMsgCreate.cpp b/mozilla/mailnews/compose/src/nsMsgCreate.cpp index b7fd5e78054..64a74435215 100644 --- a/mozilla/mailnews/compose/src/nsMsgCreate.cpp +++ b/mozilla/mailnews/compose/src/nsMsgCreate.cpp @@ -173,8 +173,7 @@ nsMsgDraft::ProcessDraftOrTemplateOperation(const char *msgURI, nsMimeOutputType } nsCOMPtr dummyChannel; - rv = NS_NewInputStreamChannel(getter_AddRefs(dummyChannel), aURL, nsnull, - NS_LITERAL_CSTRING(""), NS_LITERAL_CSTRING(""), -1); + rv = NS_NewInputStreamChannel(getter_AddRefs(dummyChannel), aURL, nsnull); if (NS_FAILED(mimeParser->AsyncConvertData(nsnull, nsnull, nsnull, dummyChannel))) { Release(); diff --git a/mozilla/mailnews/compose/src/nsSmtpProtocol.cpp b/mozilla/mailnews/compose/src/nsSmtpProtocol.cpp index 37c8fa6bb3b..c86b5a4a105 100644 --- a/mozilla/mailnews/compose/src/nsSmtpProtocol.cpp +++ b/mozilla/mailnews/compose/src/nsSmtpProtocol.cpp @@ -46,6 +46,7 @@ #include "nsIStreamListener.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "nsISocketTransport.h" #include "nsIMsgHeaderParser.h" #include "nsFileStream.h" #include "nsIMsgMailNewsUrl.h" @@ -712,14 +713,10 @@ PRInt32 nsSmtpProtocol::SendTLSResponse() if (m_responseCode == 220) { nsCOMPtr secInfo; - nsCOMPtr trans; - nsCOMPtr transReq = do_QueryInterface(m_request, &rv); + nsCOMPtr strans = do_QueryInterface(m_transport, &rv); if (NS_FAILED(rv)) return rv; - rv = transReq->GetTransport(getter_AddRefs(trans)); - if (NS_FAILED(rv)) return rv; - - rv = trans->GetSecurityInfo(getter_AddRefs(secInfo)); + rv = strans->GetSecurityInfo(getter_AddRefs(secInfo)); if (NS_SUCCEEDED(rv) && secInfo) { nsCOMPtr sslControl = do_QueryInterface(secInfo, &rv); diff --git a/mozilla/mailnews/imap/src/nsImapProtocol.cpp b/mozilla/mailnews/imap/src/nsImapProtocol.cpp index d54f917c18b..c7bc77d3928 100644 --- a/mozilla/mailnews/imap/src/nsImapProtocol.cpp +++ b/mozilla/mailnews/imap/src/nsImapProtocol.cpp @@ -104,6 +104,7 @@ PRLogModuleInfo *IMAP; #include "nsIProxyObjectManager.h" #include "nsIStreamConverterService.h" #include "nsIProxyInfo.h" +#include "nsEventQueueUtils.h" #if 0 #include "nsIHashAlgorithm.h" #endif @@ -413,6 +414,8 @@ nsImapProtocol::nsImapProtocol() : m_dataOutputBuf = (char *) PR_CALLOC(sizeof(char) * OUTPUT_BUFFER_SIZE); m_allocatedSize = OUTPUT_BUFFER_SIZE; + m_pumpSuspended = PR_FALSE; + // used to buffer incoming data by ReadNextLineFromInput m_inputStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, PR_TRUE /* allocate new lines */, PR_FALSE /* leave CRLFs on the returned string */); m_currentBiffState = nsIMsgFolder::nsMsgBiffState_Unknown; @@ -735,7 +738,7 @@ nsresult nsImapProtocol::SetupWithUrl(nsIURI * aURL, nsISupports* aConsumer) imapServer->GetFetchByChunks(&m_fetchByChunks); } - if ( m_runningUrl && !m_channel /* and we don't have a transport yet */) + if ( m_runningUrl && !m_transport /* and we don't have a transport yet */) { // extract the file name and create a file transport... PRInt32 port=-1; @@ -771,35 +774,67 @@ nsresult nsImapProtocol::SetupWithUrl(nsIURI * aURL, nsISupports* aConsumer) rv = NS_ExamineForProxy("imap", hostName.get(), port, getter_AddRefs(proxyInfo)); if (NS_FAILED(rv)) proxyInfo = nsnull; + const nsACString *socketHost; + PRUint16 socketPort; + if (m_overRideUrlConnectionInfo) - rv = socketService->CreateTransportOfType(connectionType, m_logonHost.get(), m_logonPort, proxyInfo, 0, 0, getter_AddRefs(m_channel)); - else - rv = socketService->CreateTransportOfType(connectionType, hostName, port, proxyInfo, 0, 0, getter_AddRefs(m_channel)); - - // Ensure that the socket can get the notification callbacks - nsCOMPtr callbacks; - m_mockChannel->GetNotificationCallbacks(getter_AddRefs(callbacks)); - if (m_channel) { - m_channel->SetNotificationCallbacks(callbacks, PR_FALSE); + socketHost = &m_logonHost; + socketPort = m_logonPort; + } + else + { + socketHost = &hostName; + socketPort = port; + } + rv = socketService->CreateTransport(&connectionType, connectionType != nsnull, + *socketHost, socketPort, proxyInfo, + getter_AddRefs(m_transport)); - if (NS_SUCCEEDED(rv)) - rv = m_channel->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(m_outputStream)); + if (m_transport) + { + // Ensure that the socket can get the notification callbacks + nsCOMPtr callbacks; + m_mockChannel->GetNotificationCallbacks(getter_AddRefs(callbacks)); + if (callbacks) + m_transport->SetSecurityCallbacks(callbacks); + + nsCOMPtr sink = do_QueryInterface(m_mockChannel); + if (sink) { + nsCOMPtr eventQ; + NS_GetMainEventQ(getter_AddRefs(eventQ)); + m_transport->SetEventSink(sink, eventQ); + } + + // open buffered, asynchronous input stream + rv = m_transport->OpenInputStream(0, 0, 0, getter_AddRefs(m_inputStream)); + if (NS_FAILED(rv)) return rv; + + // open buffered, blocking output stream + rv = m_transport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(m_outputStream)); + if (NS_FAILED(rv)) return rv; } } } // if m_runningUrl - if (m_channel && m_mockChannel) + if (m_transport && m_mockChannel) { // set the security info for the mock channel to be the security status for our underlying transport. nsCOMPtr securityInfo; - m_channel->GetSecurityInfo(getter_AddRefs(securityInfo)); + m_transport->GetSecurityInfo(getter_AddRefs(securityInfo)); m_mockChannel->SetSecurityInfo(securityInfo); nsCOMPtr callbacks; m_mockChannel->GetNotificationCallbacks(getter_AddRefs(callbacks)); - if (callbacks && m_channel) - m_channel->SetNotificationCallbacks(callbacks, PR_FALSE); + if (callbacks && m_transport) + m_transport->SetSecurityCallbacks(callbacks); + + nsCOMPtr sink = do_QueryInterface(m_mockChannel); + if (sink) { + nsCOMPtr eventQ; + NS_GetMainEventQ(getter_AddRefs(eventQ)); + m_transport->SetEventSink(sink, eventQ); + } // and if we have a cache entry that we are saving the message to, set the security info on it too. // since imap only uses the memory cache, passing this on is the right thing to do. @@ -822,8 +857,11 @@ nsresult nsImapProtocol::SetupWithUrl(nsIURI * aURL, nsISupports* aConsumer) void nsImapProtocol::ReleaseUrlState() { // clear out the socket's reference to the notification callbacks for this transaction - if (m_channel) - m_channel->SetNotificationCallbacks(nsnull, PR_FALSE); + if (m_transport) + { + m_transport->SetSecurityCallbacks(nsnull); + m_transport->SetEventSink(nsnull, nsnull); + } if (m_mockChannel) { @@ -923,7 +961,8 @@ NS_IMETHODIMP nsImapProtocol::Run() } me->m_runningUrl = nsnull; - me->m_channel = nsnull; + me->m_transport = nsnull; + me->m_inputStream = nsnull; me->m_outputStream = nsnull; me->m_channelListener = nsnull; me->m_channelContext = nsnull; @@ -1030,8 +1069,8 @@ nsImapProtocol::TellThreadToDie(PRBool isSaveToClose) } } - if (mAsyncReadRequest) - mAsyncReadRequest->Cancel(NS_OK); + if (m_pump) + m_pump->Cancel(NS_ERROR_ABORT); PR_EnterMonitor(m_threadDeathMonitor); m_threadShouldDie = PR_TRUE; PR_ExitMonitor(m_threadDeathMonitor); @@ -1114,7 +1153,7 @@ nsImapProtocol::ImapThreadMainLoop() // process the current url. Don't try to wait for the monitor // the first time because it may have already been signaled. // But make sure we have a channel first, or ProcessCurrentUrl will fail. - if (TestFlag(IMAP_FIRST_PASS_IN_THREAD) && m_runningUrl && m_channel) + if (TestFlag(IMAP_FIRST_PASS_IN_THREAD) && m_runningUrl && m_transport) { // if we launched another url, just loop around and process it. if (ProcessCurrentURL()) @@ -1202,13 +1241,19 @@ PRBool nsImapProtocol::ProcessCurrentURL() PRBool isExternalUrl; + nsresult rv = NS_OK; + PseudoInterrupt(PR_FALSE); // clear this if left over from previous url. - if (!TestFlag(IMAP_CONNECTION_IS_OPEN) && m_channel) + if (!TestFlag(IMAP_CONNECTION_IS_OPEN) && m_inputStream) { - m_channel->AsyncRead(this /* stream listener */, nsnull, 0, PRUint32(-1), 0, - getter_AddRefs(mAsyncReadRequest)); - SetFlag(IMAP_CONNECTION_IS_OPEN); + rv = NS_NewInputStreamPump(getter_AddRefs(m_pump), m_inputStream); + if (NS_SUCCEEDED(rv)) + { + rv = m_pump->AsyncRead(this /* stream listener */, nsnull); + if (NS_SUCCEEDED(rv)) + SetFlag(IMAP_CONNECTION_IS_OPEN); + } } if (m_runningUrl) { @@ -1244,7 +1289,6 @@ PRBool nsImapProtocol::ProcessCurrentURL() GetServerStateParser().SetConnected(PR_TRUE); // acknowledge that we are running the url now.. - nsresult rv = NS_OK; nsCOMPtr mailnewsurl = do_QueryInterface(m_runningUrl, &rv); #ifdef DEBUG_bienvenu1 nsXPIDLCString urlSpec; @@ -1425,26 +1469,30 @@ void nsImapProtocol::ParseIMAPandCheckForNewMail(const char* commandString, PRBo //////////////////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP nsImapProtocol::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, nsIInputStream *aIStream, PRUint32 aSourceOffset, PRUint32 aLength) { - nsresult res = NS_OK; - - if(NS_SUCCEEDED(res) && aLength > 0) - { + if (aLength > 0) + { // make sure m_inputStream is set to the right input stream... - if (!m_inputStream) - m_inputStream = dont_QueryInterface(aIStream); + NS_ASSERTION(m_inputStream == aIStream, "unexpected stream"); - if (TestFlag(IMAP_WAITING_FOR_DATA)) - { - // if we received data, we need to signal the data available monitor... + if (TestFlag(IMAP_WAITING_FOR_DATA)) + { + // if we received data, we need to signal the data available monitor... // Read next line from input will actually read the data out of the stream - ClearFlag(IMAP_WAITING_FOR_DATA); // we are no longer waiting for data - PR_EnterMonitor(m_dataAvailableMonitor); + ClearFlag(IMAP_WAITING_FOR_DATA); // we are no longer waiting for data + + // XXX no one ever waits on this monitor! + PR_EnterMonitor(m_dataAvailableMonitor); PR_Notify(m_dataAvailableMonitor); - PR_ExitMonitor(m_dataAvailableMonitor); - } + PR_ExitMonitor(m_dataAvailableMonitor); + } + + // suspend this request until we've read from the input stream + NS_ASSERTION(m_pump == request, "unexpected request"); + request->Suspend(); + m_pumpSuspended = PR_TRUE; } - return res; + return NS_OK; } NS_IMETHODIMP nsImapProtocol::OnStartRequest(nsIRequest *request, nsISupports *ctxt) @@ -1466,7 +1514,6 @@ NS_IMETHODIMP nsImapProtocol::OnStartRequest(nsIRequest *request, nsISupports *c // stop binding is a "notification" informing us that the stream associated with aURL is going away. NS_IMETHODIMP nsImapProtocol::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult aStatus) { - PRBool killThread = PR_TRUE; // we always want to kill the thread, I believe. if (NS_FAILED(aStatus)) @@ -1509,14 +1556,14 @@ NS_IMETHODIMP nsImapProtocol::OnStopRequest(nsIRequest *request, nsISupports *ct } PR_CEnterMonitor(this); - mAsyncReadRequest = nsnull; // don't need to cache this anymore, it's going away + m_pump = nsnull; // don't need to cache this anymore, it's going away if (killThread == PR_TRUE) { ClearFlag(IMAP_CONNECTION_IS_OPEN); TellThreadToDie(PR_FALSE); } - m_channel = nsnull; + m_transport = nsnull; m_outputStream = nsnull; m_inputStream = nsnull; PR_CExitMonitor(this); @@ -1558,10 +1605,9 @@ NS_IMETHODIMP nsImapProtocol::GetRunningImapURL(nsIImapUrl **aImapUrl) nsresult nsImapProtocol::SendData(const char * dataBuffer, PRBool aSuppressLogging) { - PRUint32 writeCount = 0; nsresult rv = NS_ERROR_NULL_POINTER; - if (!m_channel) + if (!m_transport) { // the connection died unexpectedly! so clear the open connection flag ClearFlag(IMAP_CONNECTION_IS_OPEN); @@ -1577,7 +1623,10 @@ nsresult nsImapProtocol::SendData(const char * dataBuffer, PRBool aSuppressLoggi Log("SendData", nsnull, dataBuffer); else Log("SendData", nsnull, "Logging suppressed for this command (it probably contained authentication information)"); - rv = m_outputStream->Write(dataBuffer, PL_strlen(dataBuffer), &writeCount); + + PRUint32 n; + rv = m_outputStream->Write(dataBuffer, PL_strlen(dataBuffer), &n); + if (NS_FAILED(rv)) { // the connection died unexpectedly! so clear the open connection flag @@ -1615,7 +1664,7 @@ nsresult nsImapProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer) if (NS_FAILED(rv)) return rv; SetupSinkProxy(); // generate proxies for all of the event sinks in the url m_lastActiveTime = PR_Now(); - if (m_channel && m_runningUrl) + if (m_transport && m_runningUrl) { nsImapAction imapAction; m_runningUrl->GetImapAction(&imapAction); @@ -1650,7 +1699,7 @@ NS_IMETHODIMP nsImapProtocol::IsBusy(PRBool *aIsConnectionBusy, nsresult rv = NS_OK; *aIsConnectionBusy = PR_FALSE; *isInboxConnection = PR_FALSE; - if (!m_channel) + if (!m_transport) { // ** jt -- something is really wrong kill the thread TellThreadToDie(PR_FALSE); @@ -1694,7 +1743,7 @@ NS_IMETHODIMP nsImapProtocol::CanHandleUrl(nsIImapUrl * aImapUrl, PRBool isBusy = PR_FALSE; PRBool isInboxConnection = PR_FALSE; - if (!m_channel) + if (!m_transport) { // *** jt -- something is really wrong; it could be the dialer gave up // the connection or ip binding has been release by the operating @@ -4045,9 +4094,20 @@ char* nsImapProtocol::CreateNewLineFromSocket() { m_eventQueue->ProcessPendingEvents(); newLine = m_inputStreamBuffer->ReadNextLine(m_inputStream, numBytesInLine, needMoreData); + + PR_LOG(IMAP, PR_LOG_DEBUG, ("ReadNextLine [stream=%x nb=%u needmore=%u]\n", + m_inputStream.get(), numBytesInLine, needMoreData)); + if (needMoreData) { SetFlag(IMAP_WAITING_FOR_DATA); + + if (m_pump && m_pumpSuspended) + { + m_pump->Resume(); + m_pumpSuspended = PR_FALSE; + } + // we want to put this thread to rest until the on data available monitor goes off.. // so sleep until the timeout hits, then pump some events. This may cause the IMAP_WAITING_FOR_DATA // flag to get cleared which means data has arrived so we can kick out of the loop or the @@ -7374,6 +7434,7 @@ NS_INTERFACE_MAP_BEGIN(nsImapMockChannel) NS_INTERFACE_MAP_ENTRY(nsIChannel) NS_INTERFACE_MAP_ENTRY(nsIRequest) NS_INTERFACE_MAP_ENTRY(nsICacheListener) + NS_INTERFACE_MAP_ENTRY(nsITransportEventSink) NS_INTERFACE_MAP_END_THREADSAFE @@ -7589,19 +7650,14 @@ nsImapMockChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry, nsCache nsCOMPtr tee = do_CreateInstance(kStreamListenerTeeCID, &rv); if (NS_SUCCEEDED(rv)) { - nsCOMPtr transport; - rv = entry->GetTransport(getter_AddRefs(transport)); + nsCOMPtr out; + // this will fail with the mem cache turned off, so we need to fall through + // to ReadFromImapConnection instead of aborting with NS_ENSURE_SUCCESS(rv,rv) + rv = entry->OpenOutputStream(0, getter_AddRefs(out)); if (NS_SUCCEEDED(rv)) { - nsCOMPtr out; - // this will fail with the mem cache turned off, so we need to fall through - // to ReadFromImapConnection instead of aborting with NS_ENSURE_SUCCESS(rv,rv) - rv = transport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(out)); - if (NS_SUCCEEDED(rv)) - { - rv = tee->Init(m_channelListener, out); - m_channelListener = do_QueryInterface(tee); - } + rv = tee->Init(m_channelListener, out); + m_channelListener = do_QueryInterface(tee); } } } @@ -7701,36 +7757,41 @@ nsresult nsImapMockChannel::ReadFromMemCache(nsICacheEntryDescriptor *entry) } if (shouldUseCacheEntry) { - nsCOMPtr cacheTransport; - rv = entry->GetTransport(getter_AddRefs(cacheTransport)); - if (NS_SUCCEEDED(rv)) + nsCOMPtr in; + rv = entry->OpenInputStream(0, getter_AddRefs(in)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), in); + if (NS_FAILED(rv)) return rv; + + // if we are going to read from the cache, then create a mock stream listener class and use it + nsImapCacheStreamListener * cacheListener = new nsImapCacheStreamListener(); + NS_ADDREF(cacheListener); + cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this)); + rv = pump->AsyncRead(cacheListener, m_channelContext); + NS_RELEASE(cacheListener); + + if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return { - // if we are going to read from the cache, then create a mock stream listener class and use it - nsImapCacheStreamListener * cacheListener = new nsImapCacheStreamListener(); - NS_ADDREF(cacheListener); - cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this)); - rv = cacheTransport->AsyncRead(cacheListener, m_channelContext, 0, PRUint32(-1), 0, getter_AddRefs(mCacheRequest)); - NS_RELEASE(cacheListener); + mCacheRequest = pump; - if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return - { - nsCOMPtr imapUrl = do_QueryInterface(m_url); + nsCOMPtr imapUrl = do_QueryInterface(m_url); - // if the msg is unread, we should mark it read on the server. This lets - // the code running this url we're loading from the cache, if it cares. - imapUrl->SetMsgLoadingFromCache(PR_TRUE); + // if the msg is unread, we should mark it read on the server. This lets + // the code running this url we're loading from the cache, if it cares. + imapUrl->SetMsgLoadingFromCache(PR_TRUE); - // and force the url to remove its reference on the mock channel...this is to solve - // a nasty reference counting problem... - imapUrl->SetMockChannel(nsnull); + // and force the url to remove its reference on the mock channel...this is to solve + // a nasty reference counting problem... + imapUrl->SetMockChannel(nsnull); - // be sure to set the cache entry's security info status as our security info status... - nsCOMPtr securityInfo; - entry->GetSecurityInfo(getter_AddRefs(securityInfo)); - SetSecurityInfo(securityInfo); - return NS_OK; - } // if AsyncRead succeeded. - } // if get transport succeeded + // be sure to set the cache entry's security info status as our security info status... + nsCOMPtr securityInfo; + entry->GetSecurityInfo(getter_AddRefs(securityInfo)); + SetSecurityInfo(securityInfo); + return NS_OK; + } // if AsyncRead succeeded. } // if contnet is not modified else rv = NS_ERROR_FAILURE; // content is modified so return an error so we try to open it the old fashioned way @@ -7791,13 +7852,13 @@ PRBool nsImapMockChannel::ReadFromLocalCache() if (folder && NS_SUCCEEDED(rv)) { // we want to create a file channel and read the msg from there. - nsCOMPtr fileChannel; + nsCOMPtr fileStream; nsMsgKey msgKey = atoi(messageIdString); PRUint32 size, offset; - rv = folder->GetOfflineFileTransport(msgKey, &offset, &size, getter_AddRefs(fileChannel)); + rv = folder->GetOfflineFileStream(msgKey, &offset, &size, getter_AddRefs(fileStream)); // get the file channel from the folder, somehow (through the message or // folder sink?) We also need to set the transfer offset to the message offset - if (fileChannel && NS_SUCCEEDED(rv)) + if (fileStream && NS_SUCCEEDED(rv)) { // dougt - This may break the ablity to "cancel" a read from offline mail reading. // fileChannel->SetLoadGroup(m_loadGroup); @@ -7809,8 +7870,13 @@ PRBool nsImapMockChannel::ReadFromLocalCache() nsImapCacheStreamListener * cacheListener = new nsImapCacheStreamListener(); NS_ADDREF(cacheListener); cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this)); - nsCOMPtr request; - rv = fileChannel->AsyncRead(cacheListener, m_channelContext, offset, size, 0, getter_AddRefs(request)); + + // create a stream pump that will async read the specified amount of data. + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), fileStream, offset, size); + if (NS_SUCCEEDED(rv)) + rv = pump->AsyncRead(cacheListener, m_channelContext); + NS_RELEASE(cacheListener); if (NS_SUCCEEDED(rv)) // ONLY if we succeeded in actually starting the read should we return @@ -8082,3 +8148,26 @@ nsImapMockChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotification return NS_OK; } + +NS_IMETHODIMP +nsImapMockChannel::OnTransportStatus(nsITransport *transport, nsresult status, + PRUint32 progress, PRUint32 progressMax) +{ + if (mProgressEventSink && !(mLoadFlags & LOAD_BACKGROUND)) + { + // these transport events should not generate any status messages + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + status == nsISocketTransport::STATUS_SENDING_TO) + { + mProgressEventSink->OnProgress(this, nsnull, progress, progressMax); + } + else + { + nsCAutoString host; + if (m_url) + m_url->GetHost(host); + mProgressEventSink->OnStatus(this, nsnull, status, NS_ConvertUTF8toUCS2(host).get()); + } + } + return NS_OK; +} diff --git a/mozilla/mailnews/imap/src/nsImapProtocol.h b/mozilla/mailnews/imap/src/nsImapProtocol.h index 8f4c22acdbe..0abcc10d192 100644 --- a/mozilla/mailnews/imap/src/nsImapProtocol.h +++ b/mozilla/mailnews/imap/src/nsImapProtocol.h @@ -51,7 +51,8 @@ #include "nsIProgressEventSink.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsITransport.h" +#include "nsISocketTransport.h" +#include "nsIInputStreamPump.h" // imap event sinks #include "nsIImapMailFolderSink.h" @@ -390,16 +391,18 @@ private: nsCAutoString m_trashFolderName; // Ouput stream for writing commands to the socket - nsCOMPtr m_channel; - nsCOMPtr m_outputStream; // this will be obtained from the transport interface - nsCOMPtr m_inputStream; + nsCOMPtr m_transport; + nsCOMPtr m_outputStream; // this will be obtained from the transport interface + nsCOMPtr m_inputStream; + nsCOMPtr m_pump; + PRBool m_pumpSuspended; nsCOMPtr m_channelInputStream; nsCOMPtr m_channelOutputStream; nsCOMPtr m_channelListener; // if we are displaying an article this is the rfc-822 display sink... nsCOMPtr m_channelContext; nsCOMPtr m_mockChannel; // this is the channel we should forward to people - nsCOMPtr mAsyncReadRequest; // we're going to cancel this when we're done with the conn. + //nsCOMPtr mAsyncReadRequest; // we're going to cancel this when we're done with the conn. // this is a method designed to buffer data coming from the input stream and efficiently extract out @@ -669,7 +672,9 @@ private: class nsICacheEntryDescriptor; -class nsImapMockChannel : public nsIImapMockChannel, public nsICacheListener +class nsImapMockChannel : public nsIImapMockChannel + , public nsICacheListener + , public nsITransportEventSink { public: @@ -678,6 +683,7 @@ public: NS_DECL_NSICHANNEL NS_DECL_NSIREQUEST NS_DECL_NSICACHELISTENER + NS_DECL_NSITRANSPORTEVENTSINK nsImapMockChannel(); virtual ~nsImapMockChannel(); diff --git a/mozilla/mailnews/import/comm4x/src/nsComm4xProfile.cpp b/mozilla/mailnews/import/comm4x/src/nsComm4xProfile.cpp index 4110da00bcd..38eeaa41ba1 100644 --- a/mozilla/mailnews/import/comm4x/src/nsComm4xProfile.cpp +++ b/mozilla/mailnews/import/comm4x/src/nsComm4xProfile.cpp @@ -42,6 +42,7 @@ #include "nsILineInputStream.h" #include "nsReadableUtils.h" #include "nsIPrefMigration.h" +#include "nsNetCID.h" nsComm4xProfile::nsComm4xProfile() diff --git a/mozilla/mailnews/local/src/nsMailboxProtocol.cpp b/mozilla/mailnews/local/src/nsMailboxProtocol.cpp index aa788b74ba2..8b71931c3f6 100644 --- a/mozilla/mailnews/local/src/nsMailboxProtocol.cpp +++ b/mozilla/mailnews/local/src/nsMailboxProtocol.cpp @@ -61,11 +61,10 @@ #include "nsFileStream.h" PRLogModuleInfo *MAILBOX; -#include "nsIFileChannel.h" #include "nsIFileStreams.h" +#include "nsIStreamTransportService.h" #include "nsIStreamConverterService.h" #include "nsIIOService.h" -#include "nsIFileTransportService.h" #include "nsXPIDLString.h" #include "nsNetUtil.h" #include "nsIMsgWindow.h" @@ -128,44 +127,42 @@ NS_IMETHODIMP nsMailboxProtocol::GetContentLength(PRInt32 * aContentLength) return NS_OK; } +nsresult nsMailboxProtocol::OpenMultipleMsgTransport(PRUint32 offset, PRInt32 size) +{ + nsresult rv; + + NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); + nsCOMPtr serv = + do_GetService(kStreamTransportServiceCID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = serv->CreateInputTransport(m_multipleMsgMoveCopyStream, offset, size, PR_FALSE, getter_AddRefs(m_transport)); + + return rv; +} + nsresult nsMailboxProtocol::OpenFileSocketForReuse(nsIURI * aURL, PRUint32 aStartPosition, PRInt32 aReadCount) { NS_ENSURE_ARG_POINTER(aURL); nsresult rv = NS_OK; - m_startPosition = aStartPosition; m_readCount = aReadCount; nsCOMPtr file; rv = GetFileFromURL(aURL, getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); - - NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); - - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr fileStream = do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv); + nsCOMPtr fileStream = do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); m_multipleMsgMoveCopyStream = do_QueryInterface(fileStream, &rv); NS_ENSURE_SUCCESS(rv, rv); fileStream->Init(file, PR_RDONLY, 0664, PR_FALSE); //just have to read the messages - PRUint32 length; - PRInt64 fileSize; - rv = file->GetFileSize( &fileSize); - LL_L2UI( length, fileSize ); - // probably should pass in the file size instead of aReadCount - rv = fts->CreateTransportFromStream(NS_LITERAL_CSTRING("mailbox"), - m_multipleMsgMoveCopyStream, - NS_LITERAL_CSTRING(""), - NS_LITERAL_CSTRING(""), - length, PR_FALSE, getter_AddRefs(m_transport)); + rv = OpenMultipleMsgTransport(aStartPosition, aReadCount); + m_socketIsOpen = PR_FALSE; - return rv; } @@ -329,8 +326,32 @@ NS_IMETHODIMP nsMailboxProtocol::OnStopRequest(nsIRequest *request, nsISupports // basically re-initialize the transport with the correct message size. // then, we have to make sure the url keeps running somehow. nsCOMPtr urlSupports = do_QueryInterface(m_runningUrl); + // // put us in a state where we are always notified of incoming data - rv = m_transport->AsyncRead(this, urlSupports, msgKey, msgSize, 0, getter_AddRefs(m_request)); + // + + m_transport = 0; // open new stream transport + m_inputStream = 0; + m_outputStream = 0; + + rv = OpenMultipleMsgTransport(msgKey, msgSize); + if (NS_SUCCEEDED(rv)) + { + if (!m_inputStream) + rv = m_transport->OpenInputStream(0, 0, 0, getter_AddRefs(m_inputStream)); + + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), m_inputStream); + if (NS_SUCCEEDED(rv)) { + rv = pump->AsyncRead(this, urlSupports); + if (NS_SUCCEEDED(rv)) + m_request = pump; + } + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncRead failed"); if (m_loadGroup) m_loadGroup->RemoveRequest(NS_STATIC_CAST(nsIRequest *, this), nsnull, aStatus); @@ -795,3 +816,4 @@ nsresult nsMailboxProtocol::CloseSocket() return 0; } +// vim: ts=2 sw=2 diff --git a/mozilla/mailnews/local/src/nsMailboxProtocol.h b/mozilla/mailnews/local/src/nsMailboxProtocol.h index b8474ffa3fa..8c6a75bf3f0 100644 --- a/mozilla/mailnews/local/src/nsMailboxProtocol.h +++ b/mozilla/mailnews/local/src/nsMailboxProtocol.h @@ -127,6 +127,7 @@ private: virtual nsresult CloseSocket(); PRInt32 SetupMessageExtraction(); + nsresult OpenMultipleMsgTransport(PRUint32 offset, PRInt32 size); nsresult OpenFileSocketForReuse(nsIURI * aURL, PRUint32 aStartPosition, PRInt32 aReadCount); PRBool RunningMultipleMsgUrl(); diff --git a/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp b/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp index 5e3a63579d7..86ab398f60d 100644 --- a/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp +++ b/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp @@ -78,8 +78,6 @@ NS_IMPL_THREADSAFE_RELEASE(nsMimeBaseEmitter) NS_INTERFACE_MAP_BEGIN(nsMimeBaseEmitter) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMimeEmitter) NS_INTERFACE_MAP_ENTRY(nsIMimeEmitter) - NS_INTERFACE_MAP_ENTRY(nsIInputStreamObserver) - NS_INTERFACE_MAP_ENTRY(nsIOutputStreamObserver) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_END @@ -345,51 +343,6 @@ nsMimeBaseEmitter::LocalizeHeaderName(const char *aHeaderName, const char *aDefa return nsCRT::strdup(aDefaultName); } -/////////////////////////////////////////////////////////////////////////// -// nsIPipeObserver Interface -/////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP nsMimeBaseEmitter::OnWrite(nsIOutputStream* out, PRUint32 aCount) -{ - return NS_OK; -} - -NS_IMETHODIMP nsMimeBaseEmitter::OnEmpty(nsIInputStream* in) -{ - return NS_OK; -} - - -NS_IMETHODIMP nsMimeBaseEmitter::OnFull(nsIOutputStream* out) -{ - // the pipe is full so we should flush our data to the converter's listener - // in order to make more room. - - // since we only have one pipe per mime emitter, i can ignore the pipe param and use - // my outStream object directly (it will be the same thing as what we'd get from aPipe. - - nsresult rv = NS_OK; - if (mOutListener && mInputStream) - { - PRUint32 bytesAvailable = 0; - rv = mInputStream->Available(&bytesAvailable); - NS_ASSERTION(NS_SUCCEEDED(rv), "Available failed"); - - nsCOMPtr request = do_QueryInterface(mChannel); - - rv = mOutListener->OnDataAvailable(request, mURL, mInputStream, 0, bytesAvailable); - } - else - rv = NS_ERROR_NULL_POINTER; - - return rv; -} - -NS_IMETHODIMP nsMimeBaseEmitter::OnClose(nsIInputStream* in) -{ - return NS_OK; -} - /////////////////////////////////////////////////////////////////////////// // nsMimeBaseEmitter Interface /////////////////////////////////////////////////////////////////////////// @@ -537,8 +490,7 @@ nsMimeBaseEmitter::Write(const char *buf, PRUint32 size, PRUint32 *amountWritten // First, handle any old buffer data... if (needToWrite > 0) { - rv = mOutStream->Write(mBufferMgr->GetBuffer(), - needToWrite, &written); + rv = WriteHelper(mBufferMgr->GetBuffer(), needToWrite, &written); mTotalWritten += written; mBufferMgr->ReduceBuffer(written); @@ -556,7 +508,7 @@ nsMimeBaseEmitter::Write(const char *buf, PRUint32 size, PRUint32 *amountWritten // if we get here, we are dealing with new data...try to write // and then do the right thing... - rv = mOutStream->Write(buf, size, &written); + rv = WriteHelper(buf, size, &written); *amountWritten = written; mTotalWritten += written; @@ -566,6 +518,26 @@ nsMimeBaseEmitter::Write(const char *buf, PRUint32 size, PRUint32 *amountWritten return rv; } +nsresult +nsMimeBaseEmitter::WriteHelper(const char *buf, PRUint32 count, PRUint32 *countWritten) +{ + nsresult rv; + + rv = mOutStream->Write(buf, count, countWritten); + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + // pipe is full, push contents of pipe to listener... + PRUint32 avail; + rv = mInputStream->Available(&avail); + if (NS_SUCCEEDED(rv) && avail) { + mOutListener->OnDataAvailable(mChannel, mURL, mInputStream, 0, avail); + + // try writing again... + rv = mOutStream->Write(buf, count, countWritten); + } + } + return rv; +} + // // Find a cached header! Note: Do NOT free this value! // diff --git a/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.h b/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.h index 8b970cce22c..b9ca12fc187 100644 --- a/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.h +++ b/mozilla/mailnews/mime/emitters/src/nsMimeBaseEmitter.h @@ -44,8 +44,7 @@ #include "nsIStreamListener.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" -#include "nsIObservableInputStream.h" -#include "nsIObservableOutputStream.h" +#include "nsIAsyncInputStream.h" #include "nsIURI.h" #include "nsIPref.h" #include "nsIChannel.h" @@ -87,9 +86,7 @@ typedef struct { } headerInfoType; class nsMimeBaseEmitter : public nsIMimeEmitter, - public nsIInterfaceRequestor, - public nsIInputStreamObserver, - public nsIOutputStreamObserver + public nsIInterfaceRequestor { public: nsMimeBaseEmitter (); @@ -99,8 +96,6 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIMIMEEMITTER - NS_DECL_NSIINPUTSTREAMOBSERVER - NS_DECL_NSIOUTPUTSTREAMOBSERVER NS_DECL_NSIINTERFACEREQUESTOR // Utility output functions... @@ -129,6 +124,8 @@ protected: nsresult DumpRestOfHeaders(); nsresult OutputGenericHeader(const char *aHeaderVal); + nsresult WriteHelper(const char *buf, PRUint32 count, PRUint32 *countWritten); + // For string bundle usage... nsCOMPtr m_stringBundle; // for translated strings nsCOMPtr m_headerStringBundle; // for non-translated header strings diff --git a/mozilla/mailnews/mime/src/mimemoz2.cpp b/mozilla/mailnews/mime/src/mimemoz2.cpp index 61974f30f1e..df9ea13a14f 100644 --- a/mozilla/mailnews/mime/src/mimemoz2.cpp +++ b/mozilla/mailnews/mime/src/mimemoz2.cpp @@ -1121,15 +1121,12 @@ mime_image_begin(const char *image_url, const char *content_type, { mailUrl->CacheCacheEntry(entry); entry->MarkValid(); - nsCOMPtr transport; - rv = entry->GetTransport(getter_AddRefs(transport)); - if (NS_FAILED(rv)) return nsnull; // remember the content type as meta data so we can pull it out in the imap code // to feed the cache entry directly to imglib w/o going through mime. entry->SetMetaDataElement("contentType", content_type); - nsCOMPtr out; - rv = transport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(mid->memCacheOutputStream)); + + rv = entry->OpenOutputStream(0, getter_AddRefs(mid->memCacheOutputStream)); if (NS_FAILED(rv)) return nsnull; } } diff --git a/mozilla/mailnews/mime/src/nsStreamConverter.cpp b/mozilla/mailnews/mime/src/nsStreamConverter.cpp index 1fbb1cdae54..177ffe5f871 100644 --- a/mozilla/mailnews/mime/src/nsStreamConverter.cpp +++ b/mozilla/mailnews/mime/src/nsStreamConverter.cpp @@ -70,8 +70,8 @@ #include "nsICategoryManager.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIObservableInputStream.h" -#include "nsIObservableOutputStream.h" +#include "nsIAsyncInputStream.h" +#include "nsIAsyncOutputStream.h" #define PREF_MAIL_DISPLAY_GLYPH "mail.display_glyph" #define PREF_MAIL_DISPLAY_STRUCT "mail.display_struct" @@ -699,22 +699,6 @@ NS_IMETHODIMP nsStreamConverter::Init(nsIURI *aURI, nsIStreamListener * aOutList NS_STREAM_CONVERTER_BUFFER_SIZE, PR_TRUE, PR_TRUE); - if (NS_SUCCEEDED(rv)) - { - nsCOMPtr inObs = do_GetInterface(mEmitter, &rv); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr observableIn(do_QueryInterface(mInputStream, &rv)); - if (NS_SUCCEEDED(rv)) - observableIn->SetObserver(inObs); - } - nsCOMPtr outObs = do_GetInterface(mEmitter, &rv); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr observableOut(do_QueryInterface(mOutputStream, &rv)); - if (NS_SUCCEEDED(rv)) - observableOut->SetObserver(outObs); - } - } - // initialize our emitter if (NS_SUCCEEDED(rv) && mEmitter) { diff --git a/mozilla/mailnews/news/src/nsNNTPProtocol.cpp b/mozilla/mailnews/news/src/nsNNTPProtocol.cpp index d4f0400a108..b89411d161c 100644 --- a/mozilla/mailnews/news/src/nsNNTPProtocol.cpp +++ b/mozilla/mailnews/news/src/nsNNTPProtocol.cpp @@ -795,11 +795,15 @@ nsresult nsNNTPProtocol::ReadFromMemCache(nsICacheEntryDescriptor *entry) { NS_ENSURE_ARG(entry); - nsCOMPtr cacheTransport; - nsresult rv = entry->GetTransport(getter_AddRefs(cacheTransport)); + nsCOMPtr cacheStream; + nsresult rv = entry->OpenInputStream(0, getter_AddRefs(cacheStream)); if (NS_SUCCEEDED(rv)) { + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), cacheStream); + if (NS_FAILED(rv)) return rv; + nsXPIDLCString group; nsXPIDLCString commandSpecificData; // do this to get m_key set, so that marking the message read will work. @@ -815,9 +819,9 @@ nsresult nsNNTPProtocol::ReadFromMemCache(nsICacheEntryDescriptor *entry) nsCOMPtr mailnewsUrl = do_QueryInterface(m_runningURL); cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this), mailnewsUrl); - nsCOMPtr request; m_ContentType = ""; // reset the content type for the upcoming read.... - rv = cacheTransport->AsyncRead(cacheListener, m_channelContext, 0, PRUint32(-1), 0, getter_AddRefs(request)); + + rv = pump->AsyncRead(cacheListener, m_channelContext); NS_RELEASE(cacheListener); MarkCurrentMsgRead(); @@ -857,23 +861,30 @@ PRBool nsNNTPProtocol::ReadFromLocalCache() if (folder && NS_SUCCEEDED(rv)) { // we want to create a file channel and read the msg from there. - nsCOMPtr fileChannel; + nsCOMPtr fileStream; PRUint32 offset=0, size=0; - rv = folder->GetOfflineFileTransport(m_key, &offset, &size, getter_AddRefs(fileChannel)); + rv = folder->GetOfflineFileStream(m_key, &offset, &size, getter_AddRefs(fileStream)); - // get the file channel from the folder, somehow (through the message or + // get the file stream from the folder, somehow (through the message or // folder sink?) We also need to set the transfer offset to the message offset - if (fileChannel && NS_SUCCEEDED(rv)) + if (fileStream && NS_SUCCEEDED(rv)) { // dougt - This may break the ablity to "cancel" a read from offline mail reading. // fileChannel->SetLoadGroup(m_loadGroup); m_typeWanted = ARTICLE_WANTED; + nsNntpCacheStreamListener * cacheListener = new nsNntpCacheStreamListener(); NS_ADDREF(cacheListener); cacheListener->Init(m_channelListener, NS_STATIC_CAST(nsIChannel *, this), mailnewsUrl); - nsCOMPtr request; - rv = fileChannel->AsyncRead(cacheListener, m_channelContext, offset, size, 0, getter_AddRefs(request)); + + // create a stream pump that will async read the specified amount of data. + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), + fileStream, offset, size); + if (NS_SUCCEEDED(rv)) + rv = pump->AsyncRead(cacheListener, m_channelContext); + NS_RELEASE(cacheListener); MarkCurrentMsgRead(); @@ -909,12 +920,8 @@ nsNNTPProtocol::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry, nsCacheAcc nsCOMPtr tee = do_CreateInstance(kStreamListenerTeeCID, &rv); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr transport; - rv = entry->GetTransport(getter_AddRefs(transport)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr out; - rv = transport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(out)); + rv = entry->OpenOutputStream(0, getter_AddRefs(out)); NS_ENSURE_SUCCESS(rv, rv); rv = tee->Init(m_channelListener, out); diff --git a/mozilla/modules/libjar/nsIJARChannel.idl b/mozilla/modules/libjar/nsIJARChannel.idl index 56ad867e1a4..85832c259a4 100644 --- a/mozilla/modules/libjar/nsIJARChannel.idl +++ b/mozilla/modules/libjar/nsIJARChannel.idl @@ -37,16 +37,7 @@ #include "nsIChannel.idl" -interface nsISimpleEnumerator; - [scriptable, uuid(c7e410d1-85f2-11d3-9f63-006008a6efe9)] interface nsIJARChannel : nsIChannel { - /** - * Enumerates all the entries in the JAR (the root URI). - * ARGUMENTS: - * aRoot - a string representing the root dir to enumerate from - * or null to enumerate the whole thing. - */ - nsISimpleEnumerator EnumerateEntries(in string aRoot); }; diff --git a/mozilla/modules/libjar/nsJARChannel.cpp b/mozilla/modules/libjar/nsJARChannel.cpp index 814e42ba47a..630a903120c 100644 --- a/mozilla/modules/libjar/nsJARChannel.cpp +++ b/mozilla/modules/libjar/nsJARChannel.cpp @@ -17,409 +17,476 @@ * */ -#include "nsNetUtil.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" #include "nsJARChannel.h" -#include "nsCRT.h" -#include "nsIFileTransportService.h" -#include "nsIURI.h" -#include "nsIFileURL.h" -#include "nsCExternalHandlerService.h" -#include "nsIMIMEService.h" -#include "nsAutoLock.h" -#include "nsIFileStreams.h" +#include "nsJARProtocolHandler.h" #include "nsMimeTypes.h" +#include "nsNetUtil.h" + #include "nsScriptSecurityManager.h" #include "nsIAggregatePrincipal.h" -#include "nsIProgressEventSink.h" -#include "nsXPIDLString.h" -#include "nsReadableUtils.h" +#include "nsIFileURL.h" #include "nsIJAR.h" -#include "prthread.h" -static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); static NS_DEFINE_CID(kScriptSecurityManagerCID, NS_SCRIPTSECURITYMANAGER_CID); +static NS_DEFINE_CID(kInputStreamChannelCID, NS_INPUTSTREAMCHANNEL_CID); + +//----------------------------------------------------------------------------- #if defined(PR_LOGGING) // -// Log module for JarChannel logging... +// set NSPR_LOG_MODULES=nsJarProtocol:5 // -// To enable logging (see prlog.h for full details): -// -// set NSPR_LOG_MODULES=nsJarProtocol:5 -// set NSPR_LOG_FILE=nspr.log -// -// this enables PR_LOG_DEBUG level information and places all output in -// the file nspr.log -// -PRLogModuleInfo* gJarProtocolLog = nsnull; +static PRLogModuleInfo *gJarProtocolLog = nsnull; +#endif -#endif /* PR_LOGGING */ +#define LOG(args) PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, args) +#define LOG_ENABLED() PR_LOG_TEST(gJarProtocolLog, 4) -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsJARInputThunk +// +// this class allows us to do some extra work on the stream transport thread. +//----------------------------------------------------------------------------- -#define NS_DEFAULT_JAR_BUFFER_SEGMENT_SIZE (16*1024) -#define NS_DEFAULT_JAR_BUFFER_MAX_SIZE (256*1024) +class nsJARInputThunk : public nsIInputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + + nsJARInputThunk(nsIFile *jarFile, const nsACString &jarEntry, + nsIZipReaderCache *jarCache) + : mJarCache(jarCache) + , mJarFile(jarFile) + , mJarEntry(jarEntry) + { + NS_ASSERTION(mJarFile, "no jar file"); + } + virtual ~nsJARInputThunk() {} + + void GetJarReader(nsIZipReader **result) + { + NS_ADDREF(*result = mJarReader); + } + +private: + nsresult EnsureJarStream(); + + nsCOMPtr mJarCache; + nsCOMPtr mJarReader; + nsCOMPtr mJarFile; + nsCOMPtr mJarStream; + nsCString mJarEntry; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputThunk, nsIInputStream) + +nsresult +nsJARInputThunk::EnsureJarStream() +{ + if (mJarStream) + return NS_OK; + + nsresult rv = mJarCache->GetZip(mJarFile, getter_AddRefs(mJarReader)); + if (NS_FAILED(rv)) return rv; + + return mJarReader->GetInputStream(mJarEntry.get(), + getter_AddRefs(mJarStream)); +} + +NS_IMETHODIMP +nsJARInputThunk::Close() +{ + if (mJarStream) + return mJarStream->Close(); + + return NS_OK; +} + +NS_IMETHODIMP +nsJARInputThunk::Available(PRUint32 *avail) +{ + nsresult rv = EnsureJarStream(); + if (NS_FAILED(rv)) return rv; + + return mJarStream->Available(avail); +} + +NS_IMETHODIMP +nsJARInputThunk::Read(char *buf, PRUint32 count, PRUint32 *countRead) +{ + nsresult rv = EnsureJarStream(); + if (NS_FAILED(rv)) return rv; + + return mJarStream->Read(buf, count, countRead); +} + +NS_IMETHODIMP +nsJARInputThunk::ReadSegments(nsWriteSegmentFun writer, void *closure, + PRUint32 count, PRUint32 *countRead) +{ + // stream transport does only calls Read() + NS_NOTREACHED("nsJarInputThunk::ReadSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsJARInputThunk::IsNonBlocking(PRBool *nonBlocking) +{ + *nonBlocking = PR_FALSE; + return NS_OK; +} + +//----------------------------------------------------------------------------- nsJARChannel::nsJARChannel() - : mLoadFlags(LOAD_NORMAL) - , mContentLength(-1) + : mContentLength(-1) + , mLoadFlags(LOAD_NORMAL) , mStatus(NS_OK) -#ifdef DEBUG - , mInitiator(nsnull) -#endif + , mIsPending(PR_FALSE) + , mJarInput(nsnull) { #if defined(PR_LOGGING) - // - // Initialize the global PRLogModule for socket transport logging - // if necessary... - // - if (nsnull == gJarProtocolLog) { + if (!gJarProtocolLog) gJarProtocolLog = PR_NewLogModule("nsJarProtocol"); - } -#endif /* PR_LOGGING */ +#endif + + // hold an owning reference to the jar handler + NS_ADDREF(gJarHandler); } nsJARChannel::~nsJARChannel() { - NS_IF_RELEASE(mJARProtocolHandler); + // release owning reference to the jar handler + nsJARProtocolHandler *handler = gJarHandler; + NS_RELEASE(handler); // NULL parameter } -NS_IMPL_THREADSAFE_ISUPPORTS7(nsJARChannel, - nsIJARChannel, - nsIChannel, - nsIRequest, - nsIRequestObserver, - nsIStreamListener, - nsIStreamIO, - nsIDownloadObserver) +NS_IMPL_ISUPPORTS6(nsJARChannel, + nsIRequest, + nsIChannel, + nsIStreamListener, + nsIRequestObserver, + nsIDownloadObserver, + nsIJARChannel) -NS_METHOD -nsJARChannel::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +nsresult +nsJARChannel::Init(nsIURI *uri) { nsresult rv; + mJarURI = do_QueryInterface(uri, &rv); - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - - nsJARChannel* jarChannel = new nsJARChannel(); - if (jarChannel == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(jarChannel); - rv = jarChannel->QueryInterface(aIID, aResult); - NS_RELEASE(jarChannel); +#if defined(PR_LOGGING) + mJarURI->GetSpec(mSpec); +#endif return rv; } - -nsresult -nsJARChannel::Init(nsJARProtocolHandler* aHandler, nsIURI* uri) + +nsresult +nsJARChannel::CreateJarInput() { - nsresult rv; - mURI = do_QueryInterface(uri, &rv); + // important to pass a clone of the file since the nsIFile impl is not + // necessarily MT-safe + nsCOMPtr clonedFile; + nsresult rv = mJarFile->Clone(getter_AddRefs(clonedFile)); if (NS_FAILED(rv)) return rv; - NS_ADDREF(mJARProtocolHandler = aHandler); + mJarInput = new nsJARInputThunk(clonedFile, mJarEntry, gJarHandler->JarCache()); + if (!mJarInput) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mJarInput); return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIRequest methods +nsresult +nsJARChannel::EnsureJarInput(PRBool blocking) +{ + LOG(("nsJARChannel::EnsureJarInput [this=%x %s]\n", this, mSpec.get())); + + nsresult rv; + nsCOMPtr uri; + + rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI)); + if (NS_FAILED(rv)) return rv; + + rv = mJarURI->GetJAREntry(mJarEntry); + if (NS_FAILED(rv)) return rv; + + // try to get a nsIFile directly from the url, which will often succeed. + { + nsCOMPtr fileURL = do_QueryInterface(mJarBaseURI); + if (fileURL) + fileURL->GetFile(getter_AddRefs(mJarFile)); + } + + if (mJarFile) { + rv = CreateJarInput(); + } + 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), + mJarBaseURI, this, nsnull, PR_FALSE, + mLoadGroup, mCallbacks, mLoadFlags); + } + return rv; + +} + +//----------------------------------------------------------------------------- +// nsIRequest +//----------------------------------------------------------------------------- NS_IMETHODIMP nsJARChannel::GetName(nsACString &result) { - return mURI->GetSpec(result); + return mJarURI->GetSpec(result); } NS_IMETHODIMP -nsJARChannel::IsPending(PRBool* result) +nsJARChannel::IsPending(PRBool *result) { - NS_NOTREACHED("nsJARChannel::IsPending"); - return NS_ERROR_NOT_IMPLEMENTED; + *result = mIsPending; + return NS_OK; } NS_IMETHODIMP nsJARChannel::GetStatus(nsresult *status) { - *status = mStatus; + if (mPump && NS_SUCCEEDED(mStatus)) + mPump->GetStatus(status); + else + *status = mStatus; return NS_OK; } NS_IMETHODIMP nsJARChannel::Cancel(nsresult status) { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); - nsresult rv = NS_OK; - - if (mJarExtractionTransport) { - rv = mJarExtractionTransport->Cancel(status); - mJarExtractionTransport = nsnull; - } - mStatus = status; - return rv; + if (mPump) + return mPump->Cancel(status); + + NS_ASSERTION(!mIsPending, "need to implement cancel when downloading"); + return NS_OK; } NS_IMETHODIMP nsJARChannel::Suspend() { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - nsresult rv = NS_OK; + if (mPump) + return mPump->Suspend(); - if (mJarExtractionTransport) { - rv = mJarExtractionTransport->Suspend(); - } - - return rv; + NS_ASSERTION(!mIsPending, "need to implement suspend when downloading"); + return NS_OK; } NS_IMETHODIMP nsJARChannel::Resume() { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - nsresult rv = NS_OK; + if (mPump) + return mPump->Resume(); - if (mJarExtractionTransport) { - rv = mJarExtractionTransport->Resume(); - } - - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIChannel methods - -NS_IMETHODIMP -nsJARChannel::GetOriginalURI(nsIURI* *aOriginalURI) -{ - if (mOriginalURI) - *aOriginalURI = mOriginalURI; - else - *aOriginalURI = NS_STATIC_CAST(nsIURI*, mURI); - - NS_IF_ADDREF(*aOriginalURI); + NS_ASSERTION(!mIsPending, "need to implement resume when downloading"); return NS_OK; } NS_IMETHODIMP -nsJARChannel::SetOriginalURI(nsIURI* aOriginalURI) -{ - mOriginalURI = aOriginalURI; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetURI(nsIURI* *aURI) -{ - *aURI = mURI; - NS_ADDREF(*aURI); - return NS_OK; -} - -nsresult -nsJARChannel::OpenJARElement() -{ - nsresult rv; - nsAutoCMonitor mon(this); - rv = Open(); - if (NS_SUCCEEDED(rv)) - rv = GetInputStream(getter_AddRefs(mSynchronousInputStream)); - mon.Notify(); // wake up nsIChannel::Open - return rv; -} - -NS_IMETHODIMP -nsJARChannel::Open(nsIInputStream* *result) -{ - nsAutoCMonitor mon(this); - nsresult rv; - mSynchronousRead = PR_TRUE; - rv = EnsureJARFileAvailable(); - if (NS_FAILED(rv)) return rv; - if (mSynchronousInputStream == nsnull) - mon.Wait(); - if (!mSynchronousInputStream) - return NS_ERROR_FAILURE; - - *result = mSynchronousInputStream; // Result of GetInputStream called on transport thread - NS_ADDREF(*result); - mSynchronousInputStream = 0; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::AsyncOpen(nsIStreamListener* listener, nsISupports* ctxt) -{ - nsresult rv; - -#ifdef DEBUG - mInitiator = PR_GetCurrentThread(); -#endif - - mUserContext = ctxt; - mUserListener = listener; - mSynchronousRead = PR_FALSE; - - if (mLoadGroup) { - rv = mLoadGroup->AddRequest(this, nsnull); - if (NS_FAILED(rv)) return rv; - } - - rv = EnsureJARFileAvailable(); - if (NS_FAILED(rv) && mLoadGroup) - mLoadGroup->RemoveRequest(this, nsnull, rv); - return rv; -} - -nsresult -nsJARChannel::EnsureJARFileAvailable() -{ - nsresult rv; - -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCAutoString jarURLStr; - mURI->GetSpec(jarURLStr); - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: EnsureJARFileAvailable %s", jarURLStr.get())); - } -#endif - - rv = mURI->GetJARFile(getter_AddRefs(mJARBaseURI)); - if (NS_FAILED(rv)) return rv; - - rv = mURI->GetJAREntry(mJAREntry); - if (NS_FAILED(rv)) return rv; - - // try to get a nsIFile directly from the url, which will often succeed. - { - nsCOMPtr fileURL = do_QueryInterface(mJARBaseURI); - if (fileURL) - fileURL->GetFile(getter_AddRefs(mDownloadedJARFile)); - } - - if (mDownloadedJARFile) { - // after successfully downloading the jar file to the cache, - // start the extraction process: - if (mSynchronousRead) - rv = OpenJARElement(); - else - rv = AsyncReadJARElement(); - } - else { - rv = NS_NewDownloader(getter_AddRefs(mDownloader), - mJARBaseURI, this, nsnull, mSynchronousRead, - mLoadGroup, mCallbacks, mLoadFlags); - - // if DownloadComplete() was called early, need to release the reference. - if (mSynchronousRead && mSynchronousInputStream) - mDownloader = 0; - } - return rv; -} - -nsresult -nsJARChannel::AsyncReadJARElement() -{ - nsresult rv; - - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr jarTransport; - rv = fts->CreateTransportFromStreamIO(this, PR_TRUE, getter_AddRefs(jarTransport)); - if (NS_FAILED(rv)) return rv; - - if (mCallbacks) { - nsCOMPtr sink = do_GetInterface(mCallbacks); - if (sink) { - // XXX don't think that this is needed anymore - // jarTransport->SetProgressEventSink(sink); - } - } - -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCAutoString jarURLStr; - mURI->GetSpec(jarURLStr); - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: AsyncRead jar entry %s", jarURLStr.get())); - } -#endif - - rv = jarTransport->AsyncRead(this, nsnull, 0, PRUint32(-1), 0, - getter_AddRefs(mJarExtractionTransport)); - jarTransport = 0; - return rv; -} - -NS_IMETHODIMP -nsJARChannel::GetLoadFlags(PRUint32* aLoadFlags) +nsJARChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) { *aLoadFlags = mLoadFlags; return NS_OK; } NS_IMETHODIMP -nsJARChannel::SetLoadFlags(PRUint32 aLoadFlags) +nsJARChannel::SetLoadFlags(nsLoadFlags aLoadFlags) { mLoadFlags = aLoadFlags; return NS_OK; } NS_IMETHODIMP -nsJARChannel::GetContentType(nsACString &aContentType) +nsJARChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) { - nsresult rv = NS_OK; - if (mContentType.IsEmpty()) { - if (mJAREntry.IsEmpty()) - return NS_ERROR_NOT_AVAILABLE; - const char *ext = nsnull, *fileName = mJAREntry.get(); - PRInt32 len = mJAREntry.Length(); - for (PRInt32 i = len-1; i >= 0; i--) { - if (fileName[i] == '.') { - ext = &fileName[i + 1]; - break; - } - } - if (ext) { - nsIMIMEService* mimeServ = mJARProtocolHandler->GetCachedMimeService(); - if (mimeServ) { - nsXPIDLCString mimeType; - rv = mimeServ->GetTypeFromExtension(ext, getter_Copies(mimeType)); - if (NS_SUCCEEDED(rv)) - mContentType = mimeType; - } - } - else - rv = NS_ERROR_NOT_AVAILABLE; + NS_IF_ADDREF(*aLoadGroup = mLoadGroup); + return NS_OK; +} - if (NS_FAILED(rv)) { - mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); - rv = NS_OK; +NS_IMETHODIMP +nsJARChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) +{ + mLoadGroup = aLoadGroup; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// nsIChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsJARChannel::GetOriginalURI(nsIURI **aURI) +{ + if (mOriginalURI) + *aURI = mOriginalURI; + else + *aURI = mJarURI; + NS_IF_ADDREF(*aURI); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::SetOriginalURI(nsIURI *aURI) +{ + mOriginalURI = aURI; + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetURI(nsIURI **aURI) +{ + NS_IF_ADDREF(*aURI = mJarURI); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetOwner(nsISupports **result) +{ + nsresult rv; + + if (mOwner) { + NS_ADDREF(*result = mOwner); + return NS_OK; + } + + if (!mJarInput) { + *result = nsnull; + return NS_OK; + } + + //-- Verify signature, if one is present, and set owner accordingly + nsCOMPtr jarReader; + mJarInput->GetJarReader(getter_AddRefs(jarReader)); + if (!jarReader) + return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr jar = do_QueryInterface(jarReader, &rv); + if (NS_FAILED(rv)) { + NS_ERROR("nsIJAR not supported"); + return rv; + } + + nsCOMPtr cert; + rv = jar->GetCertificatePrincipal(mJarEntry.get(), getter_AddRefs(cert)); + if (NS_FAILED(rv)) return rv; + + if (cert) { + // Get the codebase principal + nsCOMPtr secMan = + do_GetService(kScriptSecurityManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr codebase; + rv = secMan->GetCodebasePrincipal(mJarBaseURI, + getter_AddRefs(codebase)); + if (NS_FAILED(rv)) return rv; + + // Join the certificate and the codebase + nsCOMPtr agg = do_QueryInterface(cert, &rv); + if (NS_FAILED(rv)) return rv; + + rv = agg->SetCodebase(codebase); + if (NS_FAILED(rv)) return rv; + + mOwner = do_QueryInterface(agg, &rv); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = mOwner); + } + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::SetOwner(nsISupports *aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) +{ + NS_IF_ADDREF(*aCallbacks = mCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) +{ + mCallbacks = aCallbacks; + mProgressSink = do_GetInterface(mCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo) +{ + *aSecurityInfo = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetContentType(nsACString &result) +{ + nsresult rv; + + if (!mContentType.IsEmpty()) { + result = mContentType; + return NS_OK; + } + + // + // generate content type and set it + // + if (mJarEntry.IsEmpty()) { + LOG(("mJarEntry is empty!\n")); + return NS_ERROR_NOT_AVAILABLE; + } + + const char *ext = nsnull, *fileName = mJarEntry.get(); + PRInt32 len = mJarEntry.Length(); + for (PRInt32 i = len-1; i >= 0; i--) { + if (fileName[i] == '.') { + ext = &fileName[i + 1]; + break; + } + } + if (ext) { + nsIMIMEService *mimeServ = gJarHandler->MimeService(); + if (mimeServ) { + nsXPIDLCString mimeType; + rv = mimeServ->GetTypeFromExtension(ext, getter_Copies(mimeType)); + if (NS_SUCCEEDED(rv)) + mContentType = mimeType; } } - if (NS_SUCCEEDED(rv)) - aContentType = mContentType; else - aContentType.Truncate(); - return rv; + rv = NS_ERROR_NOT_AVAILABLE; + + if (NS_FAILED(rv) || mContentType.IsEmpty()) + mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); + + result = mContentType; + return NS_OK; } NS_IMETHODIMP nsJARChannel::SetContentType(const nsACString &aContentType) { - mContentType = aContentType; + // mContentCharset is unchanged if not parsed + NS_ParseContentType(aContentType, mContentType, mContentCharset); return NS_OK; } @@ -438,274 +505,163 @@ nsJARChannel::SetContentCharset(const nsACString &aContentCharset) } NS_IMETHODIMP -nsJARChannel::GetContentLength(PRInt32* aContentLength) +nsJARChannel::GetContentLength(PRInt32 *result) { - NS_ENSURE_ARG_POINTER(aContentLength); - if (mContentLength == -1 && mJAR) { + if (mContentLength < 0 && mJarInput) { // ask the zip entry for the content length - nsresult rv; - nsCOMPtr entry; - rv = mJAR->GetEntry(mJAREntry.get(), getter_AddRefs(entry)); - if (NS_FAILED(rv)) return rv; - - rv = entry->GetRealSize((PRUint32*)&mContentLength); - if (NS_FAILED(rv)) return rv; + nsCOMPtr jarReader; + mJarInput->GetJarReader(getter_AddRefs(jarReader)); + if (jarReader) { + nsCOMPtr entry; + jarReader->GetEntry(mJarEntry.get(), getter_AddRefs(entry)); + if (entry) + entry->GetRealSize((PRUint32 *) &mContentLength); + } } - *aContentLength = mContentLength; + + *result = mContentLength; return NS_OK; } NS_IMETHODIMP nsJARChannel::SetContentLength(PRInt32 aContentLength) { - NS_NOTREACHED("nsJARChannel::SetContentLength"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsJARChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) -{ - *aLoadGroup = mLoadGroup; - NS_IF_ADDREF(*aLoadGroup); + // XXX does this really make any sense at all? + mContentLength = aContentLength; return NS_OK; } NS_IMETHODIMP -nsJARChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) +nsJARChannel::Open(nsIInputStream **stream) { - mLoadGroup = aLoadGroup; + LOG(("nsJARChannel::Open [this=%x]\n", this)); + + NS_ENSURE_TRUE(!mJarInput, NS_ERROR_IN_PROGRESS); + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + + nsresult rv = EnsureJarInput(PR_TRUE); + if (NS_FAILED(rv)) return rv; + + if (!mJarInput) + return NS_ERROR_UNEXPECTED; + + NS_ADDREF(*stream = mJarInput); return NS_OK; } NS_IMETHODIMP -nsJARChannel::GetOwner(nsISupports* *aOwner) +nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) { - nsresult rv; - if (mOwner == nsnull) { - //-- Verify signature, if one is present, and set owner accordingly - rv = EnsureZipReader(); + LOG(("nsJARChannel::AsyncOpen [this=%x]\n", this)); + + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + + nsresult rv = EnsureJarInput(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + if (mJarInput) { + // create input stream pump + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput); if (NS_FAILED(rv)) return rv; - nsCOMPtr jar = do_QueryInterface(mJAR, &rv); - NS_ASSERTION(NS_SUCCEEDED(rv), "Zip reader is not an nsIJAR"); - nsCOMPtr certificate; - rv = jar->GetCertificatePrincipal(mJAREntry.get(), - getter_AddRefs(certificate)); + rv = mPump->AsyncRead(this, nsnull); if (NS_FAILED(rv)) return rv; - if (certificate) - { // Get the codebase principal - nsCOMPtr secMan = - do_GetService(kScriptSecurityManagerCID, &rv); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - nsCOMPtr codebase; - rv = secMan->GetCodebasePrincipal(mJARBaseURI, - getter_AddRefs(codebase)); - if (NS_FAILED(rv)) return rv; - - // Join the certificate and the codebase - nsCOMPtr agg; - agg = do_QueryInterface(certificate, &rv); - rv = agg->SetCodebase(codebase); - if (NS_FAILED(rv)) return rv; - mOwner = do_QueryInterface(agg, &rv); - if (NS_FAILED(rv)) return rv; - } } - *aOwner = mOwner; - NS_IF_ADDREF(*aOwner); - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::SetOwner(nsISupports* aOwner) -{ - mOwner = aOwner; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) -{ - *aNotificationCallbacks = mCallbacks.get(); - NS_IF_ADDREF(*aNotificationCallbacks); - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) -{ - mCallbacks = aNotificationCallbacks; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) -{ - *aSecurityInfo = nsnull; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIDownloadObserver methods: - -NS_IMETHODIMP -nsJARChannel::OnDownloadComplete(nsIDownloader* aDownloader, nsISupports* aClosure, - nsresult aStatus, nsIFile* aFile) -{ - nsresult rv=aStatus; - if(NS_SUCCEEDED(aStatus)) { - NS_ASSERTION(!mDownloader ||(aDownloader == mDownloader.get()), "wrong downloader"); - mDownloadedJARFile = aFile; - // after successfully downloading the jar file to the cache, - // start the extraction process: - if (mSynchronousRead) - rv = OpenJARElement(); - else - rv = AsyncReadJARElement(); - } - mDownloader = 0; - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIRequestObserver methods: - -NS_IMETHODIMP -nsJARChannel::OnStartRequest(nsIRequest* jarExtractionTransport, - nsISupports* context) -{ -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - return mUserListener->OnStartRequest(this, mUserContext); -} - -NS_IMETHODIMP -nsJARChannel::OnStopRequest(nsIRequest* jarExtractionTransport, nsISupports* context, - nsresult aStatus) -{ - nsresult rv; -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCOMPtr jarURI; - nsCAutoString jarURLStr; - rv = mURI->GetSpec(jarURLStr); - if (NS_SUCCEEDED(rv)) { - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: jar extraction complete %s status=%x", - jarURLStr.get(), aStatus)); - } - } -#endif - - rv = mUserListener->OnStopRequest(this, mUserContext, aStatus); - NS_ASSERTION(NS_SUCCEEDED(rv), "OnStopRequest failed"); if (mLoadGroup) - mLoadGroup->RemoveRequest(this, context, aStatus); + mLoadGroup->AddRequest(this, nsnull); - mUserListener = nsnull; - mUserContext = nsnull; - mJarExtractionTransport = nsnull; - return rv; + mListener = listener; + mListenerContext = ctx; + mIsPending = PR_TRUE; + return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamListener methods: +//----------------------------------------------------------------------------- +// nsIDownloadObserver +//----------------------------------------------------------------------------- NS_IMETHODIMP -nsJARChannel::OnDataAvailable(nsIRequest* jarCacheTransport, - nsISupports* context, - nsIInputStream *inStr, - PRUint32 sourceOffset, - PRUint32 count) +nsJARChannel::OnDownloadComplete(nsIDownloader *downloader, + nsISupports *closure, + nsresult status, + nsIFile *file) { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - return mUserListener->OnDataAvailable(this, mUserContext, - inStr, sourceOffset, count); + if (NS_SUCCEEDED(status)) { + mJarFile = file; + + nsresult rv = CreateJarInput(); + if (NS_SUCCEEDED(rv)) { + // create input stream pump + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput); + if (NS_SUCCEEDED(rv)) + rv = mPump->AsyncRead(this, nsnull); + } + status = rv; + } + + if (NS_FAILED(status)) { + OnStartRequest(nsnull, nsnull); + OnStopRequest(nsnull, nsnull, status); + } + + mDownloader = 0; + return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamIO methods: +//----------------------------------------------------------------------------- +// nsIStreamListener +//----------------------------------------------------------------------------- -nsresult -nsJARChannel::EnsureZipReader() +NS_IMETHODIMP +nsJARChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx) { - if (mJAR == nsnull) { - nsresult rv; - if (mDownloadedJARFile == nsnull) - return NS_ERROR_FAILURE; + LOG(("nsJARChannel::OnStartRequest [this=%x %s]\n", this, mSpec.get())); - nsCOMPtr jarCache; - rv = mJARProtocolHandler->GetJARCache(getter_AddRefs(jarCache)); - if (NS_FAILED(rv)) return rv; + return mListener->OnStartRequest(this, mListenerContext); +} - rv = jarCache->GetZip(mDownloadedJARFile, getter_AddRefs(mJAR)); - if (NS_FAILED(rv)) return rv; +NS_IMETHODIMP +nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) +{ + LOG(("nsJARChannel::OnStopRequest [this=%x %s status=%x]\n", + this, mSpec.get(), status)); + + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + if (mListener) { + mListener->OnStopRequest(this, mListenerContext, status); + mListener = 0; + mListenerContext = 0; } + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, status); + + mPump = 0; + NS_IF_RELEASE(mJarInput); + mIsPending = PR_FALSE; return NS_OK; } NS_IMETHODIMP -nsJARChannel::Open() +nsJARChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, + PRUint32 offset, PRUint32 count) { - return EnsureZipReader(); -} - -NS_IMETHODIMP -nsJARChannel::Close(nsresult status) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetInputStream(nsIInputStream* *aInputStream) -{ -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCAutoString jarURLStr; - mURI->GetSpec(jarURLStr); - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: GetInputStream jar entry %s", jarURLStr.get())); - } +#if defined(PR_LOGGING) + LOG(("nsJARChannel::OnDataAvailable [this=%x %s]\n", this, mSpec.get())); #endif - NS_ENSURE_TRUE(mJAR, NS_ERROR_NULL_POINTER); - nsresult rv = mJAR->GetInputStream(mJAREntry.get(), aInputStream); - if (NS_SUCCEEDED(rv)) - (*aInputStream)->Available((PRUint32 *) &mContentLength); - return rv; -} - -NS_IMETHODIMP -nsJARChannel::GetOutputStream(nsIOutputStream* *aOutputStream) -{ - NS_NOTREACHED("nsJARChannel::GetOutputStream"); - return NS_ERROR_NOT_IMPLEMENTED; -} -NS_IMETHODIMP -nsJARChannel::GetName(char* *aName) -{ - nsCAutoString spec; - nsresult rv = mURI->GetSpec(spec); - if (NS_FAILED(rv)) return rv; - *aName = ToNewCString(spec); - return *aName ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + nsresult rv; + + rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); + + // simply report progress here instead of hooking ourselves up as a + // nsITransportEventSink implementation. + if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND)) + mProgressSink->OnProgress(this, nsnull, offset + count, mContentLength); + + return rv; // let the pump cancel on failure } - -//////////////////////////////////////////////////////////////////////////////// -// nsIJARChannel methods: - -NS_IMETHODIMP -nsJARChannel::EnumerateEntries(const char *aRoot, nsISimpleEnumerator **_retval) -{ - NS_NOTREACHED("nsJARChannel::EnumerateEntries"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/modules/libjar/nsJARChannel.h b/mozilla/modules/libjar/nsJARChannel.h index 89045eb094a..4d4d361962f 100644 --- a/mozilla/modules/libjar/nsJARChannel.h +++ b/mozilla/modules/libjar/nsJARChannel.h @@ -39,104 +39,70 @@ #define nsJARChannel_h__ #include "nsIJARChannel.h" -#include "nsIStreamListener.h" -#include "nsIJARProtocolHandler.h" #include "nsIJARURI.h" -#include "nsIStreamIO.h" -#include "nsIChannel.h" -#include "nsIZipReader.h" -#include "nsIChannel.h" -#include "nsILoadGroup.h" +#include "nsIInputStreamPump.h" #include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsCOMPtr.h" -#include "nsIFile.h" -#include "prmon.h" +#include "nsIProgressEventSink.h" +#include "nsIStreamListener.h" #include "nsIDownloader.h" -#include "nsIInputStream.h" -#include "nsJARProtocolHandler.h" +#include "nsILoadGroup.h" +#include "nsIFile.h" +#include "nsIURI.h" +#include "nsCOMPtr.h" #include "nsString.h" +#include "prlog.h" -#ifdef DEBUG -#include "prthread.h" -#endif +class nsJARInputThunk; -class nsIFileChannel; -class nsJARChannel; +//----------------------------------------------------------------------------- -#define NS_JARCHANNEL_CID \ -{ /* 0xc7e410d5-0x85f2-11d3-9f63-006008a6efe9 */ \ - 0xc7e410d5, \ - 0x85f2, \ - 0x11d3, \ - {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ -} - -class nsJARChannel : public nsIJARChannel, - public nsIStreamListener, - public nsIStreamIO, - public nsIDownloadObserver +class nsJARChannel : public nsIJARChannel + , public nsIDownloadObserver + , public nsIStreamListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL NS_DECL_NSIJARCHANNEL + NS_DECL_NSIDOWNLOADOBSERVER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIDOWNLOADOBSERVER - - // NS_DECL_NSISTREAMIO and nsIChannel both define (attribute string contentType) - - NS_IMETHOD Open(); - NS_IMETHOD Close(nsresult status); - NS_IMETHOD GetInputStream(nsIInputStream * *aInputStream); - NS_IMETHOD GetOutputStream(nsIOutputStream * *aOutputStream); - NS_IMETHOD GetName(char * *aName); nsJARChannel(); virtual ~nsJARChannel(); - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, REFNSIID aIID, void **aResult); + nsresult Init(nsIURI *uri); - nsresult Init(nsJARProtocolHandler* aHandler, nsIURI* uri); - nsresult EnsureJARFileAvailable(); - nsresult OpenJARElement(); - nsresult AsyncReadJARElement(); - nsresult EnsureZipReader(); +private: + nsresult CreateJarInput(); + nsresult EnsureJarInput(PRBool blocking); - friend class nsJARDownloadObserver; - -protected: - nsJARProtocolHandler* mJARProtocolHandler; - nsCOMPtr mURI; - nsCOMPtr mLoadGroup; - nsCOMPtr mCallbacks; - nsCOMPtr mOriginalURI; - nsLoadFlags mLoadFlags; - nsCOMPtr mOwner; - - nsCOMPtr mUserContext; - nsCOMPtr mUserListener; - - nsCString mContentType; - nsCString mContentCharset; - PRInt32 mContentLength; - nsCOMPtr mJARBaseURI; - nsCString mJAREntry; - nsCOMPtr mJAR; - nsCOMPtr mDownloadedJARFile; - nsresult mStatus; - PRBool mSynchronousRead; - nsCOMPtr mSynchronousInputStream; - - nsCOMPtr mDownloader; - nsCOMPtr mJarExtractionTransport; -#ifdef DEBUG - PRThread* mInitiator; +#if defined(PR_LOGGING) + nsCString mSpec; #endif + + nsCOMPtr mJarURI; + nsCOMPtr mOriginalURI; + nsCOMPtr mOwner; + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; + nsCOMPtr mLoadGroup; + nsCOMPtr mListener; + nsCOMPtr mListenerContext; + nsCString mContentType; + nsCString mContentCharset; + PRInt32 mContentLength; + PRUint32 mLoadFlags; + nsresult mStatus; + PRBool mIsPending; + + nsJARInputThunk *mJarInput; + nsCOMPtr mPump; + nsCOMPtr mDownloader; + nsCOMPtr mJarFile; + nsCOMPtr mJarBaseURI; + nsCString mJarEntry; }; #endif // nsJARChannel_h__ diff --git a/mozilla/modules/libjar/nsJARProtocolHandler.cpp b/mozilla/modules/libjar/nsJARProtocolHandler.cpp index 141a55ab015..24f18bd1eb5 100644 --- a/mozilla/modules/libjar/nsJARProtocolHandler.cpp +++ b/mozilla/modules/libjar/nsJARProtocolHandler.cpp @@ -52,12 +52,20 @@ static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID); -#define NS_JAR_CACHE_SIZE 32 +#define NS_JAR_CACHE_SIZE 32 -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- + +nsJARProtocolHandler *gJarHandler = nsnull; nsJARProtocolHandler::nsJARProtocolHandler() { + gJarHandler = this; +} + +nsJARProtocolHandler::~nsJARProtocolHandler() +{ + gJarHandler = nsnull; } nsresult @@ -74,17 +82,13 @@ nsJARProtocolHandler::Init() return rv; } -nsIMIMEService* -nsJARProtocolHandler::GetCachedMimeService() +nsIMIMEService * +nsJARProtocolHandler::MimeService() { - if (!mMimeService) { + if (!mMimeService) mMimeService = do_GetService(NS_MIMESERVICE_CONTRACTID); - } - return mMimeService.get(); -} -nsJARProtocolHandler::~nsJARProtocolHandler() -{ + return mMimeService.get(); } NS_IMPL_THREADSAFE_ISUPPORTS3(nsJARProtocolHandler, @@ -124,7 +128,7 @@ nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result) NS_IMETHODIMP nsJARProtocolHandler::GetScheme(nsACString &result) { - result = "jar"; + result = NS_LITERAL_CSTRING("jar"); return NS_OK; } @@ -185,21 +189,20 @@ nsJARProtocolHandler::NewURI(const nsACString &aSpec, } NS_IMETHODIMP -nsJARProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) +nsJARProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result) { - nsresult rv; + nsJARChannel *chan = new nsJARChannel(); + if (!chan) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(chan); - nsJARChannel* channel; - rv = nsJARChannel::Create(nsnull, NS_GET_IID(nsIJARChannel), (void**)&channel); - if (NS_FAILED(rv)) return rv; - - rv = channel->Init(this, uri); + nsresult rv = chan->Init(uri); if (NS_FAILED(rv)) { - NS_RELEASE(channel); + NS_RELEASE(chan); return rv; } - *result = channel; + *result = chan; return NS_OK; } diff --git a/mozilla/modules/libjar/nsJARProtocolHandler.h b/mozilla/modules/libjar/nsJARProtocolHandler.h index debfd0c4034..dfe008b07a7 100644 --- a/mozilla/modules/libjar/nsJARProtocolHandler.h +++ b/mozilla/modules/libjar/nsJARProtocolHandler.h @@ -35,8 +35,8 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsJARProtocolHandler_h___ -#define nsJARProtocolHandler_h___ +#ifndef nsJARProtocolHandler_h__ +#define nsJARProtocolHandler_h__ #include "nsIJARProtocolHandler.h" #include "nsIProtocolHandler.h" @@ -46,15 +46,6 @@ #include "nsWeakReference.h" #include "nsCOMPtr.h" -#define NS_JARPROTOCOLHANDLER_CID \ -{ /* 0xc7e410d4-0x85f2-11d3-9f63-006008a6efe9 */ \ - 0xc7e410d4, \ - 0x85f2, \ - 0x11d3, \ - {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ -} - - class nsJARProtocolHandler : public nsIJARProtocolHandler , public nsSupportsWeakReference { @@ -73,11 +64,14 @@ public: nsresult Init(); // returns non addref'ed pointer. - nsIMIMEService* GetCachedMimeService(); + nsIMIMEService *MimeService(); + nsIZipReaderCache *JarCache() { return mJARCache; } protected: nsCOMPtr mJARCache; nsCOMPtr mMimeService; }; -#endif /* nsJARProtocolHandler_h___ */ +extern nsJARProtocolHandler *gJarHandler; + +#endif // !nsJARProtocolHandler_h__ diff --git a/mozilla/modules/libjar/nsJARURI.h b/mozilla/modules/libjar/nsJARURI.h index 695c7ed1e9e..903944a573c 100644 --- a/mozilla/modules/libjar/nsJARURI.h +++ b/mozilla/modules/libjar/nsJARURI.h @@ -24,14 +24,6 @@ #include "nsCOMPtr.h" #include "nsString.h" -#define NS_JARURI_CID \ -{ /* 0xc7e410d7-0x85f2-11d3-9f63-006008a6efe9 */ \ - 0xc7e410d7, \ - 0x85f2, \ - 0x11d3, \ - {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ -} - class nsJARURI : public nsIJARURI, nsISerializable { public: diff --git a/mozilla/modules/libpref/src/nsPrefService.cpp b/mozilla/modules/libpref/src/nsPrefService.cpp index 7e77b2eca5b..e6c362ce5c9 100644 --- a/mozilla/modules/libpref/src/nsPrefService.cpp +++ b/mozilla/modules/libpref/src/nsPrefService.cpp @@ -43,8 +43,8 @@ #include "nsDirectoryServiceDefs.h" #include "nsICategoryManager.h" #include "nsCategoryManagerUtils.h" +#include "nsNetUtil.h" #include "nsIFile.h" -#include "nsIFileStreams.h" #include "nsILocalFile.h" #include "nsIObserverService.h" #include "nsPrefBranch.h" diff --git a/mozilla/netwerk/Makefile.in b/mozilla/netwerk/Makefile.in index c2083ad8c15..5685a2adb8d 100644 --- a/mozilla/netwerk/Makefile.in +++ b/mozilla/netwerk/Makefile.in @@ -29,11 +29,11 @@ include $(DEPTH)/config/autoconf.mk DIRS = \ base \ cookie \ - cache \ dns \ socket \ mime \ streamconv \ + cache \ protocol \ build \ build2 \ diff --git a/mozilla/netwerk/base/public/MANIFEST_IDL b/mozilla/netwerk/base/public/MANIFEST_IDL index 884e1605414..1ec2fe7c974 100644 --- a/mozilla/netwerk/base/public/MANIFEST_IDL +++ b/mozilla/netwerk/base/public/MANIFEST_IDL @@ -2,15 +2,13 @@ # This is a list of local files which get copied to the mozilla:dist directory # -nsIAuthenticator.idl nsIAuthPrompt.idl nsIChannel.idl nsIDirectoryListing.idl nsIDownloader.idl nsIEncodedChannel.idl nsIFileURL.idl -nsIFileChannel.idl -nsIFileTransportService.idl +nsIStreamTransportService.idl nsIMIMEInputStream.idl nsIPasswordManager.idl nsIPasswordManagerInternal.idl @@ -22,12 +20,11 @@ nsIProxyInfo.idl nsIProxy.idl nsIRequest.idl nsISocketTransportService.idl -nsIStreamIO.idl -nsIStreamIOChannel.idl nsIStreamListener.idl nsIStreamListenerProxy.idl nsIStreamListenerTee.idl nsIFileStreams.idl +nsIBufferedStreams.idl nsITransport.idl nsIStreamLoader.idl nsIUnicharStreamLoader.idl @@ -37,18 +34,17 @@ nsIResumableEntityID.idl nsIRequestObserver.idl nsIRequestObserverProxy.idl nsISimpleStreamListener.idl -nsISimpleStreamProvider.idl -nsIStreamProvider.idl -nsIStreamProviderProxy.idl nsIUploadChannel.idl nsIURI.idl nsIURIChecker.idl nsIURL.idl nsIURLParser.idl nsIStandardURL.idl -nsIWebFilters.idl nsISecurityEventSink.idl nsISecretDecoderRing.idl nsISecureBrowserUI.idl nsIByteRangeRequest.idl nsIMultiPartChannel.idl +nsIInputStreamPump.idl +nsIInputStreamChannel.idl +nsIAsyncStreamCopier.idl diff --git a/mozilla/netwerk/base/public/Makefile.in b/mozilla/netwerk/base/public/Makefile.in index fe1514782d8..d14a0eb959e 100644 --- a/mozilla/netwerk/base/public/Makefile.in +++ b/mozilla/netwerk/base/public/Makefile.in @@ -44,14 +44,15 @@ SDK_XPIDLSRCS = \ $(NULL) XPIDLSRCS = \ - nsIAuthenticator.idl \ nsIAuthPrompt.idl \ + nsIAsyncStreamCopier.idl \ + nsIBufferedStreams.idl \ nsIDirectoryListing.idl \ nsIDownloader.idl \ nsIEncodedChannel.idl \ - nsIFileChannel.idl \ nsIFileStreams.idl \ - nsIFileTransportService.idl \ + nsIInputStreamPump.idl \ + nsIInputStreamChannel.idl \ nsIMIMEInputStream.idl \ nsINetModRegEntry.idl \ nsINetModuleMgr.idl \ @@ -68,23 +69,18 @@ XPIDLSRCS = \ nsITransport.idl \ nsISocketTransport.idl \ nsISocketTransportService.idl \ - nsIStreamIO.idl \ - nsIStreamIOChannel.idl \ nsIResumableChannel.idl \ nsIResumableEntityID.idl \ nsIRequestObserverProxy.idl \ nsIStreamListenerProxy.idl \ nsIStreamListenerTee.idl \ - nsIStreamProvider.idl \ - nsIStreamProviderProxy.idl \ nsISimpleStreamListener.idl \ - nsISimpleStreamProvider.idl \ + nsIStreamTransportService.idl \ nsIStreamLoader.idl \ nsIUnicharStreamLoader.idl \ nsIStandardURL.idl \ nsIURLParser.idl \ nsIURIChecker.idl \ - nsIWebFilters.idl \ nsISecurityEventSink.idl \ nsISecretDecoderRing.idl \ nsISecureBrowserUI.idl \ diff --git a/mozilla/netwerk/base/public/nsIFileChannel.idl b/mozilla/netwerk/base/public/nsIFileChannel.idl index ba60a8c3964..ea1f2563698 100644 --- a/mozilla/netwerk/base/public/nsIFileChannel.idl +++ b/mozilla/netwerk/base/public/nsIFileChannel.idl @@ -44,6 +44,8 @@ interface nsIFile; * nsIFileChannel is an interface that allows for the initialization * of a simple nsIChannel that is constructed from a single nsIFile and * associated content type. + * + * XXX DEAD */ [scriptable, uuid(68a26506-f947-11d3-8cda-0060b0fc14a3)] interface nsIFileChannel : nsIChannel diff --git a/mozilla/netwerk/base/public/nsIFileStreams.idl b/mozilla/netwerk/base/public/nsIFileStreams.idl index 456bdca911b..f5d75060ec1 100644 --- a/mozilla/netwerk/base/public/nsIFileStreams.idl +++ b/mozilla/netwerk/base/public/nsIFileStreams.idl @@ -37,7 +37,6 @@ #include "nsIInputStream.idl" #include "nsIOutputStream.idl" -#include "nsISeekableStream.idl" interface nsIFile; @@ -97,211 +96,3 @@ interface nsIFileOutputStream : nsIOutputStream void init(in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); }; - -/** - * An input stream that reads ahead and keeps a buffer coming from another input - * stream so that fewer accesses to the underlying stream are necessary. - */ -[scriptable, uuid(616f5b48-da09-11d3-8cda-0060b0fc14a3)] -interface nsIBufferedInputStream : nsIInputStream -{ - /** - * @param fillFromStream - add buffering to this stream - * @param bufferSize - specifies the maximum buffer size - */ - void init(in nsIInputStream fillFromStream, - in unsigned long bufferSize); -}; - -/** - * An output stream that stores up data to write out to another output stream - * and does the entire write only when the buffer is full, so that fewer writes - * to the underlying output stream are necessary. - */ -[scriptable, uuid(6476378a-da09-11d3-8cda-0060b0fc14a3)] -interface nsIBufferedOutputStream : nsIOutputStream -{ - /** - * @param sinkToStream - add buffering to this stream - * @param bufferSize - specifies the maximum buffer size - */ - void init(in nsIOutputStream sinkToStream, - in unsigned long bufferSize); -}; - -%{C++ - -//////////////////////////////////////////////////////////////////////////////// - -#define NS_LOCALFILEINPUTSTREAM_CLASSNAME "Local File Input Stream" -#define NS_LOCALFILEINPUTSTREAM_CONTRACTID "@mozilla.org/network/file-input-stream;1" - -#define NS_LOCALFILEINPUTSTREAM_CID \ -{ /* be9a53ae-c7e9-11d3-8cda-0060b0fc14a3 */ \ - 0xbe9a53ae, \ - 0xc7e9, \ - 0x11d3, \ - {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ -} - -#define NS_LOCALFILEOUTPUTSTREAM_CLASSNAME "Local File Output Stream" -#define NS_LOCALFILEOUTPUTSTREAM_CONTRACTID "@mozilla.org/network/file-output-stream;1" - -#define NS_LOCALFILEOUTPUTSTREAM_CID \ -{ /* c272fee0-c7e9-11d3-8cda-0060b0fc14a3 */ \ - 0xc272fee0, \ - 0xc7e9, \ - 0x11d3, \ - {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ -} - -//////////////////////////////////////////////////////////////////////////////// - -#define NS_BUFFEREDINPUTSTREAM_CLASSNAME "Buffered Input Stream" -#define NS_BUFFEREDINPUTSTREAM_CONTRACTID "@mozilla.org/network/buffered-input-stream;1" - -#define NS_BUFFEREDINPUTSTREAM_CID \ -{ /* 9226888e-da08-11d3-8cda-0060b0fc14a3 */ \ - 0x9226888e, \ - 0xda08, \ - 0x11d3, \ - {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ -} - -#define NS_BUFFEREDOUTPUTSTREAM_CLASSNAME "Buffered Output Stream" -#define NS_BUFFEREDOUTPUTSTREAM_CONTRACTID "@mozilla.org/network/buffered-output-stream;1" - -#define NS_BUFFEREDOUTPUTSTREAM_CID \ -{ /* 9868b4ce-da08-11d3-8cda-0060b0fc14a3 */ \ - 0x9868b4ce, \ - 0xda08, \ - 0x11d3, \ - {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ -} - -//////////////////////////////////////////////////////////////////////////////// -// move to nsNetUtil.h later... - -#include "nsCOMPtr.h" -#include "nsIComponentManager.h" -#include "nsIFileChannel.h" -#include "nsIInputStream.h" -#include "nsIOutputStream.h" -#include "prio.h" // for read/write flags, permissions, etc. - -// This will QI the file argument to an nsILocalFile in the Init method. -inline nsresult -NS_NewLocalFileChannel(nsIFileChannel** aResult, - nsIFile* aFile, - PRInt32 aIOFlags = -1, - PRInt32 aPerm = -1) -{ - nsresult rv; - nsCOMPtr channel; - static NS_DEFINE_CID(kLocalFileChannelCID, NS_LOCALFILECHANNEL_CID); - rv = nsComponentManager::CreateInstance(kLocalFileChannelCID, - nsnull, - NS_GET_IID(nsIFileChannel), - getter_AddRefs(channel)); - if (NS_FAILED(rv)) return rv; - rv = channel->Init(aFile, aIOFlags, aPerm); - if (NS_FAILED(rv)) return rv; - - *aResult = channel; - NS_ADDREF(*aResult); - return NS_OK; -} - -// This will QI the file argument to an nsILocalFile in the Init method. -inline nsresult -NS_NewLocalFileInputStream(nsIInputStream** aResult, - nsIFile* aFile, - PRInt32 aIOFlags = -1, - PRInt32 aPerm = -1, - PRInt32 aBehaviorFlags = 0) -{ - nsresult rv; - nsCOMPtr in; - static NS_DEFINE_CID(kLocalFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID); - rv = nsComponentManager::CreateInstance(kLocalFileInputStreamCID, - nsnull, - NS_GET_IID(nsIFileInputStream), - getter_AddRefs(in)); - if (NS_FAILED(rv)) return rv; - rv = in->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); - if (NS_FAILED(rv)) return rv; - - *aResult = in; - NS_ADDREF(*aResult); - return NS_OK; -} - -// This will QI the file argument to an nsILocalFile in the Init method. -inline nsresult -NS_NewLocalFileOutputStream(nsIOutputStream** aResult, - nsIFile* aFile, - PRInt32 aIOFlags = -1, - PRInt32 aPerm = -1, - PRInt32 aBehaviorFlags = 0) -{ - nsresult rv; - nsCOMPtr out; - static NS_DEFINE_CID(kLocalFileOutputStreamCID, NS_LOCALFILEOUTPUTSTREAM_CID); - rv = nsComponentManager::CreateInstance(kLocalFileOutputStreamCID, - nsnull, - NS_GET_IID(nsIFileOutputStream), - getter_AddRefs(out)); - if (NS_FAILED(rv)) return rv; - rv = out->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); - if (NS_FAILED(rv)) return rv; - - *aResult = out; - NS_ADDREF(*aResult); - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -inline nsresult -NS_NewBufferedInputStream(nsIInputStream** aResult, - nsIInputStream* aStr, - PRUint32 aBufferSize) -{ - nsresult rv; - nsCOMPtr in; - static NS_DEFINE_CID(kBufferedInputStreamCID, NS_BUFFEREDINPUTSTREAM_CID); - rv = nsComponentManager::CreateInstance(kBufferedInputStreamCID, - nsnull, - NS_GET_IID(nsIBufferedInputStream), - getter_AddRefs(in)); - if (NS_FAILED(rv)) return rv; - rv = in->Init(aStr, aBufferSize); - if (NS_FAILED(rv)) return rv; - - *aResult = in; - NS_ADDREF(*aResult); - return NS_OK; -} - -inline nsresult -NS_NewBufferedOutputStream(nsIOutputStream** aResult, - nsIOutputStream* aStr, - PRUint32 aBufferSize) -{ - nsresult rv; - nsCOMPtr out; - static NS_DEFINE_CID(kBufferedOutputStreamCID, NS_BUFFEREDOUTPUTSTREAM_CID); - rv = nsComponentManager::CreateInstance(kBufferedOutputStreamCID, - nsnull, - NS_GET_IID(nsIBufferedOutputStream), - getter_AddRefs(out)); - if (NS_FAILED(rv)) return rv; - rv = out->Init(aStr, aBufferSize); - if (NS_FAILED(rv)) return rv; - - *aResult = out; - NS_ADDREF(*aResult); - return NS_OK; -} - -%} diff --git a/mozilla/netwerk/base/public/nsISocketTransport.idl b/mozilla/netwerk/base/public/nsISocketTransport.idl index 39ac7f00d83..4744a892bf0 100644 --- a/mozilla/netwerk/base/public/nsISocketTransport.idl +++ b/mozilla/netwerk/base/public/nsISocketTransport.idl @@ -37,59 +37,76 @@ #include "nsITransport.idl" -[scriptable, uuid(785CA0F0-C39E-11d3-9ED6-0010A4053FD0)] +interface nsIInterfaceRequestor; +interface nsISocketEventSink; + +%{C++ +#include "prio.h" +%} + +[ptr] native PRNetAddrStar(PRNetAddr); + +/** + * nsISocketTransport + * + * NOTE: This is a free-threaded interface. + */ +[scriptable, uuid(1e372001-ca12-4507-8405-3267d4e0c1fd)] interface nsISocketTransport : nsITransport { /** - * Destination host and port. These are used for reporting status messages - * Since the end server may change at any time (eg persistent connections - * through proxies), a client can update this to get correct results. - * There is no other effect of setting these attributes, and if a proxy - * server is not being used, NS_ERROR_FAILURE is returned. + * Get the host for the underlying socket connection. */ - attribute string host; - attribute long port; + readonly attribute AUTF8String host; /** + * Get the port for the underlying socket connection. + */ + readonly attribute long port; + + /** + * Get the PRNetAddr for the underlying socket connection. + */ + [noscript] void getAddress(in PRNetAddrStar addr); + + /** + * Security info object returned from the PSM socket provider. This object + * supports nsISSLSocketControl, nsITransportSecurityInfo, and possibly + * other interfaces. + */ + readonly attribute nsISupports securityInfo; + + /** + * Security notification callbacks passed to PSM via nsISSLSocketControl at + * socket creation time. * + * NOTE: this attribute cannot be changed once a stream has been opened. */ - attribute boolean reuseConnection; - + attribute nsIInterfaceRequestor securityCallbacks; + /** - * socket read/write timeout in seconds; 0 = no timeout + * Test if this socket transport is (still) connected. */ - attribute unsigned long socketTimeout; - + boolean isAlive(); + /** - * socket connect timeout in seconds; 0 = no timeout + * nsITransportEventSink status codes: */ - attribute unsigned long socketConnectTimeout; - - /** - * Is used to tell the channel to stop reading data after a certain point; - * needed by HTTP/1.1 - */ - attribute long bytesExpected; - attribute unsigned long reuseCount; - - /** - * Checks if the socket is still alive - * - * @param seconds amount of time after which the socket is always deemed to be - * dead (no further checking is done in this case); seconds = 0 - * will cause it not to do the timeout checking at all - */ - boolean isAlive (in unsigned long seconds); - - /** - * maximum amount of time in seconds the transport is allowed to stay alive - * while connected (0 - default; no maximum idle timeout) - */ - attribute unsigned long idleTimeout; - - /** - * the string representation of the underlying ip address. Caller - * is responsible for de-allocating the returned string. - */ - [noscript] string GetIPStr(in unsigned long aStrLen); + const unsigned long STATUS_RESOLVING = 0x804b0003; + const unsigned long STATUS_CONNECTED_TO = 0x804b0004; + const unsigned long STATUS_SENDING_TO = 0x804b0005; + const unsigned long STATUS_RECEIVING_FROM = 0x804b0006; + const unsigned long STATUS_CONNECTING_TO = 0x804b0007; + const unsigned long STATUS_WAITING_FOR = 0x804b000a; }; + +%{C++ +/** + * #define's for compatibility + */ +#define NS_NET_STATUS_RESOLVING_HOST nsISocketTransport::STATUS_RESOLVING +#define NS_NET_STATUS_CONNECTED_TO nsISocketTransport::STATUS_CONNECTED_TO +#define NS_NET_STATUS_SENDING_TO nsISocketTransport::STATUS_SENDING_TO +#define NS_NET_STATUS_RECEIVING_FROM nsISocketTransport::STATUS_RECEIVING_FROM +#define NS_NET_STATUS_CONNECTING_TO nsISocketTransport::STATUS_CONNECTING_TO +%} diff --git a/mozilla/netwerk/base/public/nsISocketTransportService.idl b/mozilla/netwerk/base/public/nsISocketTransportService.idl index 3e57ffa2316..b73e52baddb 100644 --- a/mozilla/netwerk/base/public/nsISocketTransportService.idl +++ b/mozilla/netwerk/base/public/nsISocketTransportService.idl @@ -37,9 +37,8 @@ #include "nsISupports.idl" -interface nsITransport; -interface nsIEventSinkGetter; -interface nsIChannel; +interface nsISocketTransport; +interface nsISocketEventHandler; interface nsIProxyInfo; [scriptable, uuid(05331390-6884-11d3-9382-00104ba0fd40)] @@ -48,86 +47,70 @@ interface nsISocketTransportService : nsISupports /** * Creates a transport for a specified host and port. * - * @param proxyInfo Information about any transport-layer proxying. Used - * for communicating information about proxies like socks. - * This can either be the proxyInfo attribute on an - * nsISupportsTransparentProxy (or from the protocolProxyService), - * or null for no proxying. - * - * @see nsISupportsTransparentProxy + * @param aSocketTypes + * array of socket type strings. null if using default socket type. + * @param aTypeCount + * specifies length of aSocketTypes. + * @param aHost + * specifies the target hostname or IP address literal of the peer + * for this socket. + * @param aPort + * specifies the target port of the peer for this socket. + * @param aProxyInfo + * specifies the transport-layer proxy type to use. null if no + * proxy. used for communicating information about proxies like + * SOCKS (which are transparent to upper protocols). + * + * @see nsIProxiedProtocolHandler * @see nsIProtocolProxyService::GetProxyInfo */ - nsITransport createTransport(in string host, - in long port, - in nsIProxyInfo proxyInfo, - in unsigned long bufferSegmentSize, - in unsigned long bufferMaxSize); - - nsITransport createTransportOfType(in string socketType, - in string host, - in long port, - in nsIProxyInfo proxyInfo, - in unsigned long bufferSegmentSize, - in unsigned long bufferMaxSize); - - nsITransport createTransportOfTypes(in unsigned long typeCount, - [array, size_is(typeCount)] in string socketTypes, - in string host, - in long port, - in nsIProxyInfo proxyInfo, - in unsigned long bufferSegmentSize, - in unsigned long bufferMaxSize); + nsISocketTransport createTransport([array, size_is(aTypeCount)] + in string aSocketTypes, + in unsigned long aTypeCount, + in AUTF8String aHost, + in long aPort, + in nsIProxyInfo aProxyInfo); /** - * Returns true if the specified transport is good enough for - * being used again. The situations in which this may return false - * include- an error including server resets, an explicit - * Connection: close header (for HTTP) and timeouts! + * init/shutdown routines. */ - boolean reuseTransport(in nsITransport i_Transport); - - void init (); + void init(); void shutdown(); - void wakeup (in nsITransport i_Transport); - - /** - * Total number of nsSocketTransport objects currently alive - */ - readonly attribute unsigned long totalTransportCount; - /** - * A number of nsSocketTransport objects with I/O operation currently in-progress - */ - readonly attribute unsigned long inUseTransportCount; - /** - * A number of nsSocketTransport objects connected (this may include keep-alive idle connections) - */ - readonly attribute unsigned long connectedTransportCount; /** - * Autodial helper is enabled via pref. + * Post an event to be executed on the socket thread. + * + * @param aHandler + * handler that will be executed on the socket thread. + * @param aType + * caller defined message parameter + * @param aUParam + * caller defined message parameter + * @param aVParam + * caller defined message parameter + * + * The socket transport service treats each parameter as opaque data (i.e., + * it is not responsible for cleaning up aVParam if it happens to be + * dynamically allocated). If this function succeeds, then the message + * will be delivered. All messages successfully posted will be delivered + * before the socket transport service shuts down. + */ + [noscript] void postEvent(in nsISocketEventHandler aHandler, + in unsigned long aType, + in unsigned long aUParam, + in voidPtr aVParam); + + /** + * controls whether or not the socket transport service should poke + * the autodialer on connection failure. */ attribute boolean autodialEnabled; - }; -%{C++ -#define NS_SOCKETTRANSPORTSERVICE_CID \ -{ /* c07e81e0-ef12-11d2-92b6-00105a1b0d64 */ \ - 0xc07e81e0, \ - 0xef12, \ - 0x11d2, \ - {0x92, 0xb6, 0x00, 0x10, 0x5a, 0x1b, 0x0d, 0x64} \ -} - -#include "nsNetError.h" - -/** - * Status nsresult codes: used with nsIProgressEventSink::OnStatus - */ -#define NS_NET_STATUS_RESOLVING_HOST NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 3) -#define NS_NET_STATUS_CONNECTED_TO NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 4) -#define NS_NET_STATUS_SENDING_TO NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 5) -#define NS_NET_STATUS_RECEIVING_FROM NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 6) -#define NS_NET_STATUS_CONNECTING_TO NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 7) - -%} +[uuid(c20f98be-b3e4-4f9b-a492-97a688577355)] +interface nsISocketEventHandler : nsISupports +{ + [noscript] void onSocketEvent(in unsigned long aType, + in unsigned long aUParam, + in voidPtr aVParam); +}; diff --git a/mozilla/netwerk/base/public/nsIStreamListenerProxy.idl b/mozilla/netwerk/base/public/nsIStreamListenerProxy.idl index 8d47cc2710b..705af532dde 100644 --- a/mozilla/netwerk/base/public/nsIStreamListenerProxy.idl +++ b/mozilla/netwerk/base/public/nsIStreamListenerProxy.idl @@ -65,7 +65,7 @@ interface nsIStreamListenerProxy : nsIStreamListener }; /** - * THIS INTERFACE IS DEPRACATED + * THIS INTERFACE IS DEPRECATED * * An asynchronous stream listener is used to ship data over to another thread specified * by the thread's event queue. The receiver stream listener is then used to receive diff --git a/mozilla/netwerk/base/public/nsITransport.idl b/mozilla/netwerk/base/public/nsITransport.idl index 49f651f1be0..82cdacfbf8e 100644 --- a/mozilla/netwerk/base/public/nsITransport.idl +++ b/mozilla/netwerk/base/public/nsITransport.idl @@ -1,147 +1,138 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** 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) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Darin Fisher * * 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 "nsISupports.idl" -#include "nsIRequest.idl" -interface nsIStreamListener; -interface nsIStreamProvider; interface nsIInputStream; interface nsIOutputStream; -interface nsIInterfaceRequestor; +interface nsITransportEventSink; +interface nsIEventQueue; -[scriptable, uuid(fd01f9a4-d492-4cf8-b76e-160ffc8c01e8)] +[scriptable, uuid(cbb0baeb-5fcb-408b-a2be-9f8fc98d0af1)] interface nsITransport : nsISupports { /** - * Get security info for this transport. + * Open flags. */ - readonly attribute nsISupports securityInfo; - - /** - * Get/set notificationCallbacks for this transport. - */ - nsIInterfaceRequestor getNotificationCallbacks(); - void setNotificationCallbacks(in nsIInterfaceRequestor callbacks, - in unsigned long flags); - - /** - * If the notificationCallbacks provide a nsIProgressEventSink - * implementation, then progress is by default reported to the thread - * that called setNotificationCallbacks. The following flags provide - * finer control over progress notifications: - * - * DONT_REPORT_PROGRESS - progress notifications are not sent. - * DONT_PROXY_PROGRESS - progress notifications can occur on any thread. - */ - const unsigned long DONT_REPORT_PROGRESS = 1; - const unsigned long DONT_PROXY_PROGRESS = 2; + const unsigned long OPEN_BLOCKING = 1<<0; + const unsigned long OPEN_UNBUFFERED = 1<<1; /** * Open an input stream on this transport. * - * @param offset - read starting at this offset - * @param count - read this many bytes (pass PRUint32(-1) if unlimited) - * @param flags - optional transport specific flags + * @param aFlags + * optional transport specific flags. + * @param aSegmentSize + * if OPEN_UNBUFFERED is not set, then this parameter specifies the + * size of each buffer segment (pass 0 to use default value). + * @param aSegmentCount + * if OPEN_UNBUFFERED is not set, then this parameter specifies the + * maximum number of buffer segments (pass 0 to use default value). */ - nsIInputStream openInputStream(in unsigned long offset, - in unsigned long count, - in unsigned long flags); + nsIInputStream openInputStream(in unsigned long aFlags, + in unsigned long aSegmentSize, + in unsigned long aSegmentCount); /** * Open an output stream on this transport. * - * @param offset - write starting at this offset - * @param count - write no more than this many bytes (pass PRUint32(-1) if unlimited) - * @param flags - optional transport specific flags + * @param aFlags + * optional transport specific flags. + * @param aSegmentSize + * if OPEN_UNBUFFERED is not set, then this parameter specifies the + * size of each buffer segment (pass 0 to use default value). + * @param aSegmentCount + * if OPEN_UNBUFFERED is not set, then this parameter specifies the + * maximum number of buffer segments (pass 0 to use default value). */ - nsIOutputStream openOutputStream(in unsigned long offset, - in unsigned long count, - in unsigned long flags); + nsIOutputStream openOutputStream(in unsigned long aFlags, + in unsigned long aSegmentSize, + in unsigned long aSegmentCount); /** - * Asynchronously read data from the transport. + * Close the transport and any open streams. * - * @param listener - notify this listener when data is available - * @param ctxt - opaque parameter passed to listener methods - * @param offset - read starting at this offset - * @param count - read this many bytes (pass PRUint32(-1) if unlimited) - * @param flags - optional transport specific flags + * @param aReason + * the reason for closing the stream. */ - nsIRequest asyncRead(in nsIStreamListener listener, - in nsISupports ctxt, - in unsigned long offset, - in unsigned long count, - in unsigned long flags); + void close(in nsresult aReason); /** - * Asynchronously write data to the transport. + * Set the transport event sink. * - * @param provider - notify this provider when data can be written - * @param ctxt - opaque parameter passed to provider methods - * @param offset - write starting at this offset - * @param count - write no more than this many bytes (pass PRUint32(-1) if unlimited) - * @param flags - optional transport specific flags + * @param aSink + * receives transport layer notifications + * @param aEventQ + * indicates the event queue to which the notifications should + * be delivered. if NULL, then the notifications may occur on + * any thread. (NOTE: the event queue must be resolved.) */ - nsIRequest asyncWrite(in nsIStreamProvider provider, - in nsISupports ctxt, - in unsigned long offset, - in unsigned long count, - in unsigned long flags); - + void setEventSink(in nsITransportEventSink aSink, + in nsIEventQueue aEventQ); + /** - * Callbacks from asyncRead and asyncWrite may be proxied from a - * background thread (if one exists) to the thread which initiated - * the request. This is the expected behavior of such a nsITransport - * implementation. A caller of asyncRead or asyncWrite can explicitly - * ask the transport to not proxy the callback. The caller must then - * be prepared to handle callbacks on any thread. + * Generic nsITransportEventSink status codes. nsITransport + * implementations may override these status codes with their own more + * specific status codes (e.g., see nsISocketTransport). */ - const unsigned long DONT_PROXY_OBSERVER = 1 << 0; - const unsigned long DONT_PROXY_LISTENER = 1 << 1; - const unsigned long DONT_PROXY_PROVIDER = 1 << 1; - + const unsigned long STATUS_READING = 0x804b0008; + const unsigned long STATUS_WRITING = 0x804b0009; }; -[scriptable, uuid(d7abf5a4-ce72-482a-9217-a219a905c019)] -interface nsITransportRequest : nsIRequest +[scriptable, uuid(561de8af-1b74-4cd4-8479-89447d48185c)] +interface nsITransportEventSink : nsISupports { /** - * Get the transport associated with this request. + * Transport status notification. + * + * @param aTransport + * the transport sending this status notification. + * @param aStatus + * the transport status (resolvable to a string using + * nsIErrorService). + * @param aProgress + * the amount of data either read or written depending on the value + * of the status code. this value is relative to aProgressMax. + * @param aProgressMax + * the maximum amount of data that will be read or written. if + * unknown, 0xFFFFFFFF will be passed. */ - readonly attribute nsITransport transport; + void onTransportStatus(in nsITransport aTransport, + in nsresult aStatus, + in unsigned long aProgress, + in unsigned long aProgressMax); }; diff --git a/mozilla/netwerk/base/public/nsNetUtil.h b/mozilla/netwerk/base/public/nsNetUtil.h index 69b0f88ec2d..f69f25748f1 100644 --- a/mozilla/netwerk/base/public/nsNetUtil.h +++ b/mozilla/netwerk/base/public/nsNetUtil.h @@ -38,47 +38,46 @@ #ifndef nsNetUtil_h__ #define nsNetUtil_h__ -#include "nsString.h" +#include "nsNetError.h" +#include "nsNetCID.h" #include "nsReadableUtils.h" -#include "netCore.h" +#include "nsString.h" +#include "nsMemory.h" +#include "nsCOMPtr.h" +#include "prio.h" // for read/write flags, permissions, etc. + #include "nsIURI.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" #include "nsIStreamListener.h" -#include "nsIStreamProvider.h" #include "nsIRequestObserverProxy.h" -#include "nsIStreamListenerProxy.h" -#include "nsIStreamProviderProxy.h" +#include "nsIStreamListenerProxy.h" // XXX for nsIAsyncStreamListener #include "nsISimpleStreamListener.h" -#include "nsISimpleStreamProvider.h" #include "nsILoadGroup.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIIOService.h" #include "nsIServiceManager.h" #include "nsIChannel.h" -#include "nsIStreamIOChannel.h" +#include "nsIInputStreamChannel.h" #include "nsITransport.h" #include "nsIHttpChannel.h" -#include "nsMemory.h" -#include "nsCOMPtr.h" #include "nsIDownloader.h" #include "nsIResumableEntityID.h" #include "nsIStreamLoader.h" #include "nsIUnicharStreamLoader.h" -#include "nsIStreamIO.h" #include "nsIPipe.h" #include "nsIProtocolHandler.h" #include "nsIFileProtocolHandler.h" #include "nsIStringStream.h" #include "nsILocalFile.h" #include "nsIFileStreams.h" -#include "nsXPIDLString.h" #include "nsIProtocolProxyService.h" #include "nsIProxyInfo.h" -#include "prio.h" // for read/write flags, permissions, etc. - -#include "nsNetCID.h" +#include "nsIFileStreams.h" +#include "nsIBufferedStreams.h" +#include "nsIInputStreamPump.h" +#include "nsIAsyncStreamCopier.h" // Helper, to simplify getting the I/O service. inline const nsGetServiceByCID @@ -289,77 +288,79 @@ NS_MakeAbsoluteURI(nsAString &result, } inline nsresult -NS_NewPostDataStream(nsIInputStream **result, - PRBool isFile, - const nsACString &data, - PRUint32 encodeFlags, - nsIIOService* ioService = nsnull) // pass in nsIIOService to optimize callers +NS_NewInputStreamChannel(nsIChannel **result, + nsIURI *uri, + nsIInputStream *stream, + const nsACString &contentType = NS_LITERAL_CSTRING(""), + const nsACString &contentCharset = NS_LITERAL_CSTRING("")) { nsresult rv; - if (isFile) { - nsCOMPtr file; - nsCOMPtr fileStream; - - rv = NS_NewNativeLocalFile(data, PR_FALSE, getter_AddRefs(file)); - if (NS_FAILED(rv)) return rv; - - rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file); - if (NS_FAILED(rv)) return rv; - - // wrap the file stream with a buffered input stream - return NS_NewBufferedInputStream(result, fileStream, 8192); - } - - // otherwise, create a string stream for the data - return NS_NewCStringInputStream(result, data); -} - -inline nsresult -NS_NewStreamIOChannel(nsIStreamIOChannel **result, - nsIURI* uri, - nsIStreamIO* io) -{ - nsresult rv; - nsCOMPtr channel; - static NS_DEFINE_CID(kStreamIOChannelCID, NS_STREAMIOCHANNEL_CID); - rv = nsComponentManager::CreateInstance(kStreamIOChannelCID, - nsnull, - NS_GET_IID(nsIStreamIOChannel), - getter_AddRefs(channel)); - if (NS_FAILED(rv)) return rv; - rv = channel->Init(uri, io); + static NS_DEFINE_CID(kInputStreamChannelCID, NS_INPUTSTREAMCHANNEL_CID); + nsCOMPtr channel = + do_CreateInstance(kInputStreamChannelCID, &rv); if (NS_FAILED(rv)) return rv; - *result = channel; - NS_ADDREF(*result); + rv = channel->SetURI(uri); + if (NS_FAILED(rv)) return rv; + rv = channel->SetContentStream(stream); + if (NS_FAILED(rv)) return rv; + rv = channel->SetContentType(contentType); + if (NS_FAILED(rv)) return rv; + rv = channel->SetContentCharset(contentCharset); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = channel); return NS_OK; } inline nsresult -NS_NewInputStreamChannel(nsIChannel **result, - nsIURI* uri, - nsIInputStream* inStr, - const nsACString &contentType, - const nsACString &contentCharset, - PRInt32 contentLength) +NS_NewInputStreamPump(nsIInputStreamPump **result, + nsIInputStream *stream, + PRInt32 streamPos = -1, + PRInt32 streamLen = -1, + PRUint32 segsize = 0, + PRUint32 segcount = 0, + PRBool closeWhenDone = PR_FALSE) { nsresult rv; - nsCAutoString spec; - rv = uri->GetSpec(spec); + + static NS_DEFINE_CID(kInputStreamPumpCID, NS_INPUTSTREAMPUMP_CID); + nsCOMPtr pump = + do_CreateInstance(kInputStreamPumpCID, &rv); if (NS_FAILED(rv)) return rv; - nsCOMPtr io; - rv = NS_NewInputStreamIO(getter_AddRefs(io), spec, inStr, - contentType, contentCharset, contentLength); + rv = pump->Init(stream, streamPos, streamLen, + segsize, segcount, closeWhenDone); if (NS_FAILED(rv)) return rv; - nsCOMPtr channel; - rv = NS_NewStreamIOChannel(getter_AddRefs(channel), uri, io); + NS_ADDREF(*result = pump); + return NS_OK; +} + +// NOTE: you can optimize the copy by specifying whether or not your streams +// are buffered (i.e., do they implement ReadSegments/WriteSegments). the +// default assumption of FALSE for both streams is OK, but the copy is much +// more efficient if one of the streams is buffered. +inline nsresult +NS_NewAsyncStreamCopier(nsIAsyncStreamCopier **result, + nsIInputStream *source, + nsIOutputStream *sink, + PRBool sourceBuffered = PR_FALSE, + PRBool sinkBuffered = PR_FALSE, + PRUint32 chunkSize = 0) +{ + nsresult rv; + + static NS_DEFINE_CID(kAsyncStreamCopierCID, NS_ASYNCSTREAMCOPIER_CID); + nsCOMPtr copier = + do_CreateInstance(kAsyncStreamCopierCID, &rv); if (NS_FAILED(rv)) return rv; - *result = channel; - NS_ADDREF(*result); + rv = copier->Init(source, sink, sourceBuffered, sinkBuffered, chunkSize); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = copier); return NS_OK; } @@ -505,58 +506,6 @@ NS_NewRequestObserverProxy(nsIRequestObserver **aResult, return CallQueryInterface(proxy, aResult); } -inline nsresult -NS_NewStreamListenerProxy(nsIStreamListener **aResult, - nsIStreamListener *aListener, - nsIEventQueue *aEventQ=nsnull, - PRUint32 aBufferSegmentSize=0, - PRUint32 aBufferMaxSize=0) -{ - NS_ENSURE_ARG_POINTER(aResult); - - nsresult rv; - nsCOMPtr proxy; - static NS_DEFINE_CID(kStreamListenerProxyCID, NS_STREAMLISTENERPROXY_CID); - - rv = nsComponentManager::CreateInstance(kStreamListenerProxyCID, - nsnull, - NS_GET_IID(nsIStreamListenerProxy), - getter_AddRefs(proxy)); - if (NS_FAILED(rv)) return rv; - - rv = proxy->Init(aListener, aEventQ, aBufferSegmentSize, aBufferMaxSize); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*aResult = proxy); - return NS_OK; -} - -inline nsresult -NS_NewStreamProviderProxy(nsIStreamProvider **aResult, - nsIStreamProvider *aProvider, - nsIEventQueue *aEventQ=nsnull, - PRUint32 aBufferSegmentSize=0, - PRUint32 aBufferMaxSize=0) -{ - NS_ENSURE_ARG_POINTER(aResult); - - nsresult rv; - nsCOMPtr proxy; - static NS_DEFINE_CID(kStreamProviderProxyCID, NS_STREAMPROVIDERPROXY_CID); - - rv = nsComponentManager::CreateInstance(kStreamProviderProxyCID, - nsnull, - NS_GET_IID(nsIStreamProviderProxy), - getter_AddRefs(proxy)); - if (NS_FAILED(rv)) return rv; - - rv = proxy->Init(aProvider, aEventQ, aBufferSegmentSize, aBufferMaxSize); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*aResult = proxy); - return NS_OK; -} - inline nsresult NS_NewSimpleStreamListener(nsIStreamListener **aResult, nsIOutputStream *aSink, @@ -580,53 +529,7 @@ NS_NewSimpleStreamListener(nsIStreamListener **aResult, return NS_OK; } -inline nsresult -NS_NewSimpleStreamProvider(nsIStreamProvider **aResult, - nsIInputStream *aSource, - nsIRequestObserver *aObserver=nsnull) -{ - NS_ENSURE_ARG_POINTER(aResult); - - nsresult rv; - nsCOMPtr provider; - static NS_DEFINE_CID(kSimpleStreamProviderCID, NS_SIMPLESTREAMPROVIDER_CID); - rv = nsComponentManager::CreateInstance(kSimpleStreamProviderCID, - nsnull, - NS_GET_IID(nsISimpleStreamProvider), - getter_AddRefs(provider)); - if (NS_FAILED(rv)) return rv; - - rv = provider->Init(aSource, aObserver); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*aResult = provider); - return NS_OK; -} - -/* -// Depracated, prefer NS_NewStreamObserverProxy -inline nsresult -NS_NewAsyncStreamObserver(nsIRequestObserver **result, - nsIRequestObserver *receiver, - nsIEventQueue *eventQueue) -{ - nsresult rv; - nsCOMPtr obs; - static NS_DEFINE_CID(kAsyncStreamObserverCID, NS_ASYNCSTREAMOBSERVER_CID); - rv = nsComponentManager::CreateInstance(kAsyncStreamObserverCID, - nsnull, - NS_GET_IID(nsIAsyncStreamObserver), - getter_AddRefs(obs)); - if (NS_FAILED(rv)) return rv; - rv = obs->Init(receiver, eventQueue); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*result = obs); - return NS_OK; -} -*/ - -// Depracated, prefer NS_NewStreamListenerProxy +// Deprecated, prefer NS_NewStreamListenerProxy inline nsresult NS_NewAsyncStreamListener(nsIStreamListener **result, nsIStreamListener *receiver, @@ -647,106 +550,6 @@ NS_NewAsyncStreamListener(nsIStreamListener **result, return NS_OK; } -// Depracated, prefer a true synchonous implementation -inline nsresult -NS_NewSyncStreamListener(nsIInputStream **aInStream, - nsIOutputStream **aOutStream, - nsIStreamListener **aResult) -{ - nsresult rv; - - NS_ENSURE_ARG_POINTER(aInStream); - NS_ENSURE_ARG_POINTER(aOutStream); - - nsCOMPtr pipeIn; - nsCOMPtr pipeOut; - - rv = NS_NewPipe(getter_AddRefs(pipeIn), - getter_AddRefs(pipeOut), - 4*1024, // NS_SYNC_STREAM_LISTENER_SEGMENT_SIZE - 32*1024); // NS_SYNC_STREAM_LISTENER_BUFFER_SIZE - if (NS_FAILED(rv)) return rv; - - rv = NS_NewSimpleStreamListener(aResult, pipeOut); - if (NS_FAILED(rv)) return rv; - - NS_ADDREF(*aInStream = pipeIn); - NS_ADDREF(*aOutStream = pipeOut); - return NS_OK; -} - -// -// Calls AsyncWrite on the specified transport, with a stream provider that -// reads data from the specified input stream. -// -inline nsresult -NS_AsyncWriteFromStream(nsIRequest **aRequest, - nsITransport *aTransport, - nsIInputStream *aSource, - PRUint32 aOffset=0, - PRUint32 aCount=0, - PRUint32 aFlags=0, - nsIRequestObserver *aObserver=NULL, - nsISupports *aContext=NULL) -{ - NS_ENSURE_ARG_POINTER(aTransport); - - nsresult rv; - nsCOMPtr provider; - rv = NS_NewSimpleStreamProvider(getter_AddRefs(provider), - aSource, - aObserver); - if (NS_FAILED(rv)) return rv; - - // - // We can safely allow the transport impl to bypass proxying the provider - // since we are using a simple stream provider. - // - // A simple stream provider masks the OnDataWritable from consumers. - // Moreover, it makes an assumption about the underlying nsIInputStream - // implementation: namely, that it is thread-safe and blocking. - // - // So, let's always make this optimization. - // - aFlags |= nsITransport::DONT_PROXY_PROVIDER; - - return aTransport->AsyncWrite(provider, aContext, - aOffset, - aCount, - aFlags, - aRequest); -} - -// -// Calls AsyncRead on the specified transport, with a stream listener that -// writes data to the specified output stream. -// -inline nsresult -NS_AsyncReadToStream(nsIRequest **aRequest, - nsITransport *aTransport, - nsIOutputStream *aSink, - PRUint32 aOffset=0, - PRUint32 aCount=0, - PRUint32 aFlags=0, - nsIRequestObserver *aObserver=NULL, - nsISupports *aContext=NULL) -{ - NS_ENSURE_ARG_POINTER(aTransport); - - nsresult rv; - nsCOMPtr listener; - rv = NS_NewSimpleStreamListener(getter_AddRefs(listener), - aSink, - aObserver); - if (NS_FAILED(rv)) return rv; - - return aTransport->AsyncRead(listener, aContext, - aOffset, - aCount, - aFlags, - aRequest); -} - inline nsresult NS_CheckPortSafety(PRInt32 port, const char* scheme, nsIIOService* ioService = nsnull) { @@ -903,5 +706,119 @@ NS_ParseContentType(const nsACString &rawContentType, return NS_OK; } -#endif // nsNetUtil_h__ +inline nsresult +NS_NewLocalFileInputStream(nsIInputStream** aResult, + nsIFile* aFile, + PRInt32 aIOFlags = -1, + PRInt32 aPerm = -1, + PRInt32 aBehaviorFlags = 0) +{ + nsresult rv; + nsCOMPtr in; + static NS_DEFINE_CID(kLocalFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID); + rv = nsComponentManager::CreateInstance(kLocalFileInputStreamCID, + nsnull, + NS_GET_IID(nsIFileInputStream), + getter_AddRefs(in)); + if (NS_FAILED(rv)) return rv; + rv = in->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); + if (NS_FAILED(rv)) return rv; + *aResult = in; + NS_ADDREF(*aResult); + return NS_OK; +} + +inline nsresult +NS_NewLocalFileOutputStream(nsIOutputStream** aResult, + nsIFile* aFile, + PRInt32 aIOFlags = -1, + PRInt32 aPerm = -1, + PRInt32 aBehaviorFlags = 0) +{ + nsresult rv; + nsCOMPtr out; + static NS_DEFINE_CID(kLocalFileOutputStreamCID, NS_LOCALFILEOUTPUTSTREAM_CID); + rv = nsComponentManager::CreateInstance(kLocalFileOutputStreamCID, + nsnull, + NS_GET_IID(nsIFileOutputStream), + getter_AddRefs(out)); + if (NS_FAILED(rv)) return rv; + rv = out->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); + if (NS_FAILED(rv)) return rv; + + *aResult = out; + NS_ADDREF(*aResult); + return NS_OK; +} + +inline nsresult +NS_NewBufferedInputStream(nsIInputStream** aResult, + nsIInputStream* aStr, + PRUint32 aBufferSize) +{ + nsresult rv; + nsCOMPtr in; + static NS_DEFINE_CID(kBufferedInputStreamCID, NS_BUFFEREDINPUTSTREAM_CID); + rv = nsComponentManager::CreateInstance(kBufferedInputStreamCID, + nsnull, + NS_GET_IID(nsIBufferedInputStream), + getter_AddRefs(in)); + if (NS_FAILED(rv)) return rv; + rv = in->Init(aStr, aBufferSize); + if (NS_FAILED(rv)) return rv; + + *aResult = in; + NS_ADDREF(*aResult); + return NS_OK; +} + +inline nsresult +NS_NewBufferedOutputStream(nsIOutputStream** aResult, + nsIOutputStream* aStr, + PRUint32 aBufferSize) +{ + nsresult rv; + nsCOMPtr out; + static NS_DEFINE_CID(kBufferedOutputStreamCID, NS_BUFFEREDOUTPUTSTREAM_CID); + rv = nsComponentManager::CreateInstance(kBufferedOutputStreamCID, + nsnull, + NS_GET_IID(nsIBufferedOutputStream), + getter_AddRefs(out)); + if (NS_FAILED(rv)) return rv; + rv = out->Init(aStr, aBufferSize); + if (NS_FAILED(rv)) return rv; + + *aResult = out; + NS_ADDREF(*aResult); + return NS_OK; +} + +inline nsresult +NS_NewPostDataStream(nsIInputStream **result, + PRBool isFile, + const nsACString &data, + PRUint32 encodeFlags, + nsIIOService* ioService = nsnull) // pass in nsIIOService to optimize callers +{ + nsresult rv; + + if (isFile) { + nsCOMPtr file; + nsCOMPtr fileStream; + + rv = NS_NewNativeLocalFile(data, PR_FALSE, getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file); + if (NS_FAILED(rv)) return rv; + + // wrap the file stream with a buffered input stream + return NS_NewBufferedInputStream(result, fileStream, 8192); + } + + // otherwise, create a string stream for the data + return NS_NewCStringInputStream(result, data); +} + +#endif // nsNetUtil_h__ diff --git a/mozilla/netwerk/base/src/Makefile.in b/mozilla/netwerk/base/src/Makefile.in index 54ee9c23435..c874b0334ec 100644 --- a/mozilla/netwerk/base/src/Makefile.in +++ b/mozilla/netwerk/base/src/Makefile.in @@ -39,14 +39,15 @@ REQUIRES = xpcom \ $(NULL) CPPSRCS = \ + nsAsyncStreamCopier.cpp \ nsAsyncStreamListener.cpp \ nsBufferedStreams.cpp \ nsDirectoryIndexStream.cpp \ nsDownloader.cpp \ nsFileStreams.cpp \ - nsFileTransport.cpp \ - nsFileTransportService.cpp \ nsInputStreamChannel.cpp \ + nsInputStreamPump.cpp \ + nsStreamTransportService.cpp \ nsIOService.cpp \ nsLoadGroup.cpp \ nsMIMEInputStream.cpp \ @@ -56,17 +57,13 @@ CPPSRCS = \ nsRequestObserverProxy.cpp \ nsResumableEntityID.cpp \ nsSimpleStreamListener.cpp \ - nsSimpleStreamProvider.cpp \ nsSimpleURI.cpp \ nsStandardURL.cpp \ - nsSocketTransport.cpp \ - nsSocketTransportService.cpp \ - nsStorageTransport.cpp \ - nsStreamListenerProxy.cpp \ + nsSocketTransport2.cpp \ + nsSocketTransportService2.cpp \ nsStreamListenerTee.cpp \ nsStreamLoader.cpp \ nsUnicharStreamLoader.cpp \ - nsStreamProviderProxy.cpp \ nsURIChecker.cpp \ nsURLHelper.cpp \ nsURLParsers.cpp \ diff --git a/mozilla/netwerk/base/src/nsBufferedStreams.h b/mozilla/netwerk/base/src/nsBufferedStreams.h index 6809d3ded8e..57929228e96 100644 --- a/mozilla/netwerk/base/src/nsBufferedStreams.h +++ b/mozilla/netwerk/base/src/nsBufferedStreams.h @@ -38,9 +38,10 @@ #ifndef nsBufferedStreams_h__ #define nsBufferedStreams_h__ -#include "nsIFileStreams.h" +#include "nsIBufferedStreams.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "nsISeekableStream.h" #include "nsIStreamBufferAccess.h" #include "nsCOMPtr.h" diff --git a/mozilla/netwerk/base/src/nsDownloader.cpp b/mozilla/netwerk/base/src/nsDownloader.cpp index 82ff8b5da02..d00d030f333 100644 --- a/mozilla/netwerk/base/src/nsDownloader.cpp +++ b/mozilla/netwerk/base/src/nsDownloader.cpp @@ -44,55 +44,60 @@ #include "nsICachingChannel.h" #include "nsProxiedService.h" #include "nsIFile.h" +#include "nsIFileURL.h" #include "nsXPIDLString.h" static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); +// XXX this API seems all wrong for "sync" downloading + NS_IMETHODIMP nsDownloader::Init(nsIURI* aURL, nsIDownloadObserver* aObserver, nsISupports* aContext, PRBool aIsSynchronous, nsILoadGroup* aGroup, - nsIInterfaceRequestor* aNotificationCallbacks, - nsLoadFlags aLoadAttributes) + nsIInterfaceRequestor* aCallbacks, + nsLoadFlags aLoadFlags) { + NS_ENSURE_ARG_POINTER(aObserver); nsresult rv; + mObserver = aObserver; mContext = aContext; - nsCOMPtr localFile; - nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull, aGroup, aNotificationCallbacks, - aLoadAttributes); - if (NS_SUCCEEDED(rv) && channel) - { - nsCOMPtr fc = do_QueryInterface(channel); - if (fc) - rv = fc->GetFile(getter_AddRefs(localFile)); - } - if (mObserver && (NS_FAILED(rv) || localFile)) - { - if (aIsSynchronous) - return mObserver->OnDownloadComplete(this, mContext, rv, localFile); - else - { - // 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 - nsresult rv2 = NS_OK; - nsCOMPtr pIProxyObjectManager = - do_GetService(kProxyObjectManagerCID, &rv); - if (NS_FAILED(rv2)) return rv2; - nsCOMPtr pObserver; - rv2 = pIProxyObjectManager->GetProxyForObject(NS_CURRENT_EVENTQ, - NS_GET_IID(nsIDownloadObserver), mObserver, - PROXY_ASYNC | PROXY_ALWAYS, getter_AddRefs(pObserver)); - if (NS_FAILED(rv2)) return rv2; - return pObserver->OnDownloadComplete(this, mContext, rv, localFile); - } + nsCOMPtr file; + + nsCOMPtr 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 pIProxyObjectManager = + do_GetService(kProxyObjectManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr 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 channel; + rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull, + aGroup, aCallbacks, aLoadFlags); + if (NS_FAILED(rv)) return rv; + return channel->AsyncOpen(this, aContext); } diff --git a/mozilla/netwerk/base/src/nsFileStreams.cpp b/mozilla/netwerk/base/src/nsFileStreams.cpp index 878ef16a2c7..f51947019fd 100644 --- a/mozilla/netwerk/base/src/nsFileStreams.cpp +++ b/mozilla/netwerk/base/src/nsFileStreams.cpp @@ -71,7 +71,8 @@ #include "nsDirectoryIndexStream.h" #include "nsMimeTypes.h" #include "nsReadLine.h" -#include "nsFileTransportService.h" +#include "nsNetUtil.h" +//#include "nsFileTransportService.h" #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067 @@ -91,308 +92,6 @@ PRLogModuleInfo* gFileIOLog = nsnull; #endif /* PR_LOGGING */ -//////////////////////////////////////////////////////////////////////////////// -// nsFileIO - -#define NS_INPUT_STREAM_BUFFER_SIZE (16 * 1024) -#define NS_OUTPUT_STREAM_BUFFER_SIZE (64 * 1024) - -NS_IMPL_THREADSAFE_ISUPPORTS2(nsFileIO, - nsIFileIO, - nsIStreamIO) - -nsFileIO::nsFileIO() - : mFD(0), - mIOFlags(0), - mPerm(0), - mStatus(NS_OK) -{ -#if defined(PR_LOGGING) - // - // Initialize the global PRLogModule for socket transport logging - // if necessary... - // - if (nsnull == gFileIOLog) { - gFileIOLog = PR_NewLogModule("nsFileIO"); - } -#endif /* PR_LOGGING */ -} - -nsFileIO::~nsFileIO() -{ - (void)Close(NS_OK); - if (mFD) { - PR_Close(mFD); - mFD = nsnull; - } -} - -NS_METHOD -nsFileIO::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) -{ - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - nsFileIO* io = new nsFileIO(); - if (io == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(io); - nsresult rv = io->QueryInterface(aIID, aResult); - NS_RELEASE(io); - return rv; -} - -NS_IMETHODIMP -nsFileIO::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm) -{ - NS_ASSERTION(file, "File must not be null"); - if (file == nsnull) - return NS_ERROR_NOT_INITIALIZED; - - mFile = file; - mIOFlags = ioFlags; - mPerm = perm; -#ifdef PR_LOGGING - nsresult rv = mFile->GetNativePath(mSpec); - NS_ASSERTION(NS_SUCCEEDED(rv), "GetSpec failed"); -#endif - return NS_OK; -} - -NS_IMETHODIMP -nsFileIO::GetFile(nsIFile* *aFile) -{ - *aFile = mFile; - NS_ADDREF(*aFile); - return NS_OK; -} - -NS_IMETHODIMP -nsFileIO::Open() -{ - NS_ASSERTION(mFile, "File must not be null"); - if (mFile == nsnull) - return NS_ERROR_NOT_INITIALIZED; - - nsresult rv = NS_OK; - nsCOMPtr localFile = do_QueryInterface(mFile, &rv); - if (NS_FAILED(rv)) return rv; - if (mIOFlags == -1) - mIOFlags = PR_RDONLY; - if (mPerm == -1) - mPerm = 0; - - rv = localFile->OpenNSPRFileDesc(mIOFlags, mPerm, &mFD); - if (NS_FAILED(rv)) { - mFD = nsnull; // just in case -#ifdef PR_LOGGING - nsresult openError = rv; -#endif - // maybe we can't open this because it is a directory... - PRBool isDir; - rv = localFile->IsDirectory(&isDir); - if (NS_SUCCEEDED(rv) && isDir) { - return NS_OK; - } - PR_LOG(gFileIOLog, PR_LOG_DEBUG, - ("nsFileIO: OpenNSPRFileDesc failed [rv=%x]\n", openError)); - return NS_ERROR_FILE_NOT_FOUND; - } - - PR_LOG(gFileIOLog, PR_LOG_DEBUG, - ("nsFileIO: logically opening %s", mSpec.get())); - return rv; -} - -NS_IMETHODIMP -nsFileIO::GetContentType(nsACString &result) -{ - if (!mContentType.IsEmpty()) { - result = mContentType; - return NS_OK; - } - - if (mFile == nsnull) - return NS_ERROR_NOT_INITIALIZED; - - nsresult rv = NS_OK; - nsIMIMEService* mimeServ = nsnull; - nsFileTransportService* fileTransportService = nsFileTransportService::GetInstance(); - if (fileTransportService) { - mimeServ = fileTransportService->GetCachedMimeService(); - if (mimeServ) { - nsXPIDLCString mimeType; // XXX fix mime service to use |ACString| - rv = mimeServ->GetTypeFromFile(mFile, getter_Copies(mimeType)); - if (NS_SUCCEEDED(rv)) - result = mimeType; - } - } - - if (!mimeServ || (NS_FAILED(rv))) { - // if all else fails treat it as text/html? - result = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); - } - - mContentType = result; - return NS_OK; -} - -NS_IMETHODIMP -nsFileIO::GetContentCharset(nsACString &result) -{ - result.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -nsFileIO::GetContentLength(PRInt32 *result) -{ - NS_ENSURE_ARG_POINTER(result); - *result = -1; - - if (!mFile) - return NS_ERROR_NOT_INITIALIZED; - - // We'll try to use the file's length, if it has one. If not, - // assume the file to be special, and set the content length - // to -1, which means "read the stream until exhausted". - PRInt64 size; - nsresult rv = mFile->GetFileSize(&size); - if (NS_SUCCEEDED(rv)) { - *result = nsInt64(size); - if (*result == 0) - *result = -1; - } - return rv; -} - -NS_IMETHODIMP -nsFileIO::Close(nsresult status) -{ - if (mFile) { - PR_LOG(gFileIOLog, PR_LOG_DEBUG, - ("nsFileIO: logically closing %s: status=%x", - mSpec.get(), status)); - mFile = nsnull; - } - mStatus = status; - return NS_OK; -} - -NS_IMETHODIMP -nsFileIO::GetInputStream(nsIInputStream * *aInputStream) -{ - NS_ASSERTION(mFile, "File must not be null"); - if (!mFile) - return NS_ERROR_NOT_INITIALIZED; - - nsresult rv; - - if (!mFD) { - rv = Open(); - if (NS_FAILED(rv)) // file or directory does not exist - return rv; - } - - PRBool isDir; - rv = mFile->IsDirectory(&isDir); - if (NS_FAILED(rv)) // file or directory does not exist - return rv; - - if (isDir) { - if (mFD) { - PR_Close(mFD); - mFD = nsnull; - } - rv = nsDirectoryIndexStream::Create(mFile, aInputStream); - PR_LOG(gFileIOLog, PR_LOG_DEBUG, - ("nsFileIO: opening local dir %s for input (%x)", - mSpec.get(), rv)); - return rv; - } - - nsFileInputStream* fileIn = new nsFileInputStream(); - if (fileIn == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(fileIn); - rv = fileIn->InitWithFileDescriptor(mFD, this); - if (NS_SUCCEEDED(rv)) { -#ifdef NS_NO_INPUT_BUFFERING - *aInputStream = fileIn; - NS_ADDREF(*aInputStream); -#else - rv = NS_NewBufferedInputStream(aInputStream, - fileIn, - NS_INPUT_STREAM_BUFFER_SIZE); -#endif - } - NS_RELEASE(fileIn); - - PR_LOG(gFileIOLog, PR_LOG_DEBUG, - ("nsFileIO: opening local file %s for input (%x)", - mSpec.get(), rv)); - return rv; -} - -NS_IMETHODIMP -nsFileIO::GetOutputStream(nsIOutputStream * *aOutputStream) -{ - NS_ASSERTION(mFile, "File must not be null"); - if (mFile == nsnull) - return NS_ERROR_NOT_INITIALIZED; - - nsresult rv; - - if (!mFD) { - rv = Open(); - if (NS_FAILED(rv)) // file or directory does not exist - return rv; - } - - PRBool isDir; - rv = mFile->IsDirectory(&isDir); - if (NS_SUCCEEDED(rv) && isDir) { - return NS_ERROR_FAILURE; - } - - nsFileOutputStream* fileOut = new nsFileOutputStream(); - if (fileOut == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(fileOut); - rv = fileOut->InitWithFileDescriptor(mFD, this); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr bufStr; -#ifdef NS_NO_OUTPUT_BUFFERING - *aOutputStream = fileOut; - NS_ADDREF(*aOutputStream); -#else - rv = NS_NewBufferedOutputStream(aOutputStream, - fileOut, - NS_OUTPUT_STREAM_BUFFER_SIZE); -#endif - } - NS_RELEASE(fileOut); - - PR_LOG(gFileIOLog, PR_LOG_DEBUG, - ("nsFileIO: opening local file %s for output (%x)", - mSpec.get(), rv)); - return rv; -} - -NS_IMETHODIMP -nsFileIO::GetName(nsACString &aName) -{ - NS_ASSERTION(mFile, "File must not be null"); - if (mFile == nsnull) - return NS_ERROR_NOT_INITIALIZED; - - nsAutoString path; - nsresult rv = mFile->GetPath(path); - if (NS_FAILED(rv)) return rv; - - aName = NS_ConvertUCS2toUTF8(path); - return NS_OK; -} - //////////////////////////////////////////////////////////////////////////////// // nsFileStream diff --git a/mozilla/netwerk/base/src/nsFileStreams.h b/mozilla/netwerk/base/src/nsFileStreams.h index 3d1a639e228..52b9e01ddd8 100644 --- a/mozilla/netwerk/base/src/nsFileStreams.h +++ b/mozilla/netwerk/base/src/nsFileStreams.h @@ -40,44 +40,16 @@ #include "nsIFileStreams.h" #include "nsIFile.h" -#include "nsIChannel.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "nsISeekableStream.h" #include "nsILineInputStream.h" -#include "nsIStreamIO.h" #include "nsCOMPtr.h" #include "nsReadLine.h" #include "prlog.h" //////////////////////////////////////////////////////////////////////////////// -class nsFileIO : public nsIFileIO -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMIO - NS_DECL_NSIFILEIO - - nsFileIO(); - virtual ~nsFileIO(); - - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); - -protected: - nsCOMPtr mFile; - PRFileDesc* mFD; - PRInt32 mIOFlags; - PRInt32 mPerm; - nsresult mStatus; - nsCString mContentType; -#ifdef PR_LOGGING - nsCString mSpec; -#endif -}; - -//////////////////////////////////////////////////////////////////////////////// - class nsFileStream : public nsISeekableStream { public: diff --git a/mozilla/netwerk/base/src/nsIOService.cpp b/mozilla/netwerk/base/src/nsIOService.cpp index 3fec0985762..4e05bf4c5d9 100644 --- a/mozilla/netwerk/base/src/nsIOService.cpp +++ b/mozilla/netwerk/base/src/nsIOService.cpp @@ -41,7 +41,6 @@ #include "nscore.h" #include "nsIServiceManager.h" #include "nsIEventQueueService.h" -#include "nsIFileTransportService.h" #include "nsIURI.h" #include "nsIStreamListener.h" #include "prprf.h" @@ -53,7 +52,6 @@ #include "nsIErrorService.h" #include "netCore.h" #include "nsIObserverService.h" -#include "nsIHttpProtocolHandler.h" #include "nsIPrefService.h" #include "nsIPrefBranchInternal.h" #include "nsIPrefLocalizedString.h" @@ -66,12 +64,14 @@ #include "nsEscape.h" #include "nsNetCID.h" #include "nsIRecyclingAllocator.h" +#include "nsISocketTransport.h" +#include "nsCRT.h" #define PORT_PREF_PREFIX "network.security.ports." #define PORT_PREF(x) PORT_PREF_PREFIX x #define AUTODIAL_PREF "network.autodial-helper.enabled" -static NS_DEFINE_CID(kFileTransportService, NS_FILETRANSPORTSERVICE_CID); +static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID); static NS_DEFINE_CID(kErrorServiceCID, NS_ERRORSERVICE_CID); @@ -176,65 +176,52 @@ nsIOService::nsIOService() nsresult nsIOService::Init() { - nsresult rv = NS_OK; + nsresult rv; // Hold onto the eventQueue service. We do not want any eventqueues to go away // when we shutdown until we process all remaining transports - if (NS_SUCCEEDED(rv)) - mEventQueueService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); - + mEventQueueService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID); + if (NS_FAILED(rv)) + NS_WARNING("failed to get event queue service"); // We need to get references to these services so that we can shut them // down later. If we wait until the nsIOService is being shut down, // GetService will fail at that point. - rv = nsServiceManager::GetService(kSocketTransportServiceCID, - NS_GET_IID(nsISocketTransportService), - getter_AddRefs(mSocketTransportService)); - if (NS_FAILED(rv)) return rv; + mSocketTransportService = do_GetService(kSocketTransportServiceCID, &rv); + if (NS_FAILED(rv)) + NS_WARNING("failed to get socket transport service"); - rv = nsServiceManager::GetService(kFileTransportService, - NS_GET_IID(nsIFileTransportService), - getter_AddRefs(mFileTransportService)); - if (NS_FAILED(rv)) return rv; + mStreamTransportService = do_GetService(kStreamTransportServiceCID, &rv); + if (NS_FAILED(rv)) + NS_WARNING("failed to get stream transport service"); - rv = nsServiceManager::GetService(kDNSServiceCID, - NS_GET_IID(nsIDNSService), - getter_AddRefs(mDNSService)); - if (NS_FAILED(rv)) return rv; + mDNSService = do_GetService(kDNSServiceCID, &rv); + if (NS_FAILED(rv)) + NS_WARNING("failed to get DNS service"); - rv = nsServiceManager::GetService(kProtocolProxyServiceCID, - NS_GET_IID(nsIProtocolProxyService), - getter_AddRefs(mProxyService)); - if (NS_FAILED(rv)) return rv; + mProxyService = do_GetService(kProtocolProxyServiceCID, &rv); + if (NS_FAILED(rv)) + NS_WARNING("failed to get protocol proxy service"); - // XXX hack until xpidl supports error info directly (http://bugzilla.mozilla.org/show_bug.cgi?id=13423) - nsCOMPtr errorService = do_GetService(kErrorServiceCID, &rv); - if (NS_FAILED(rv)) - return rv; - - rv = errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK, NECKO_MSGS_URL); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_READ_FROM, "ReadFrom"); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_WROTE_TO, "WroteTo"); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_RESOLVING_HOST, "ResolvingHost"); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_CONNECTED_TO, "ConnectedTo"); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_SENDING_TO, "SendingTo"); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_RECEIVING_FROM, "ReceivingFrom"); - if (NS_FAILED(rv)) return rv; - rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_CONNECTING_TO, "ConnectingTo"); - if (NS_FAILED(rv)) return rv; + // XXX hack until xpidl supports error info directly (bug 13423) + nsCOMPtr errorService = do_GetService(kErrorServiceCID); + if (errorService) { + errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK, NECKO_MSGS_URL); + errorService->RegisterErrorStringBundleKey(nsISocketTransport::STATUS_RESOLVING, "ResolvingHost"); + errorService->RegisterErrorStringBundleKey(nsISocketTransport::STATUS_CONNECTED_TO, "ConnectedTo"); + errorService->RegisterErrorStringBundleKey(nsISocketTransport::STATUS_SENDING_TO, "SendingTo"); + errorService->RegisterErrorStringBundleKey(nsISocketTransport::STATUS_RECEIVING_FROM, "ReceivingFrom"); + errorService->RegisterErrorStringBundleKey(nsISocketTransport::STATUS_CONNECTING_TO, "ConnectingTo"); + errorService->RegisterErrorStringBundleKey(nsISocketTransport::STATUS_WAITING_FOR, "WaitingFor"); + } + else + NS_WARNING("failed to get error service"); // setup our bad port list stuff - for(int i=0; gBadPortList[i]; i++) { + for(int i=0; gBadPortList[i]; i++) mRestrictedPortList.AppendElement(NS_REINTERPRET_CAST(void *, gBadPortList[i])); - } // Further modifications to the port list come from prefs nsCOMPtr prefBranch; @@ -251,12 +238,13 @@ nsIOService::Init() // Register for profile change notifications nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); - NS_ASSERTION(observerService, "Failed to get observer service"); if (observerService) { observerService->AddObserver(this, kProfileChangeNetTeardownTopic, PR_TRUE); observerService->AddObserver(this, kProfileChangeNetRestoreTopic, PR_TRUE); observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE); } + else + NS_WARNING("failed to get observer service"); return NS_OK; } @@ -266,47 +254,6 @@ nsIOService::~nsIOService() { } -NS_METHOD -nsIOService::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) -{ - static nsISupports *_rValue = nsnull; - - nsresult rv; - NS_ENSURE_NO_AGGREGATION(aOuter); - - if (_rValue) - { - NS_ADDREF (_rValue); - *aResult = _rValue; - return NS_OK; - } - - nsIOService* _ios = new nsIOService(); - if (_ios == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(_ios); - rv = _ios->Init(); - if (NS_FAILED(rv)) - { - delete _ios; - return rv; - } - - rv = _ios->QueryInterface(aIID, aResult); - - if (NS_FAILED(rv)) - { - delete _ios; - return rv; - } - - _rValue = NS_STATIC_CAST (nsISupports*, *aResult); - NS_RELEASE (_rValue); - _rValue = nsnull; - - return rv; -} - NS_IMPL_THREADSAFE_ISUPPORTS3(nsIOService, nsIIOService, nsIObserver, @@ -481,8 +428,6 @@ nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result) { nsresult rv; NS_ENSURE_ARG_POINTER(aURI); - // If XPCOM shutdown has started, mProxyService could be null. - NS_ENSURE_TRUE(mProxyService, NS_ERROR_NOT_AVAILABLE); NS_TIMELINE_MARK_URI("nsIOService::NewChannelFromURI(%s)", aURI); nsCAutoString scheme; @@ -490,8 +435,11 @@ nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result) if (NS_FAILED(rv)) return rv; nsCOMPtr pi; - rv = mProxyService->ExamineForProxy(aURI, getter_AddRefs(pi)); - if (NS_FAILED(rv)) return rv; + if (mProxyService) { + rv = mProxyService->ExamineForProxy(aURI, getter_AddRefs(pi)); + if (NS_FAILED(rv)) + pi = 0; + } nsCOMPtr handler; @@ -535,50 +483,56 @@ nsIOService::GetOffline(PRBool *offline) NS_IMETHODIMP nsIOService::SetOffline(PRBool offline) { - nsCOMPtr - observerService(do_GetService("@mozilla.org/observer-service;1")); + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1"); - nsresult rv1 = NS_OK; - nsresult rv2 = NS_OK; + nsresult rv; if (offline) { NS_NAMED_LITERAL_STRING(offlineString, "offline"); - mOffline = PR_TRUE; // indicate we're trying to shutdown + mOffline = PR_TRUE; // indicate we're trying to shutdown + // don't care if notification fails - if (observerService) // this allows users to attempt a little cleanup before dns and socket transport are shut down. - (void)observerService->NotifyObservers(NS_STATIC_CAST(nsIIOService *, this), - "network:offline-about-to-go-offline", - offlineString.get()); - // be sure to try and shutdown both (even if the first fails) - if (mDNSService) - rv1 = mDNSService->Shutdown(); // shutdown dns service first, because it has callbacks for socket transport - if (mSocketTransportService) - rv2 = mSocketTransportService->Shutdown(); - if (NS_FAILED(rv1)) return rv1; - if (NS_FAILED(rv2)) return rv2; + if (observerService) + observerService->NotifyObservers(NS_STATIC_CAST(nsIIOService *, this), + "network:offline-about-to-go-offline", + offlineString.get()); + + // be sure to try and shutdown both (even if the first fails)... + // shutdown dns service first, because it has callbacks for socket transport + if (mDNSService) { + rv = mDNSService->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed"); + } + if (mSocketTransportService) { + rv = mSocketTransportService->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed"); + } // don't care if notification fails if (observerService) - (void)observerService->NotifyObservers(NS_STATIC_CAST(nsIIOService *, this), - "network:offline-status-changed", - offlineString.get()); + observerService->NotifyObservers(NS_STATIC_CAST(nsIIOService *, this), + "network:offline-status-changed", + offlineString.get()); } else if (!offline && mOffline) { // go online - if (mDNSService) - rv1 = mDNSService->Init(); - if (NS_FAILED(rv2)) return rv1; - - if (mSocketTransportService) - rv2 = mSocketTransportService->Init(); //XXX should we shutdown the dns service? - if (NS_FAILED(rv2)) return rv1; + if (mDNSService) { + rv = mDNSService->Init(); + NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed"); + } + if (mSocketTransportService) { + rv = mSocketTransportService->Init(); + NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed"); + } mOffline = PR_FALSE; // indicate success only AFTER we've // brought up the services + // don't care if notification fails if (observerService) - (void)observerService->NotifyObservers(NS_STATIC_CAST(nsIIOService *, this), - "network:offline-status-changed", - NS_LITERAL_STRING("online").get()); + observerService->NotifyObservers(NS_STATIC_CAST(nsIIOService *, this), + "network:offline-status-changed", + NS_LITERAL_STRING("online").get()); } return NS_OK; } @@ -718,12 +672,13 @@ nsIOService::Observe(nsISupports *subject, } } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - (void)SetOffline(PR_TRUE); - if (mFileTransportService) - (void)mFileTransportService->Shutdown(); + SetOffline(PR_TRUE); + + if (mStreamTransportService) + mStreamTransportService->Shutdown(); // Break circular reference. - mProxyService = nsnull; + mProxyService = 0; } return NS_OK; } diff --git a/mozilla/netwerk/base/src/nsIOService.h b/mozilla/netwerk/base/src/nsIOService.h index 35265038cac..95af5ec6bd1 100644 --- a/mozilla/netwerk/base/src/nsIOService.h +++ b/mozilla/netwerk/base/src/nsIOService.h @@ -42,7 +42,7 @@ #include "nsIIOService.h" #include "nsVoidArray.h" #include "nsISocketTransportService.h" -#include "nsIFileTransportService.h" +#include "nsIStreamTransportService.h" #include "nsIDNSService.h" #include "nsIProtocolProxyService.h" #include "nsCOMPtr.h" @@ -103,7 +103,7 @@ protected: PRPackedBool mOffline; PRPackedBool mOfflineForProfileChange; nsCOMPtr mSocketTransportService; - nsCOMPtr mFileTransportService; + nsCOMPtr mStreamTransportService; nsCOMPtr mDNSService; nsCOMPtr mProxyService; nsCOMPtr mEventQueueService; diff --git a/mozilla/netwerk/base/src/nsInputStreamChannel.cpp b/mozilla/netwerk/base/src/nsInputStreamChannel.cpp index 94765a2a342..53eec32bc49 100644 --- a/mozilla/netwerk/base/src/nsInputStreamChannel.cpp +++ b/mozilla/netwerk/base/src/nsInputStreamChannel.cpp @@ -36,233 +36,140 @@ * ***** END LICENSE BLOCK ***** */ #include "nsInputStreamChannel.h" -#include "nsCOMPtr.h" -#include "nsIIOService.h" #include "nsIServiceManager.h" -#include "nsIFileTransportService.h" -#include "nsXPIDLString.h" +#include "nsIStreamTransportService.h" +#include "nsIEventQueueService.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsITransport.h" #include "nsNetUtil.h" +#include "nsCOMPtr.h" +#include "prlog.h" -static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); +static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); -//////////////////////////////////////////////////////////////////////////////// -// nsInputStreamIO methods: +#if defined(PR_LOGGING) +// +// NSPR_LOG_MODULES=nsStreamChannel:5 +// +static PRLogModuleInfo *gStreamChannelLog = nsnull; +#endif -NS_IMPL_THREADSAFE_ISUPPORTS2(nsInputStreamIO, - nsIInputStreamIO, - nsIStreamIO) +#define LOG(args) PR_LOG(gStreamChannelLog, PR_LOG_DEBUG, args) +#define LOG_ENABLED() PR_LOG_TEST(gStreamChannelLog, 4) -nsInputStreamIO::nsInputStreamIO() - : mContentLength(-1), mStatus(NS_OK) +//----------------------------------------------------------------------------- +// nsInputStreamChannel methods +//----------------------------------------------------------------------------- + +nsInputStreamChannel::nsInputStreamChannel() + : mContentLength(-1) + , mLoadFlags(LOAD_NORMAL) + , mStatus(NS_OK) +{ +#if defined(PR_LOGGING) + if (!gStreamChannelLog) + gStreamChannelLog = PR_NewLogModule("nsStreamChannel"); +#endif +} + +nsInputStreamChannel::~nsInputStreamChannel() { } -nsInputStreamIO::~nsInputStreamIO() -{ - Close(NS_OK); -} +//----------------------------------------------------------------------------- +// nsInputStreamChannel::nsISupports +//----------------------------------------------------------------------------- -NS_METHOD -nsInputStreamIO::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) -{ - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - nsInputStreamIO* io = new nsInputStreamIO(); - if (io == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(io); - nsresult rv = io->QueryInterface(aIID, aResult); - NS_RELEASE(io); - return rv; -} +NS_IMPL_ISUPPORTS5(nsInputStreamChannel, + nsIChannel, + nsIRequest, + nsIStreamListener, + nsIRequestObserver, + nsIInputStreamChannel) + +//----------------------------------------------------------------------------- +// nsInputStreamChannel::nsIRequest +//----------------------------------------------------------------------------- NS_IMETHODIMP -nsInputStreamIO::Init(const nsACString &name, - nsIInputStream* input, - const nsACString &contentType, - const nsACString &contentCharset, - PRInt32 contentLength) -{ - mName = name; - mInputStream = input; - mContentLength = contentLength; - mContentCharset = contentCharset; - // mContentCharset is unchanged if not parsed - NS_ParseContentType(contentType, mContentType, mContentCharset); - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::Open() -{ - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::GetContentType(nsACString &aContentType) -{ - aContentType = mContentType; - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::GetContentCharset(nsACString &aContentCharset) -{ - aContentCharset = mContentCharset; - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::GetContentLength(PRInt32 *aContentLength) -{ - *aContentLength = mContentLength; - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::Close(nsresult status) -{ - mStatus = status; - if (mInputStream) - return mInputStream->Close(); - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::GetInputStream(nsIInputStream * *aInputStream) -{ - *aInputStream = mInputStream; - NS_IF_ADDREF(*aInputStream); - return NS_OK; -} - -NS_IMETHODIMP -nsInputStreamIO::GetOutputStream(nsIOutputStream * *aOutputStream) -{ - // this method should never be called - NS_NOTREACHED("nsInputStreamIO::GetOutputStream"); - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsInputStreamIO::GetName(nsACString &aName) -{ - aName = mName; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsStreamIOChannel methods: - -nsStreamIOChannel::nsStreamIOChannel() - : mContentLength(-1), - mBufferSegmentSize(0), mBufferMaxSize(0), - mLoadFlags(LOAD_NORMAL), mStatus(NS_OK) -{ -} - -nsStreamIOChannel::~nsStreamIOChannel() -{ -} - -NS_METHOD -nsStreamIOChannel::Create(nsISupports *aOuter, REFNSIID aIID, - void **aResult) -{ - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - nsStreamIOChannel* channel = new nsStreamIOChannel(); - if (channel == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(channel); - nsresult rv = channel->QueryInterface(aIID, aResult); - NS_RELEASE(channel); - return rv; -} - -NS_IMETHODIMP -nsStreamIOChannel::Init(nsIURI* uri, nsIStreamIO* io) -{ - mURI = uri; - mStreamIO = io; - return NS_OK; -} - -NS_INTERFACE_MAP_BEGIN(nsStreamIOChannel) - NS_INTERFACE_MAP_ENTRY(nsIStreamIOChannel) - NS_INTERFACE_MAP_ENTRY(nsIChannel) - NS_INTERFACE_MAP_ENTRY(nsIRequest) - NS_INTERFACE_MAP_ENTRY(nsIStreamListener) - NS_INTERFACE_MAP_ENTRY(nsIStreamProvider) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequestObserver, nsIStreamListener) - NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) - NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamListener) -NS_INTERFACE_MAP_END_THREADSAFE - -NS_IMPL_THREADSAFE_ADDREF(nsStreamIOChannel) -NS_IMPL_THREADSAFE_RELEASE(nsStreamIOChannel) - -NS_IMETHODIMP -nsStreamIOChannel::GetName(nsACString &result) +nsInputStreamChannel::GetName(nsACString &result) { return mURI->GetSpec(result); } NS_IMETHODIMP -nsStreamIOChannel::IsPending(PRBool *result) +nsInputStreamChannel::IsPending(PRBool *result) { - if (mRequest) - return mRequest->IsPending(result); - *result = PR_FALSE; + NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED); + return mPump->IsPending(result); +} + +NS_IMETHODIMP +nsInputStreamChannel::GetStatus(nsresult *status) +{ + if (mPump && NS_SUCCEEDED(mStatus)) + mPump->GetStatus(status); + else + *status = mStatus; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::GetStatus(nsresult *status) +nsInputStreamChannel::Cancel(nsresult status) { - *status = mStatus; - // if we don't have a status error of our own to report - // then we should propagate the status error of the underlying - // file transport (if we have one) - if (NS_SUCCEEDED(mStatus) && mRequest) - mRequest->GetStatus(status); + NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED); + return mPump->Cancel(status); +} +NS_IMETHODIMP +nsInputStreamChannel::Suspend() +{ + NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED); + return mPump->Suspend(); +} + +NS_IMETHODIMP +nsInputStreamChannel::Resume() +{ + NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED); + return mPump->Resume(); +} + +NS_IMETHODIMP +nsInputStreamChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) +{ + *aLoadFlags = mLoadFlags; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::Cancel(nsresult status) +nsInputStreamChannel::SetLoadFlags(nsLoadFlags aLoadFlags) { - NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); - mStatus = status; - if (mRequest) - return mRequest->Cancel(status); + mLoadFlags = aLoadFlags; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::Suspend(void) +nsInputStreamChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) { - if (mRequest) - return mRequest->Suspend(); + NS_IF_ADDREF(*aLoadGroup = mLoadGroup); return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::Resume(void) +nsInputStreamChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) { - if (mRequest) - return mRequest->Resume(); + mLoadGroup = aLoadGroup; return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIChannel implementation: -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsInputStreamChannel::nsIChannel implementation +//----------------------------------------------------------------------------- NS_IMETHODIMP -nsStreamIOChannel::GetOriginalURI(nsIURI* *aURI) +nsInputStreamChannel::GetOriginalURI(nsIURI **aURI) { *aURI = mOriginalURI ? mOriginalURI : mURI; NS_IF_ADDREF(*aURI); @@ -270,153 +177,64 @@ nsStreamIOChannel::GetOriginalURI(nsIURI* *aURI) } NS_IMETHODIMP -nsStreamIOChannel::SetOriginalURI(nsIURI* aURI) +nsInputStreamChannel::SetOriginalURI(nsIURI *aURI) { mOriginalURI = aURI; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::GetURI(nsIURI* *aURI) +nsInputStreamChannel::GetURI(nsIURI **aURI) { - *aURI = mURI; - NS_IF_ADDREF(*aURI); + NS_IF_ADDREF(*aURI = mURI); return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::Open(nsIInputStream **result) +nsInputStreamChannel::GetOwner(nsISupports **aOwner) { - // XXX not calling mStreamIO->Open(), does that matter? - return mStreamIO->GetInputStream(result); -} - -NS_IMETHODIMP -nsStreamIOChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) -{ - nsresult rv; - - NS_ASSERTION(listener, "no listener"); - SetListener(listener); - - if (mLoadGroup) { - rv = mLoadGroup->AddRequest(this, nsnull); - if (NS_FAILED(rv)) return rv; - } - - if (mFileTransport == nsnull) { - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - if (NS_FAILED(rv)) goto done; - - rv = fts->CreateTransportFromStreamIO(mStreamIO, PR_TRUE, - getter_AddRefs(mFileTransport)); - if (NS_FAILED(rv)) goto done; - } - - // Hook up the notification callbacks InterfaceRequestor... - { - nsCOMPtr requestor = - do_QueryInterface(NS_STATIC_CAST(nsIRequest*, this)); - rv = mFileTransport->SetNotificationCallbacks - (requestor, (mLoadFlags & nsIRequest::LOAD_BACKGROUND)); - if (NS_FAILED(rv)) goto done; - } - - rv = mFileTransport->AsyncRead(this, ctxt, 0, PRUint32(-1), 0, getter_AddRefs(mRequest)); - - done: - if (NS_FAILED(rv)) { - nsresult rv2; - rv2 = mLoadGroup->RemoveRequest(this, ctxt, rv); - NS_ASSERTION(NS_SUCCEEDED(rv2), "RemoveRequest failed"); - // release the transport so that we don't think we're in progress - mFileTransport = nsnull; - } - return rv; -} - -NS_IMETHODIMP -nsStreamIOChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) -{ - *aLoadFlags = mLoadFlags; + NS_IF_ADDREF(*aOwner = mOwner); return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::SetLoadFlags(nsLoadFlags aLoadFlags) -{ - mLoadFlags = aLoadFlags; - return NS_OK; -} - -NS_IMETHODIMP -nsStreamIOChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) -{ - *aLoadGroup = mLoadGroup.get(); - NS_IF_ADDREF(*aLoadGroup); - return NS_OK; -} - -NS_IMETHODIMP -nsStreamIOChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) -{ - mLoadGroup = aLoadGroup; - return NS_OK; -} - -NS_IMETHODIMP -nsStreamIOChannel::GetOwner(nsISupports* *aOwner) -{ - *aOwner = mOwner.get(); - NS_IF_ADDREF(*aOwner); - return NS_OK; -} - -NS_IMETHODIMP -nsStreamIOChannel::SetOwner(nsISupports* aOwner) +nsInputStreamChannel::SetOwner(nsISupports *aOwner) { mOwner = aOwner; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) +nsInputStreamChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) { - *aNotificationCallbacks = mCallbacks.get(); - NS_IF_ADDREF(*aNotificationCallbacks); - return NS_OK; + NS_IF_ADDREF(*aCallbacks = mCallbacks); + return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) +nsInputStreamChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) { - nsresult rv = NS_OK; - mCallbacks = aNotificationCallbacks; - mProgressSink = do_GetInterface(mCallbacks); - return rv; + mCallbacks = aCallbacks; + mProgressSink = do_GetInterface(mCallbacks); + return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) +nsInputStreamChannel::GetSecurityInfo(nsISupports **aSecurityInfo) { *aSecurityInfo = nsnull; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::GetContentType(nsACString &aContentType) +nsInputStreamChannel::GetContentType(nsACString &aContentType) { - if (mContentType.IsEmpty()) { - nsresult rv = mStreamIO->GetContentType(mContentType); - if (NS_FAILED(rv)) return rv; - } aContentType = mContentType; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::SetContentType(const nsACString &aContentType) +nsInputStreamChannel::SetContentType(const nsACString &aContentType) { // mContentCharset is unchanged if not parsed NS_ParseContentType(aContentType, mContentType, mContentCharset); @@ -424,133 +242,134 @@ nsStreamIOChannel::SetContentType(const nsACString &aContentType) } NS_IMETHODIMP -nsStreamIOChannel::GetContentCharset(nsACString &aContentCharset) +nsInputStreamChannel::GetContentCharset(nsACString &aContentCharset) { - if (mContentCharset.IsEmpty()) { - nsresult rv = mStreamIO->GetContentCharset(mContentCharset); - if (NS_FAILED(rv)) return rv; - } aContentCharset = mContentCharset; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::SetContentCharset(const nsACString &aContentCharset) +nsInputStreamChannel::SetContentCharset(const nsACString &aContentCharset) { mContentCharset = aContentCharset; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::GetContentLength(PRInt32 *aContentLength) +nsInputStreamChannel::GetContentLength(PRInt32 *aContentLength) { - nsresult rv; - if (mContentLength == -1) { - rv = mStreamIO->GetContentLength(&mContentLength); - if (NS_FAILED(rv)) return rv; - } *aContentLength = mContentLength; - return NS_OK; + return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::SetContentLength(PRInt32 aContentLength) +nsInputStreamChannel::SetContentLength(PRInt32 aContentLength) { + // XXX does this really make any sense at all? mContentLength = aContentLength; return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIRequestObserver implementation: -//////////////////////////////////////////////////////////////////////////////// - NS_IMETHODIMP -nsStreamIOChannel::OnStartRequest(nsIRequest *request, nsISupports* context) +nsInputStreamChannel::Open(nsIInputStream **result) { - NS_ASSERTION(mUserObserver, "No listener..."); - return mUserObserver->OnStartRequest(this, context); + NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS); + + NS_ADDREF(*result = mContentStream); + return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::OnStopRequest(nsIRequest *request, nsISupports* context, nsresult aStatus) +nsInputStreamChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) { - if (mUserObserver) - mUserObserver->OnStopRequest(this, context, aStatus); + NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS); + + if (mContentLength == -1) + mContentStream->Available((PRUint32 *) &mContentLength); + + nsresult rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mContentStream, + -1, mContentLength, 0, 0, PR_TRUE); + if (NS_FAILED(rv)) return rv; + + rv = mPump->AsyncRead(this, nsnull); + if (NS_FAILED(rv)) return rv; if (mLoadGroup) - mLoadGroup->RemoveRequest(this, context, aStatus); + mLoadGroup->AddRequest(this, nsnull); - // Release the reference to the consumer stream listener... - mRequest = 0; - mFileTransport = 0; - mUserObserver = 0; - - // Make sure the stream io is closed - mStreamIO->Close(aStatus); - - // There is no point in returning anything other than NS_OK + mListener = listener; + mListenerContext = ctxt; return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamListener implementation: -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsInputStreamChannel::nsIInputStreamChannel implementation +//----------------------------------------------------------------------------- NS_IMETHODIMP -nsStreamIOChannel::OnDataAvailable(nsIRequest *request, nsISupports* context, - nsIInputStream *aIStream, PRUint32 aSourceOffset, - PRUint32 aLength) +nsInputStreamChannel::SetURI(nsIURI *uri) { - return GetListener()->OnDataAvailable(this, context, aIStream, - aSourceOffset, aLength); -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamProvider implementation: -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsStreamIOChannel::OnDataWritable(nsIRequest *request, nsISupports *context, - nsIOutputStream *aOStream, - PRUint32 aOffset, PRUint32 aLength) -{ - return GetProvider()->OnDataWritable(this, context, aOStream, - aOffset, aLength); -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIProgressEventSink implementation: -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsStreamIOChannel::OnProgress(nsIRequest *request, nsISupports *context, - PRUint32 progress, PRUint32 progressMax) -{ - if (mProgressSink) - mProgressSink->OnProgress(this, context, progress, progressMax); + NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS); + mURI = uri; return NS_OK; } NS_IMETHODIMP -nsStreamIOChannel::OnStatus(nsIRequest *request, nsISupports *context, - nsresult status, const PRUnichar *statusText) +nsInputStreamChannel::GetContentStream(nsIInputStream **stream) { - if (mProgressSink) - mProgressSink->OnStatus(this, context, status, statusText); + NS_IF_ADDREF(*stream = mContentStream); return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIInterfaceRequestor implementation: -//////////////////////////////////////////////////////////////////////////////// - NS_IMETHODIMP -nsStreamIOChannel::GetInterface(const nsIID &iid, void **result) +nsInputStreamChannel::SetContentStream(nsIInputStream *stream) { - if (iid.Equals(NS_GET_IID(nsIProgressEventSink))) - return QueryInterface(iid, result); - - return NS_ERROR_NO_INTERFACE; + NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS); + mContentStream = stream; + return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsInputStreamChannel::nsIStreamListener implementation +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsInputStreamChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx) +{ + return mListener->OnStartRequest(this, mListenerContext); +} + +NS_IMETHODIMP +nsInputStreamChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) +{ + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, mStatus); + + mPump = 0; + mContentStream = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, + PRUint32 offset, PRUint32 count) +{ + nsresult rv; + + rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); + + if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND)) + mProgressSink->OnProgress(this, nsnull, offset + count, mContentLength); + + return rv; // let the pump cancel on failure +} diff --git a/mozilla/netwerk/base/src/nsInputStreamChannel.h b/mozilla/netwerk/base/src/nsInputStreamChannel.h index ade4e63c98a..b52f2f313ff 100644 --- a/mozilla/netwerk/base/src/nsInputStreamChannel.h +++ b/mozilla/netwerk/base/src/nsInputStreamChannel.h @@ -38,91 +38,51 @@ #ifndef nsInputStreamChannel_h__ #define nsInputStreamChannel_h__ -#include "nsIStreamIOChannel.h" +#include "nsString.h" +#include "nsCOMPtr.h" + +#include "nsIInputStreamChannel.h" +#include "nsIInputStreamPump.h" #include "nsIInputStream.h" #include "nsIURI.h" -#include "nsCRT.h" #include "nsILoadGroup.h" #include "nsIStreamListener.h" -#include "nsIStreamProvider.h" #include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" #include "nsIProgressEventSink.h" -#include "nsIStreamIO.h" -#include "nsITransport.h" -#include "nsString.h" -class nsInputStreamIO : public nsIInputStreamIO -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMIO - NS_DECL_NSIINPUTSTREAMIO +//----------------------------------------------------------------------------- - nsInputStreamIO(); - virtual ~nsInputStreamIO(); - - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); - -protected: - nsCString mName; - nsCOMPtr mInputStream; - nsCString mContentType; - nsCString mContentCharset; - PRInt32 mContentLength; - nsresult mStatus; -}; - -//////////////////////////////////////////////////////////////////////////////// - -class nsStreamIOChannel : public nsIStreamIOChannel, - public nsIStreamListener, - public nsIStreamProvider, - public nsIProgressEventSink, - public nsIInterfaceRequestor +class nsInputStreamChannel : public nsIInputStreamChannel + , public nsIStreamListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL - NS_DECL_NSISTREAMIOCHANNEL + NS_DECL_NSIINPUTSTREAMCHANNEL NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSISTREAMPROVIDER - NS_DECL_NSIPROGRESSEVENTSINK - NS_DECL_NSIINTERFACEREQUESTOR - nsStreamIOChannel(); - virtual ~nsStreamIOChannel(); - - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + nsInputStreamChannel(); + virtual ~nsInputStreamChannel(); protected: - nsIStreamListener* GetListener() { return (nsIStreamListener*)mUserObserver.get(); } - void SetListener(nsIStreamListener* listener) { mUserObserver = listener; } - nsIStreamProvider* GetProvider() { return (nsIStreamProvider*)mUserObserver.get(); } - void SetProvider(nsIStreamProvider* provider) { mUserObserver = provider; } -protected: + nsCOMPtr mPump; nsCOMPtr mCallbacks; nsCOMPtr mProgressSink; nsCOMPtr mOriginalURI; nsCOMPtr mURI; + nsCOMPtr mLoadGroup; + nsCOMPtr mOwner; + nsCOMPtr mListener; + nsCOMPtr mListenerContext; + nsCOMPtr mContentStream; nsCString mContentType; nsCString mContentCharset; PRInt32 mContentLength; - nsCOMPtr mStreamIO; - nsCOMPtr mLoadGroup; - nsCOMPtr mOwner; - nsCOMPtr mFileTransport; - nsCOMPtr mRequest; - nsCOMPtr mUserObserver; - PRUint32 mBufferSegmentSize; - PRUint32 mBufferMaxSize; PRUint32 mLoadFlags; nsresult mStatus; }; -#endif // nsInputStreamChannel_h__ +#endif // !nsInputStreamChannel_h__ diff --git a/mozilla/netwerk/base/src/nsProtocolProxyService.cpp b/mozilla/netwerk/base/src/nsProtocolProxyService.cpp index bccf9e3a2aa..d2845fa856e 100644 --- a/mozilla/netwerk/base/src/nsProtocolProxyService.cpp +++ b/mozilla/netwerk/base/src/nsProtocolProxyService.cpp @@ -441,11 +441,11 @@ nsProtocolProxyService::NewProxyInfo(const char *aType, const char *type = nsnull; // canonicalize type - if (PL_strcasecmp(aType, "http")) + if (PL_strcasecmp(aType, "http") == 0) type = "http"; - else if (PL_strcasecmp(aType, "socks")) + else if (PL_strcasecmp(aType, "socks") == 0) type = "socks"; - else if (PL_strcasecmp(aType, "socks4")) + else if (PL_strcasecmp(aType, "socks4") == 0) type = "socks4"; else return NS_ERROR_INVALID_ARG; diff --git a/mozilla/netwerk/base/src/nsStreamLoader.cpp b/mozilla/netwerk/base/src/nsStreamLoader.cpp index 4a911aad6bd..cff346e8dab 100644 --- a/mozilla/netwerk/base/src/nsStreamLoader.cpp +++ b/mozilla/netwerk/base/src/nsStreamLoader.cpp @@ -40,7 +40,7 @@ #include "nsIURL.h" #include "nsNetUtil.h" #include "nsIChannel.h" -#include "nsIHttpChannel.h" +//#include "nsIHttpChannel.h" #include "nsProxiedService.h" static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); diff --git a/mozilla/netwerk/build/nsNetCID.h b/mozilla/netwerk/build/nsNetCID.h index b42ffd9ffc1..34e32bf2b96 100644 --- a/mozilla/netwerk/build/nsNetCID.h +++ b/mozilla/netwerk/build/nsNetCID.h @@ -152,32 +152,6 @@ {0x9c, 0x46, 0xd0, 0x3f, 0xaa, 0x7b, 0x69, 0x6b} \ } -// component implementing nsIStreamListenerProxy. -#define NS_STREAMLISTENERPROXY_CLASSNAME \ - "nsStreamListenerProxy" -#define NS_STREAMLISTENERPROXY_CONTRACTID \ - "@mozilla.org/network/stream-listener-proxy;1" -#define NS_STREAMLISTENERPROXY_CID \ -{ /* 96c48f15-aa8a-4da7-a9d5-e842bd76f015 */ \ - 0x96c48f15, \ - 0xaa8a, \ - 0x4da7, \ - {0xa9, 0xd5, 0xe8, 0x42, 0xbd, 0x76, 0xf0, 0x15} \ -} - -// component implementing nsIStreamProviderProxy. -#define NS_STREAMPROVIDERPROXY_CLASSNAME \ - "nsStreamProviderProxy" -#define NS_STREAMPROVIDERPROXY_CONTRACTID \ - "@mozilla.org/network/stream-provider-proxy;1" -#define NS_STREAMPROVIDERPROXY_CID \ -{ /* ae964fcf-9c27-40f7-9bbd-78894bfc1f31 */ \ - 0xae964fcf, \ - 0x9c27, \ - 0x40f7, \ - {0x9b, 0xbd, 0x78, 0x89, 0x4b, 0xfc, 0x1f, 0x31} \ -} - // component implementing nsISimpleStreamListener. #define NS_SIMPLESTREAMLISTENER_CLASSNAME \ "nsSimpleStreamListener" @@ -191,19 +165,6 @@ {0xb1, 0xd6, 0x53, 0x88, 0xe0, 0x41, 0xfb, 0x67} \ } -// component implementing nsISimpleStreamProvider. -#define NS_SIMPLESTREAMPROVIDER_CLASSNAME \ - "nsSimpleStreamProvider" -#define NS_SIMPLESTREAMPROVIDER_CONTRACTID \ - "@mozilla.org/network/simple-stream-provider;1" -#define NS_SIMPLESTREAMPROVIDER_CID \ -{ /* f9f6a519-4efb-4f36-af40-2a5ec3992710 */ \ - 0xf9f6a519, \ - 0x4efb, \ - 0x4f36, \ - {0xaf, 0x40, 0x2a, 0x5e, 0xc3, 0x99, 0x27, 0x10} \ -} - // DEPRECATED component implementing nsIAsyncStreamListener. #define NS_ASYNCSTREAMLISTENER_CLASSNAME \ "nsAsyncStreamListener" @@ -230,31 +191,38 @@ {0xb0, 0x2e, 0x77, 0xc8, 0x81, 0xcc, 0x57, 0x73} \ } -// A simple implementation of nsITransport that stores a segmented memory -// buffer (4k chunks). As long as the nsITransport is referenced, the data -// remains in memory. It can be read multiple times (only AsyncRead is -// implemented). There can be only one writer at a time (only OpenOutputStream -// is implemented). AsyncRead can be called while an output stream is still -// being written to. The readers will get notified automatically as more -// data is written via the output stream. -#define NS_STORAGETRANSPORT_CLASSNAME \ - "nsStorageTransport" -#define NS_STORAGETRANSPORT_CONTRACTID \ - "@mozilla.org/network/storage-transport;1" -#define NS_STORAGETRANSPORT_CID \ -{ /* 5e955cdb-1334-4b8f-86b5-3b0f4d54b9d2 */ \ - 0x5e955cdb, \ - 0x1334, \ - 0x4b8f, \ - {0x86, 0xb5, 0x3b, 0x0f, 0x4d, 0x54, 0xb9, 0xd2} \ +// component implementing nsIAsyncStreamCopier. +#define NS_ASYNCSTREAMCOPIER_CLASSNAME \ + "nsAsyncStreamCopier" +#define NS_ASYNCSTREAMCOPIER_CONTRACTID \ + "@mozilla.org/network/async-stream-copier;1" +#define NS_ASYNCSTREAMCOPIER_CID \ +{ /* e746a8b1-c97a-4fc5-baa4-66607521bd08 */ \ + 0xe746a8b1, \ + 0xc97a, \ + 0x4fc5, \ + {0xba, 0xa4, 0x66, 0x60, 0x75, 0x21, 0xbd, 0x08} \ } -// component implementing nsIStreamIOChannel. -#define NS_STREAMIOCHANNEL_CLASSNAME \ +// component implementing nsIInputStreamPump. +#define NS_INPUTSTREAMPUMP_CLASSNAME \ + "nsInputStreamPump" +#define NS_INPUTSTREAMPUMP_CONTRACTID \ + "@mozilla.org/network/input-stream-pump;1" +#define NS_INPUTSTREAMPUMP_CID \ +{ /* ccd0e960-7947-4635-b70e-4c661b63d675 */ \ + 0xccd0e960, \ + 0x7947, \ + 0x4635, \ + {0xb7, 0x0e, 0x4c, 0x66, 0x1b, 0x63, 0xd6, 0x75} \ +} + +// component implementing nsIInputStreamChannel. +#define NS_INPUTSTREAMCHANNEL_CLASSNAME \ "nsInputStreamChannel" -#define NS_STREAMIOCHANNEL_CONTRACTID \ - "@mozilla.org/network/stream-io-channel;1" -#define NS_STREAMIOCHANNEL_CID \ +#define NS_INPUTSTREAMCHANNEL_CONTRACTID \ + "@mozilla.org/network/input-stream-channel;1" +#define NS_INPUTSTREAMCHANNEL_CID \ { /* 6ddb050c-0d04-11d4-986e-00c04fa0cf4a */ \ 0x6ddb050c, \ 0x0d04, \ @@ -327,6 +295,92 @@ {0xb9, 0x5c, 0xe5, 0xd6, 0x7a, 0x34, 0xe6, 0xb3} \ } +// service implementing nsIStreamTransportService +#define NS_STREAMTRANSPORTSERVICE_CLASSNAME \ + "nsStreamTransportService" +#define NS_STREAMTRANSPORTSERVICE_CONTRACTID \ + "@mozilla.org/network/stream-transport-service;1" +#define NS_STREAMTRANSPORTSERVICE_CID \ +{ /* 0885d4f8-f7b8-4cda-902e-94ba38bc256e */ \ + 0x0885d4f8, \ + 0xf7b8, \ + 0x4cda, \ + {0x90, 0x2e, 0x94, 0xba, 0x38, 0xbc, 0x25, 0x6e} \ +} + +// service implementing nsISocketTransportService +#define NS_SOCKETTRANSPORTSERVICE_CLASSNAME \ + "nsSocketTransportService" +#define NS_SOCKETTRANSPORTSERVICE_CONTRACTID \ + "@mozilla.org/network/socket-transport-service;1" +#define NS_SOCKETTRANSPORTSERVICE_CID \ +{ /* c07e81e0-ef12-11d2-92b6-00105a1b0d64 */ \ + 0xc07e81e0, \ + 0xef12, \ + 0x11d2, \ + {0x92, 0xb6, 0x00, 0x10, 0x5a, 0x1b, 0x0d, 0x64} \ +} + +#define NS_FILETRANSPORTSERVICE_CLASSNAME \ + "nsFileTransportService" +#define NS_FILETRANSPORTSERVICE_CONTRACTID \ + "@mozilla.org/network/file-transport-service;1" +#define NS_FILETRANSPORTSERVICE_CID \ +{ /* 2bb2b250-ea35-11d2-931b-00104ba0fd40 */ \ + 0x2bb2b250, \ + 0xea35, \ + 0x11d2, \ + {0x93, 0x1b, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +#define NS_LOCALFILEINPUTSTREAM_CLASSNAME \ + "nsFileInputStream" +#define NS_LOCALFILEINPUTSTREAM_CONTRACTID \ + "@mozilla.org/network/file-input-stream;1" +#define NS_LOCALFILEINPUTSTREAM_CID \ +{ /* be9a53ae-c7e9-11d3-8cda-0060b0fc14a3 */ \ + 0xbe9a53ae, \ + 0xc7e9, \ + 0x11d3, \ + {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ +} + +#define NS_LOCALFILEOUTPUTSTREAM_CLASSNAME \ + "nsFileOutputStream" +#define NS_LOCALFILEOUTPUTSTREAM_CONTRACTID \ + "@mozilla.org/network/file-output-stream;1" +#define NS_LOCALFILEOUTPUTSTREAM_CID \ +{ /* c272fee0-c7e9-11d3-8cda-0060b0fc14a3 */ \ + 0xc272fee0, \ + 0xc7e9, \ + 0x11d3, \ + {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ +} + +#define NS_BUFFEREDINPUTSTREAM_CLASSNAME \ + "nsBufferedInputStream" +#define NS_BUFFEREDINPUTSTREAM_CONTRACTID \ + "@mozilla.org/network/buffered-input-stream;1" +#define NS_BUFFEREDINPUTSTREAM_CID \ +{ /* 9226888e-da08-11d3-8cda-0060b0fc14a3 */ \ + 0x9226888e, \ + 0xda08, \ + 0x11d3, \ + {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ +} + +#define NS_BUFFEREDOUTPUTSTREAM_CLASSNAME \ + "nsBufferedOutputStream" +#define NS_BUFFEREDOUTPUTSTREAM_CONTRACTID \ + "@mozilla.org/network/buffered-output-stream;1" +#define NS_BUFFEREDOUTPUTSTREAM_CID \ +{ /* 9868b4ce-da08-11d3-8cda-0060b0fc14a3 */ \ + 0x9868b4ce, \ + 0xda08, \ + 0x11d3, \ + {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ +} + /****************************************************************************** * netwerk/cache/ classes @@ -386,6 +440,8 @@ * netwerk/protocol/res/ classes */ +#define NS_RESPROTOCOLHANDLER_CLASSNAME \ + "nsResProtocolHandler" #define NS_RESPROTOCOLHANDLER_CID \ { /* e64f152a-9f07-11d3-8cda-0060b0fc14a3 */ \ 0xe64f152a, \ @@ -394,6 +450,48 @@ {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ } +/****************************************************************************** + * netwerk/protocol/file/ classes + */ + +#define NS_FILEPROTOCOLHANDLER_CLASSNAME \ + "nsFileProtocolHandler" +#define NS_FILEPROTOCOLHANDLER_CID \ +{ /* fbc81170-1f69-11d3-9344-00104ba0fd40 */ \ + 0xfbc81170, \ + 0x1f69, \ + 0x11d3, \ + {0x93, 0x44, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +/****************************************************************************** + * netwerk/protocol/data/ classes + */ + +#define NS_DATAPROTOCOLHANDLER_CLASSNAME \ + "nsDataProtocolHandler" +#define NS_DATAPROTOCOLHANDLER_CID \ +{ /* {B6ED3030-6183-11d3-A178-0050041CAF44} */ \ + 0xb6ed3030, \ + 0x6183, \ + 0x11d3, \ + {0xa1, 0x78, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \ +} + +/****************************************************************************** + * netwerk/protocol/data/ classes + */ + +#define NS_JARPROTOCOLHANDLER_CLASSNAME \ + "nsJarProtocolHandler" +#define NS_JARPROTOCOLHANDLER_CID \ +{ /* 0xc7e410d4-0x85f2-11d3-9f63-006008a6efe9 */ \ + 0xc7e410d4, \ + 0x85f2, \ + 0x11d3, \ + {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ +} + /****************************************************************************** * netwerk/dns/ classes diff --git a/mozilla/netwerk/build/nsNetModule.cpp b/mozilla/netwerk/build/nsNetModule.cpp index 660bf6593dc..ee89c2db3e4 100644 --- a/mozilla/netwerk/build/nsNetModule.cpp +++ b/mozilla/netwerk/build/nsNetModule.cpp @@ -41,16 +41,12 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsICategoryManager.h" -#include "nsIOService.h" #include "nsNetModuleMgr.h" -#include "nsFileTransportService.h" -#include "nsSocketTransportService.h" #include "nsSocketProviderService.h" #include "nscore.h" #include "nsSimpleURI.h" #include "nsDnsService.h" #include "nsLoadGroup.h" -#include "nsInputStreamChannel.h" #include "nsStreamLoader.h" #include "nsUnicharStreamLoader.h" #include "nsDownloader.h" @@ -75,6 +71,27 @@ /////////////////////////////////////////////////////////////////////////////// +#include "nsIOService.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsIOService, Init) + +#include "nsStreamTransportService.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStreamTransportService, Init) + +#include "nsSocketTransportService2.h" +#undef LOG +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSocketTransportService, Init) + +#include "nsAsyncStreamCopier.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAsyncStreamCopier) + +#include "nsInputStreamPump.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsInputStreamPump) + +#include "nsInputStreamChannel.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsInputStreamChannel) + +/////////////////////////////////////////////////////////////////////////////// + #include "nsStreamConverterService.h" #ifdef BUILD_APPLEFILE_DECODER @@ -91,18 +108,12 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMIMEInfoImpl) /////////////////////////////////////////////////////////////////////////////// #include "nsRequestObserverProxy.h" -#include "nsStreamListenerProxy.h" -#include "nsStreamProviderProxy.h" #include "nsSimpleStreamListener.h" -#include "nsSimpleStreamProvider.h" #include "nsDirIndexParser.h" #include "nsDirIndex.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsRequestObserverProxy) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamListenerProxy) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamProviderProxy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleStreamListener) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleStreamProvider) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDirIndexParser, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDirIndex) @@ -113,15 +124,10 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamListenerTee) /////////////////////////////////////////////////////////////////////////////// -#include "nsStorageTransport.h" - -NS_GENERIC_FACTORY_CONSTRUCTOR(nsStorageTransport) - -/////////////////////////////////////////////////////////////////////////////// - #include "nsHttpHandler.h" #include "nsHttpBasicAuth.h" #include "nsHttpDigestAuth.h" +#undef LOG NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpHandler, Init) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpsHandler, Init) @@ -160,10 +166,13 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsIDNService) /////////////////////////////////////////////////////////////////////////////// -#include "nsFileChannel.h" #include "nsFileProtocolHandler.h" -#include "nsDataHandler.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFileProtocolHandler, Init) + #include "nsJARProtocolHandler.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsJARProtocolHandler, Init) + +#include "nsDataHandler.h" #include "nsAboutProtocolHandler.h" #include "nsAboutBlank.h" @@ -515,15 +524,15 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { { NS_IOSERVICE_CLASSNAME, NS_IOSERVICE_CID, NS_IOSERVICE_CONTRACTID, - nsIOService::Create }, - { "File Transport Service", - NS_FILETRANSPORTSERVICE_CID, - "@mozilla.org/network/file-transport-service;1", - nsFileTransportService::Create }, - { "Socket Transport Service", + nsIOServiceConstructor }, + { NS_STREAMTRANSPORTSERVICE_CLASSNAME, + NS_STREAMTRANSPORTSERVICE_CID, + NS_STREAMTRANSPORTSERVICE_CONTRACTID, + nsStreamTransportServiceConstructor }, + { NS_SOCKETTRANSPORTSERVICE_CLASSNAME, NS_SOCKETTRANSPORTSERVICE_CID, - "@mozilla.org/network/socket-transport-service;1", - nsSocketTransportService::Create }, + NS_SOCKETTRANSPORTSERVICE_CONTRACTID, + nsSocketTransportServiceConstructor }, { "Socket Provider Service", NS_SOCKETPROVIDERSERVICE_CID, "@mozilla.org/network/socket-provider-service;1", @@ -544,18 +553,18 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_NETMODULEMGR_CID, "@mozilla.org/network/net-extern-mod;1", nsNetModuleMgr::Create }, - { NS_FILEIO_CLASSNAME, - NS_FILEIO_CID, - NS_FILEIO_CONTRACTID, - nsFileIO::Create }, - { NS_INPUTSTREAMIO_CLASSNAME, - NS_INPUTSTREAMIO_CID, - NS_INPUTSTREAMIO_CONTRACTID, - nsInputStreamIO::Create }, - { NS_STREAMIOCHANNEL_CLASSNAME, - NS_STREAMIOCHANNEL_CID, - NS_STREAMIOCHANNEL_CONTRACTID, - nsStreamIOChannel::Create }, + { NS_ASYNCSTREAMCOPIER_CLASSNAME, + NS_ASYNCSTREAMCOPIER_CID, + NS_ASYNCSTREAMCOPIER_CONTRACTID, + nsAsyncStreamCopierConstructor }, + { NS_INPUTSTREAMPUMP_CLASSNAME, + NS_INPUTSTREAMPUMP_CID, + NS_INPUTSTREAMPUMP_CONTRACTID, + nsInputStreamPumpConstructor }, + { NS_INPUTSTREAMCHANNEL_CLASSNAME, + NS_INPUTSTREAMCHANNEL_CID, + NS_INPUTSTREAMCHANNEL_CONTRACTID, + nsInputStreamChannelConstructor }, { NS_STREAMLOADER_CLASSNAME, NS_STREAMLOADER_CID, NS_STREAMLOADER_CONTRACTID, @@ -572,22 +581,10 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_REQUESTOBSERVERPROXY_CID, NS_REQUESTOBSERVERPROXY_CONTRACTID, nsRequestObserverProxyConstructor }, - { NS_STREAMLISTENERPROXY_CLASSNAME, - NS_STREAMLISTENERPROXY_CID, - NS_STREAMLISTENERPROXY_CONTRACTID, - nsStreamListenerProxyConstructor }, - { NS_STREAMPROVIDERPROXY_CLASSNAME, - NS_STREAMPROVIDERPROXY_CID, - NS_STREAMPROVIDERPROXY_CONTRACTID, - nsStreamProviderProxyConstructor }, { NS_SIMPLESTREAMLISTENER_CLASSNAME, NS_SIMPLESTREAMLISTENER_CID, NS_SIMPLESTREAMLISTENER_CONTRACTID, nsSimpleStreamListenerConstructor }, - { NS_SIMPLESTREAMPROVIDER_CLASSNAME, - NS_SIMPLESTREAMPROVIDER_CID, - NS_SIMPLESTREAMPROVIDER_CONTRACTID, - nsSimpleStreamProviderConstructor }, { NS_ASYNCSTREAMLISTENER_CLASSNAME, NS_ASYNCSTREAMLISTENER_CID, NS_ASYNCSTREAMLISTENER_CONTRACTID, @@ -596,10 +593,6 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_STREAMLISTENERTEE_CID, NS_STREAMLISTENERTEE_CONTRACTID, nsStreamListenerTeeConstructor }, - { NS_STORAGETRANSPORT_CLASSNAME, - NS_STORAGETRANSPORT_CID, - NS_STORAGETRANSPORT_CONTRACTID, - nsStorageTransportConstructor }, { NS_LOADGROUP_CLASSNAME, NS_LOADGROUP_CID, NS_LOADGROUP_CONTRACTID, @@ -786,12 +779,6 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { nsDirIndexConstructor }, -#if defined(OLD_CACHE) - // from netwerk/cache: - { "Memory Cache", NS_MEM_CACHE_FACTORY_CID, NS_NETWORK_MEMORY_CACHE_CONTRACTID, nsMemCacheConstructor }, - { "File Cache", NS_NETDISKCACHE_CID, NS_NETWORK_FILE_CACHE_CONTRACTID, nsNetDiskCacheConstructor }, - { "Cache Manager",NS_CACHE_MANAGER_CID, NS_NETWORK_CACHE_MANAGER_CONTRACTID,nsCacheManagerConstructor }, -#endif // from netwerk/mime: { "xml mime INFO", NS_MIMEINFO_CID, @@ -800,15 +787,10 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { }, // from netwerk/protocol/file: - { "File Protocol Handler", + { NS_FILEPROTOCOLHANDLER_CLASSNAME, NS_FILEPROTOCOLHANDLER_CID, NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file", - nsFileProtocolHandler::Create - }, - { NS_LOCALFILECHANNEL_CLASSNAME, - NS_LOCALFILECHANNEL_CID, - NS_LOCALFILECHANNEL_CONTRACTID, - nsFileChannel::Create + nsFileProtocolHandlerConstructor }, { "HTTP Handler", @@ -839,20 +821,20 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { }, // from netwerk/protocol/data: - { "Data Protocol Handler", - NS_DATAHANDLER_CID, + { NS_DATAPROTOCOLHANDLER_CLASSNAME, + NS_DATAPROTOCOLHANDLER_CID, NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "data", nsDataHandler::Create}, // from netwerk/protocol/jar: - { "JAR Protocol Handler", - NS_JARPROTOCOLHANDLER_CID, - NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar", - nsJARProtocolHandler::Create + { NS_JARPROTOCOLHANDLER_CLASSNAME, + NS_JARPROTOCOLHANDLER_CID, + NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar", + nsJARProtocolHandlerConstructor }, // from netwerk/protocol/res: - { "Resource Protocol Handler", + { NS_RESPROTOCOLHANDLER_CLASSNAME, NS_RESPROTOCOLHANDLER_CID, NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource", nsResProtocolHandlerConstructor @@ -899,6 +881,7 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", nsAboutRedirector::Create }, + { "about:cache", NS_ABOUT_CACHE_MODULE_CID, NS_ABOUT_MODULE_CONTRACTID_PREFIX "cache", @@ -909,6 +892,7 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_ABOUT_MODULE_CONTRACTID_PREFIX "cache-entry", nsAboutCacheEntryConstructor }, + // from netwerk/protocol/keyword: { "The Keyword Protocol Handler", NS_KEYWORDPROTOCOLHANDLER_CID, diff --git a/mozilla/netwerk/cache/Makefile.in b/mozilla/netwerk/cache/Makefile.in index 7c5342f74db..48d334a78da 100644 --- a/mozilla/netwerk/cache/Makefile.in +++ b/mozilla/netwerk/cache/Makefile.in @@ -26,10 +26,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = \ - public \ - src \ - $(NULL) +DIRS = public src include $(topsrcdir)/config/rules.mk diff --git a/mozilla/netwerk/cache/public/nsICacheEntryDescriptor.idl b/mozilla/netwerk/cache/public/nsICacheEntryDescriptor.idl index 978b6738885..8254aba3515 100644 --- a/mozilla/netwerk/cache/public/nsICacheEntryDescriptor.idl +++ b/mozilla/netwerk/cache/public/nsICacheEntryDescriptor.idl @@ -29,7 +29,8 @@ interface nsISimpleEnumerator; interface nsICacheListener; -interface nsITransport; +interface nsIInputStream; +interface nsIOutputStream; interface nsIFile; interface nsICacheMetaDataVisitor; @@ -50,10 +51,33 @@ interface nsICacheEntryDescriptor : nsICacheEntryInfo void setDataSize(in unsigned long size); /** - * Get a transport to the cache data. This will fail if the cache entry - * IS NOT stream based. + * Open blocking input stream to cache data. This will fail if the cache + * entry IS NOT stream based. Use the stream transport service to + * asynchronously read this stream on a background thread. The returned + * stream MAY implement nsISeekableStream. + * + * @param offset + * read starting from this offset into the cached data. + * + * @return blocking, unbuffered input stream. */ - readonly attribute nsITransport transport; + nsIInputStream openInputStream(in unsigned long offset); + + /** + * Open blocking output stream to cache data. This will fail if the cache + * entry IS NOT stream based. Use the stream transport service to + * asynchronously write to this stream on a background thread. The returned + * stream MAY implement nsISeekableStream. + * + * If opening an output stream to existing cached data, the data will be + * truncated to the specified offset. + * + * @param offset + * write starting from this offset into the cached data. + * + * @return blocking, unbuffered output stream. + */ + nsIOutputStream openOutputStream(in unsigned long offset); /** * Get/set the cache data element. This will fail if the cache entry diff --git a/mozilla/netwerk/cache/src/Makefile.in b/mozilla/netwerk/cache/src/Makefile.in index 783107287ab..a0d17b0727d 100644 --- a/mozilla/netwerk/cache/src/Makefile.in +++ b/mozilla/netwerk/cache/src/Makefile.in @@ -48,13 +48,13 @@ CPPSRCS = \ nsCacheMetaData.cpp \ nsCacheService.cpp \ nsCacheSession.cpp \ + nsMemoryCacheDevice.cpp \ nsDiskCacheBinding.cpp \ nsDiskCacheBlockFile.cpp \ nsDiskCacheDevice.cpp \ nsDiskCacheEntry.cpp \ nsDiskCacheMap.cpp \ nsDiskCacheStreams.cpp \ - nsMemoryCacheDevice.cpp \ $(NULL) include $(topsrcdir)/config/config.mk diff --git a/mozilla/netwerk/cache/src/nsCacheDevice.h b/mozilla/netwerk/cache/src/nsCacheDevice.h index 26c1e35d0c7..844efb25c80 100644 --- a/mozilla/netwerk/cache/src/nsCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsCacheDevice.h @@ -32,7 +32,8 @@ class nsIFile; class nsCString; class nsCacheEntry; class nsICacheVisitor; -class nsITransport; +class nsIInputStream; +class nsIOutputStream; /****************************************************************************** * nsCacheDevice @@ -52,9 +53,15 @@ public: virtual nsresult BindEntry( nsCacheEntry * entry ) = 0; virtual void DoomEntry( nsCacheEntry * entry ) = 0; - virtual nsresult GetTransportForEntry( nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport **result ) = 0; + virtual nsresult OpenInputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result) = 0; + + virtual nsresult OpenOutputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result) = 0; virtual nsresult GetFileForEntry( nsCacheEntry * entry, nsIFile ** result ) = 0; diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp index 308975adbd6..8e9fa37484d 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp @@ -233,14 +233,48 @@ nsCacheEntryDescriptor::SetDataSize(PRUint32 dataSize) NS_IMETHODIMP -nsCacheEntryDescriptor::GetTransport(nsITransport ** result) +nsCacheEntryDescriptor::OpenInputStream(PRUint32 offset, nsIInputStream ** result) { NS_ENSURE_ARG_POINTER(result); - nsAutoLock lock(nsCacheService::ServiceLock()); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; - NS_ADDREF(*result = &mTransportWrapper); + { + nsAutoLock lock(nsCacheService::ServiceLock()); + if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; + + // ensure valid permissions + if (!(mAccessGranted & nsICache::ACCESS_READ)) + return NS_ERROR_CACHE_READ_ACCESS_DENIED; + } + + nsInputStreamWrapper* cacheInput = + new nsInputStreamWrapper(this, offset); + if (!cacheInput) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*result = cacheInput); + return NS_OK; +} + +NS_IMETHODIMP +nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset, nsIOutputStream ** result) +{ + NS_ENSURE_ARG_POINTER(result); + + { + nsAutoLock lock(nsCacheService::ServiceLock()); + if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; + + // ensure valid permissions + if (!(mAccessGranted & nsICache::ACCESS_WRITE)) + return NS_ERROR_CACHE_WRITE_ACCESS_DENIED; + } + + nsOutputStreamWrapper* cacheOutput = + new nsOutputStreamWrapper(this, offset); + if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*result = cacheOutput); return NS_OK; } @@ -438,259 +472,122 @@ nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor) /****************************************************************************** - * nsCacheTransportWrapper + * nsCacheInputStream - a wrapper for nsIInputstream keeps the cache entry + * open while referenced. ******************************************************************************/ -NS_IMPL_QUERY_INTERFACE1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport) - - -// special AddRef and Release, because we are part of the descriptor -#define GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(_this) \ - ((nsCacheEntryDescriptor*)((char*)(_this) - \ - offsetof(nsCacheEntryDescriptor, mTransportWrapper))) - -NS_IMETHODIMP_(nsrefcnt) nsCacheEntryDescriptor:: -nsTransportWrapper::AddRef(void) -{ - return GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this)->AddRef(); -} - -NS_IMETHODIMP_(nsrefcnt) nsCacheEntryDescriptor:: -nsTransportWrapper::Release(void) -{ - return GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this)->Release(); -} - +NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsInputStreamWrapper, + nsIInputStream) nsresult nsCacheEntryDescriptor:: -nsTransportWrapper::EnsureTransportWithAccess(nsCacheAccessMode mode) +nsInputStreamWrapper::LazyInit() { - nsresult rv = NS_OK; + nsAutoLock lock(nsCacheService::ServiceLock()); - nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this); - nsAutoLock lock(nsCacheService::ServiceLock()); - if (!descriptor->mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - if (!descriptor->mAccessGranted & mode) { - rv = (mode == nsICache::ACCESS_READ) ? - NS_ERROR_CACHE_READ_ACCESS_DENIED : NS_ERROR_CACHE_WRITE_ACCESS_DENIED; - return rv; - } - - if (!mTransport) { - rv = nsCacheService::GetTransportForEntry(descriptor->mCacheEntry, - descriptor->mAccessGranted, - getter_AddRefs(mTransport)); - if (NS_FAILED(rv)) return rv; - - if (mCallbacks) { - mTransport->SetNotificationCallbacks(mCallbacks, mCallbackFlags); - } - } - return NS_OK; -} - - -nsresult -nsCacheEntryDescriptor::NewOutputStreamWrapper(nsIOutputStream ** result, - nsCacheEntryDescriptor * descriptor, - nsIOutputStream * output) -{ - nsOutputStreamWrapper* cacheOutput = - new nsOutputStreamWrapper(descriptor, output); - if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY; - - nsCOMPtr ref(cacheOutput); - nsresult rv = cacheOutput->Init(); + nsCacheAccessMode mode; + nsresult rv = mDescriptor->GetAccessGranted(&mode); if (NS_FAILED(rv)) return rv; - NS_ADDREF(*result = cacheOutput); + NS_ENSURE_TRUE(mode & nsICache::ACCESS_READ, NS_ERROR_UNEXPECTED); + + nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); + if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; + + nsCOMPtr input; + rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode, + mStartOffset, + getter_AddRefs(mInput)); + if (NS_FAILED(rv)) return rv; + + mInitialized = PR_TRUE; return NS_OK; } - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::GetSecurityInfo(nsISupports ** securityInfo) +nsresult nsCacheEntryDescriptor:: +nsInputStreamWrapper::Close() { + nsresult rv = EnsureInit(); + if (NS_FAILED(rv)) return rv; + + return mInput->Close(); +} + +nsresult nsCacheEntryDescriptor:: +nsInputStreamWrapper::Available(PRUint32 *avail) +{ + nsresult rv = EnsureInit(); + if (NS_FAILED(rv)) return rv; + + return mInput->Available(avail); +} + +nsresult nsCacheEntryDescriptor:: +nsInputStreamWrapper::Read(char *buf, PRUint32 count, PRUint32 *countRead) +{ + nsresult rv = EnsureInit(); + if (NS_FAILED(rv)) return rv; + + return mInput->Read(buf, count, countRead); +} + +nsresult nsCacheEntryDescriptor:: +nsInputStreamWrapper::ReadSegments(nsWriteSegmentFun writer, void *closure, + PRUint32 count, PRUint32 *countRead) +{ + NS_NOTREACHED("cache stream not buffered"); return NS_ERROR_NOT_IMPLEMENTED; } - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::GetNotificationCallbacks(nsIInterfaceRequestor **result) +nsresult nsCacheEntryDescriptor:: +nsInputStreamWrapper::IsNonBlocking(PRBool *result) { - NS_ENSURE_ARG_POINTER(result); - - *result = mCallbacks; - NS_IF_ADDREF(*result); - + // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK + *result = PR_FALSE; return NS_OK; } -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::SetNotificationCallbacks(nsIInterfaceRequestor *requestor, - PRUint32 flags) -{ - if (mTransport) { - mTransport->SetNotificationCallbacks(requestor, flags); - } - - mCallbacks = requestor; - mCallbackFlags = flags; - - return NS_OK;; -} - - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::OpenInputStream(PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIInputStream ** result) -{ - NS_ENSURE_ARG_POINTER(result); - - nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_READ); - if (NS_FAILED(rv)) return rv; - - return mTransport->OpenInputStream(offset, count, flags, result); -} - - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::OpenOutputStream(PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIOutputStream ** result) -{ - NS_ENSURE_ARG_POINTER(result); - - nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE); - if (NS_FAILED(rv)) return rv; - - // Create the underlying output stream using the wrapped transport. - nsCOMPtr output; - rv = mTransport->OpenOutputStream(offset, count, flags, getter_AddRefs(output)); - if (NS_FAILED(rv)) return rv; - - // Wrap this output stream with a stream that monitors how much data gets written, - // maintains the cache entry's size, and informs the cache device. - // This mechanism provides a way for the cache device to enforce space limits, - // and to drive cache entry eviction. - nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this); - - // reset datasize of entry based on offset so OnWrite calculates delta changes correctly. - rv = descriptor->SetDataSize(offset); - if (NS_FAILED(rv)) return rv; - - return NewOutputStreamWrapper(result, descriptor, output); -} - - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::AsyncRead(nsIStreamListener * listener, - nsISupports * ctxt, - PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIRequest ** result) -{ - NS_ENSURE_ARG_POINTER(result); - - nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_READ); - if (NS_FAILED(rv)) return rv; - - return mTransport->AsyncRead(listener, ctxt, offset, count, flags, result); -} - - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsTransportWrapper::AsyncWrite(nsIStreamProvider * provider, - nsISupports * ctxt, - PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIRequest ** result) -{ - // we're not planning on implementing this - return NS_ERROR_NOT_IMPLEMENTED; - -#if 0 - NS_ENSURE_ARG_POINTER(result); - - nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE); - if (NS_FAILED(rv)) return rv; - - return mTransport->AsyncWrite(provider, ctxt, offset, count, flags, result); -#endif -} - - /****************************************************************************** * nsCacheOutputStream - a wrapper for nsIOutputstream to track the amount of * data written to a cache entry. + * - also keeps the cache entry open while referenced. ******************************************************************************/ -NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor::nsOutputStreamWrapper, nsIOutputStream); +NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsOutputStreamWrapper, + nsIOutputStream) nsresult nsCacheEntryDescriptor:: -nsOutputStreamWrapper::Init() +nsOutputStreamWrapper::LazyInit() { + nsAutoLock lock(nsCacheService::ServiceLock()); + nsCacheAccessMode mode; nsresult rv = mDescriptor->GetAccessGranted(&mode); if (NS_FAILED(rv)) return rv; - if (mode == nsICache::ACCESS_WRITE) { - nsAutoLock lock(nsCacheService::ServiceLock()); - nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); - if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_TRUE(mode & nsICache::ACCESS_WRITE, NS_ERROR_UNEXPECTED); - nsCacheDevice* device = cacheEntry->CacheDevice(); - if (!device) return NS_ERROR_NOT_AVAILABLE; + nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); + if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; - // the entry has been truncated to zero bytes, inform the device. - PRInt32 delta = cacheEntry->DataSize(); - rv = device->OnDataSizeChange(cacheEntry, -delta); - cacheEntry->SetDataSize(0); - } - return rv; -} - - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsOutputStreamWrapper::Write(const char * buf, - PRUint32 count, - PRUint32 * result) -{ - nsresult rv = OnWrite(count); + rv = nsCacheService::OpenOutputStreamForEntry(cacheEntry, mode, mStartOffset, + getter_AddRefs(mOutput)); if (NS_FAILED(rv)) return rv; - return mOutput->Write(buf, count, result); -} + nsCacheDevice* device = cacheEntry->CacheDevice(); + if (!device) return NS_ERROR_NOT_AVAILABLE; -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr, - PRUint32 count, - PRUint32 * result) -{ - nsresult rv = OnWrite(count); + // the entry has been truncated to mStartOffset bytes, inform the device. + PRInt32 size = cacheEntry->DataSize(); + rv = device->OnDataSizeChange(cacheEntry, mStartOffset - size); if (NS_FAILED(rv)) return rv; - return mOutput->WriteFrom(inStr, count, result); + + cacheEntry->SetDataSize(mStartOffset); + + mInitialized = PR_TRUE; + return NS_OK; } - -NS_IMETHODIMP nsCacheEntryDescriptor:: -nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader, - void * closure, - PRUint32 count, - PRUint32 * result) -{ - nsresult rv = OnWrite(count); - if (NS_FAILED(rv)) return rv; - return mOutput->WriteSegments(reader, closure, count, result); -} - - nsresult nsCacheEntryDescriptor:: nsOutputStreamWrapper::OnWrite(PRUint32 count) { @@ -698,4 +595,61 @@ nsOutputStreamWrapper::OnWrite(PRUint32 count) return mDescriptor->RequestDataSizeChange((PRInt32)count); } +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::Close() +{ + nsresult rv = EnsureInit(); + if (NS_FAILED(rv)) return rv; + return mOutput->Close(); +} + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::Flush() +{ + nsresult rv = EnsureInit(); + if (NS_FAILED(rv)) return rv; + + return mOutput->Flush(); +} + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::Write(const char * buf, + PRUint32 count, + PRUint32 * result) +{ + nsresult rv = EnsureInit(); + if (NS_FAILED(rv)) return rv; + + rv = OnWrite(count); + if (NS_FAILED(rv)) return rv; + + return mOutput->Write(buf, count, result); +} + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr, + PRUint32 count, + PRUint32 * result) +{ + NS_NOTREACHED("cache stream not buffered"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader, + void * closure, + PRUint32 count, + PRUint32 * result) +{ + NS_NOTREACHED("cache stream not buffered"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::IsNonBlocking(PRBool *result) +{ + // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK + *result = PR_FALSE; + return NS_OK; +} diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h index 0ca53074893..67493144ef4 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h +++ b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h @@ -27,10 +27,8 @@ #include "nsICacheEntryDescriptor.h" #include "nsCacheEntry.h" +#include "nsIInputStream.h" #include "nsIOutputStream.h" -#include "nsITransport.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" /****************************************************************************** * nsCacheEntryDescriptor @@ -64,98 +62,85 @@ public: private: + /************************************************************************* - * transport wrapper class - + * input stream wrapper class - * - * we want the transport wrapper to have the same lifetime as the - * descriptor, but since they each need to reference the other, we have the - * descriptor include the transport wrapper as a member, rather than just - * pointing to it, which avoids circular AddRefs. + * The input stream wrapper references the descriptor, but the descriptor + * doesn't need any references to the stream wrapper. *************************************************************************/ - class nsTransportWrapper : public nsITransport - { + class nsInputStreamWrapper : public nsIInputStream { + private: + nsCacheEntryDescriptor * mDescriptor; + nsCOMPtr mInput; + PRUint32 mStartOffset; + PRBool mInitialized; public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSITRANSPORT + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM - nsTransportWrapper() : mCallbackFlags(0) {} - virtual ~nsTransportWrapper() {} + nsInputStreamWrapper(nsCacheEntryDescriptor * desc, PRUint32 off) + : mDescriptor(desc) + , mStartOffset(off) + , mInitialized(PR_FALSE) + { + NS_ADDREF(mDescriptor); + } + virtual ~nsInputStreamWrapper() + { + NS_RELEASE(mDescriptor); + } - nsresult EnsureTransportWithAccess(nsCacheAccessMode mode); - - PRUint32 mCallbackFlags; - - nsCOMPtr mTransport; - nsCOMPtr mCallbacks; - }; // end of class nsTransportWrapper - friend class nsTransportWrapper; + private: + nsresult LazyInit(); + nsresult EnsureInit() { return mInitialized ? NS_OK : LazyInit(); } + }; + friend class nsInputStreamWrapper; /************************************************************************* * output stream wrapper class - * * The output stream wrapper references the descriptor, but the descriptor - * doesn't need any references to the stream wrapper, so we don't need the - * same kind of tricks that we're using for the transport wrapper. + * doesn't need any references to the stream wrapper. *************************************************************************/ class nsOutputStreamWrapper : public nsIOutputStream { private: - nsCacheEntryDescriptor * mDescriptor; - nsCOMPtr mOutput; + nsCacheEntryDescriptor * mDescriptor; + nsCOMPtr mOutput; + PRUint32 mStartOffset; + PRBool mInitialized; public: NS_DECL_ISUPPORTS - // NS_DECL_NSIOUTPUTSTREAM - NS_IMETHOD Close(void) { return mOutput->Close(); } - NS_IMETHOD Flush(void) { return mOutput->Flush(); } + NS_DECL_NSIOUTPUTSTREAM - NS_IMETHOD Write(const char * buf, - PRUint32 count, - PRUint32 * result); - - NS_IMETHOD WriteFrom(nsIInputStream * inStr, - PRUint32 count, - PRUint32 * result); - - NS_IMETHOD WriteSegments(nsReadSegmentFun reader, - void * closure, - PRUint32 count, - PRUint32 * result); - - NS_IMETHOD IsNonBlocking(PRBool * nonBlocking) - { return mOutput->IsNonBlocking(nonBlocking); } - - nsOutputStreamWrapper(nsCacheEntryDescriptor * descriptor, - nsIOutputStream * output) - : mDescriptor(nsnull), mOutput(output) + nsOutputStreamWrapper(nsCacheEntryDescriptor * desc, PRUint32 off) + : mDescriptor(desc) + , mStartOffset(off) + , mInitialized(PR_FALSE) { - NS_ADDREF(mDescriptor = descriptor); + NS_ADDREF(mDescriptor); // owning ref } - virtual ~nsOutputStreamWrapper() - { + { + // XXX _HACK_ the storage stream needs this! + Close(); NS_RELEASE(mDescriptor); } - - nsresult Init(); - private: + nsresult LazyInit(); + nsresult EnsureInit() { return mInitialized ? NS_OK : LazyInit(); } nsresult OnWrite(PRUint32 count); - }; // end of class nsOutputStreamWrapper + }; friend class nsOutputStreamWrapper; - - - static nsresult NewOutputStreamWrapper(nsIOutputStream ** result, - nsCacheEntryDescriptor * descriptor, - nsIOutputStream * output); private: /** * nsCacheEntryDescriptor data members */ nsCacheEntry * mCacheEntry; // we are a child of the entry nsCacheAccessMode mAccessGranted; - nsTransportWrapper mTransportWrapper; }; diff --git a/mozilla/netwerk/cache/src/nsCacheService.cpp b/mozilla/netwerk/cache/src/nsCacheService.cpp index d38795f4ddd..bb4ea24a8ce 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.cpp +++ b/mozilla/netwerk/cache/src/nsCacheService.cpp @@ -40,6 +40,7 @@ #include "nsIPrefBranch.h" #include "nsIPrefBranchInternal.h" #include "nsIPref.h" +#include "nsILocalFile.h" #include "nsDirectoryServiceDefs.h" #include "nsAppDirectoryServiceDefs.h" #include "nsVoidArray.h" @@ -1240,14 +1241,27 @@ nsCacheService::GetFileForEntry(nsCacheEntry * entry, nsresult -nsCacheService::GetTransportForEntry(nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** result) +nsCacheService::OpenInputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result) { nsCacheDevice * device = gService->EnsureEntryHasDevice(entry); if (!device) return NS_ERROR_UNEXPECTED; - return device->GetTransportForEntry(entry, mode, result); + return device->OpenInputStreamForEntry(entry, mode, offset, result); +} + +nsresult +nsCacheService::OpenOutputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result) +{ + nsCacheDevice * device = gService->EnsureEntryHasDevice(entry); + if (!device) return NS_ERROR_UNEXPECTED; + + return device->OpenOutputStreamForEntry(entry, mode, offset, result); } diff --git a/mozilla/netwerk/cache/src/nsCacheService.h b/mozilla/netwerk/cache/src/nsCacheService.h index fab35c5c023..9c5925734d3 100644 --- a/mozilla/netwerk/cache/src/nsCacheService.h +++ b/mozilla/netwerk/cache/src/nsCacheService.h @@ -86,9 +86,15 @@ public: static nsresult GetFileForEntry(nsCacheEntry * entry, nsIFile ** result); - static nsresult GetTransportForEntry(nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** result); + static nsresult OpenInputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result); + + static nsresult OpenOutputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result); static nsresult OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize); diff --git a/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp b/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp index 299c7b568ec..aec7817430e 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheBinding.cpp @@ -110,6 +110,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheBinding); nsDiskCacheBinding::nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record) : mCacheEntry(entry) + , mStreamIO(nsnull) { NS_ASSERTION(record->ValidRecord(), "bad record"); PR_INIT_CLIST(this); @@ -125,9 +126,21 @@ nsDiskCacheBinding::~nsDiskCacheBinding() PR_REMOVE_LINK(this); // XXX why are we still on a list? // sever streamIO/binding link - // XXX what's the right way to call a method on the concrete class? - nsDiskCacheStreamIO * streamIO = (nsDiskCacheStreamIO *)mStreamIO.get(); - if (streamIO) streamIO->ClearBinding(); + if (mStreamIO) { + mStreamIO->ClearBinding(); + NS_RELEASE(mStreamIO); + } +} + +nsresult +nsDiskCacheBinding::EnsureStreamIO() +{ + if (!mStreamIO) { + mStreamIO = new nsDiskCacheStreamIO(this); + if (!mStreamIO) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mStreamIO); + } + return NS_OK; } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheBinding.h b/mozilla/netwerk/cache/src/nsDiskCacheBinding.h index c04039651d9..9629eaff1ff 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheBinding.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheBinding.h @@ -52,12 +52,13 @@ public: nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record); virtual ~nsDiskCacheBinding(); + nsresult EnsureStreamIO(); // XXX make friends public: nsCacheEntry* mCacheEntry; // back pointer to parent nsCacheEntry nsDiskCacheRecord mRecord; - nsCOMPtr mStreamIO; + nsDiskCacheStreamIO* mStreamIO; PRBool mDoomed; // record is not stored in cache map PRUint8 mGeneration; // possibly just reservation }; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp index 1bd752b0452..3bc67cbf2ad 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheDevice.cpp @@ -55,8 +55,6 @@ #include "nsCacheService.h" #include "nsCache.h" -#include "nsIFileTransportService.h" -#include "nsITransport.h" #include "nsICacheVisitor.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" @@ -310,7 +308,6 @@ nsDiskCache::Truncate(PRFileDesc * fd, PRUint32 newEOF) /****************************************************************************** * nsDiskCacheDevice *****************************************************************************/ -static nsCOMPtr gFileTransportService; #ifdef XP_MAC #pragma mark - @@ -345,10 +342,6 @@ nsDiskCacheDevice::Init() rv = mBindery.Init(); if (NS_FAILED(rv)) return rv; - // hold the file transport service to avoid excessive calls to the service manager. - gFileTransportService = do_GetService("@mozilla.org/network/file-transport-service;1", &rv); - if (NS_FAILED(rv)) return rv; - // XXX we should spawn another thread to do this after startup // delete "Cache.Trash" folder nsCOMPtr cacheTrashDir; @@ -379,7 +372,6 @@ error_exit: delete mCacheMap; mCacheMap = nsnull; } - gFileTransportService = nsnull; return rv; } @@ -405,9 +397,6 @@ nsDiskCacheDevice::Shutdown() mInitialized = PR_FALSE; } - // release the reference to the cached file transport service. - gFileTransportService = nsnull; - return NS_OK; } @@ -596,33 +585,52 @@ nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry) } } - /** * NOTE: called while holding the cache service lock */ nsresult -nsDiskCacheDevice::GetTransportForEntry(nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** result) +nsDiskCacheDevice::OpenInputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result) { NS_ENSURE_ARG_POINTER(entry); NS_ENSURE_ARG_POINTER(result); nsresult rv; nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); - NS_ASSERTION(binding, "GetTransportForEntry: binding == nsnull"); - if (!binding) return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(binding, NS_ERROR_UNEXPECTED); NS_ASSERTION(binding->mCacheEntry == entry, "binding & entry don't point to each other"); - if (!binding->mStreamIO) { - binding->mStreamIO = new nsDiskCacheStreamIO(binding); - if (!binding->mStreamIO) return NS_ERROR_OUT_OF_MEMORY; - } - // XXX assumption: CreateTransportFromStreamIO() is light-weight - // PR_FALSE = keep streamIO open for lifetime of transport - rv = gFileTransportService->CreateTransportFromStreamIO(binding->mStreamIO, PR_FALSE, result); - return rv; + rv = binding->EnsureStreamIO(); + if (NS_FAILED(rv)) return rv; + + return binding->mStreamIO->GetInputStream(offset, result); +} + +/** + * NOTE: called while holding the cache service lock + */ +nsresult +nsDiskCacheDevice::OpenOutputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result) +{ + NS_ENSURE_ARG_POINTER(entry); + NS_ENSURE_ARG_POINTER(result); + + nsresult rv; + nsDiskCacheBinding * binding = GetCacheEntryBinding(entry); + NS_ENSURE_TRUE(binding, NS_ERROR_UNEXPECTED); + + NS_ASSERTION(binding->mCacheEntry == entry, "binding & entry don't point to each other"); + + rv = binding->EnsureStreamIO(); + if (NS_FAILED(rv)) return rv; + + return binding->mStreamIO->GetOutputStream(offset, result); } diff --git a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h index 2401257466a..6729faa1d71 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheDevice.h @@ -52,9 +52,15 @@ public: virtual nsresult BindEntry(nsCacheEntry * entry); virtual void DoomEntry( nsCacheEntry * entry ); - virtual nsresult GetTransportForEntry(nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** result); + virtual nsresult OpenInputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result); + + virtual nsresult OpenOutputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result); virtual nsresult GetFileForEntry(nsCacheEntry * entry, nsIFile ** result); diff --git a/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp b/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp index 2b4a381c6f2..02fd8dc23c1 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp +++ b/mozilla/netwerk/cache/src/nsDiskCacheStreams.cpp @@ -29,7 +29,6 @@ #include "nsIInputStream.h" #include "nsIOutputStream.h" -#include "nsISeekableStream.h" #include "nsAutoLock.h" @@ -64,7 +63,7 @@ public: private: friend class nsDiskCacheStreamIO; - nsCOMPtr mStreamIO; // backpointer to parent + nsDiskCacheStreamIO * mStreamIO; // backpointer to parent PRFileDesc * mFD; const char * mBuffer; PRUint32 mStreamEnd; @@ -73,7 +72,7 @@ private: }; -NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheInputStream, nsIInputStream); +NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheInputStream, nsIInputStream) nsDiskCacheInputStream::nsDiskCacheInputStream( nsDiskCacheStreamIO * parent, @@ -87,6 +86,7 @@ nsDiskCacheInputStream::nsDiskCacheInputStream( nsDiskCacheStreamIO * parent, , mPos(0) , mClosed(PR_FALSE) { + NS_ADDREF(mStreamIO); mStreamIO->IncrementInputStreamCount(); } @@ -95,6 +95,7 @@ nsDiskCacheInputStream::~nsDiskCacheInputStream() { Close(); mStreamIO->DecrementInputStreamCount(); + NS_RELEASE(mStreamIO); } @@ -182,37 +183,37 @@ nsDiskCacheInputStream::IsNonBlocking(PRBool * nonBlocking) #pragma mark - #pragma mark nsDiskCacheOutputStream #endif -class nsDiskCacheOutputStream : public nsIOutputStream, nsISeekableStream { - +class nsDiskCacheOutputStream : public nsIOutputStream { public: - nsDiskCacheOutputStream( nsDiskCacheStreamIO * parent); - virtual ~nsDiskCacheOutputStream(); + nsDiskCacheOutputStream( nsDiskCacheStreamIO * parent); + virtual ~nsDiskCacheOutputStream(); - NS_DECL_ISUPPORTS - NS_DECL_NSIOUTPUTSTREAM - NS_DECL_NSISEEKABLESTREAM + NS_DECL_ISUPPORTS + NS_DECL_NSIOUTPUTSTREAM private: friend class nsDiskCacheStreamIO; - nsCOMPtr mStreamIO; // backpointer to parent + nsDiskCacheStreamIO * mStreamIO; // backpointer to parent PRBool mClosed; }; -NS_IMPL_THREADSAFE_ISUPPORTS2(nsDiskCacheOutputStream, nsIOutputStream, nsISeekableStream); - +NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheOutputStream, + nsIOutputStream) nsDiskCacheOutputStream::nsDiskCacheOutputStream( nsDiskCacheStreamIO * parent) : mStreamIO(parent) , mClosed(PR_FALSE) { + NS_ADDREF(mStreamIO); } nsDiskCacheOutputStream::~nsDiskCacheOutputStream() { Close(); + NS_RELEASE(mStreamIO); } @@ -264,30 +265,6 @@ nsDiskCacheOutputStream::WriteSegments( nsReadSegmentFun reader, } -NS_IMETHODIMP -nsDiskCacheOutputStream::Seek(PRInt32 whence, PRInt32 offset) -{ - if (mClosed) return NS_ERROR_NOT_AVAILABLE; - return mStreamIO->Seek(whence, offset); -} - - -NS_IMETHODIMP -nsDiskCacheOutputStream::Tell(PRUint32 * result) -{ - if (mClosed) return NS_ERROR_NOT_AVAILABLE; - return mStreamIO->Tell(result); -} - - -NS_IMETHODIMP -nsDiskCacheOutputStream::SetEOF() -{ - if (mClosed) return NS_ERROR_NOT_AVAILABLE; - return mStreamIO->SetEOF(); -} - - NS_IMETHODIMP nsDiskCacheOutputStream::IsNonBlocking(PRBool * nonBlocking) { @@ -305,7 +282,7 @@ nsDiskCacheOutputStream::IsNonBlocking(PRBool * nonBlocking) #pragma mark nsDiskCacheStreamIO #endif -NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheStreamIO, nsIStreamIO); +NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheStreamIO) // we pick 16k as the max buffer size because that is the threshold above which // we are unable to store the data in the cache block files @@ -335,7 +312,7 @@ nsDiskCacheStreamIO::nsDiskCacheStreamIO(nsDiskCacheBinding * binding) nsDiskCacheStreamIO::~nsDiskCacheStreamIO() { - (void) Close(NS_OK); + Close(); // release "death grip" on cache service nsCacheService *service = nsCacheService::GlobalInstance(); @@ -343,15 +320,8 @@ nsDiskCacheStreamIO::~nsDiskCacheStreamIO() } -NS_IMETHODIMP -nsDiskCacheStreamIO::Open() -{ - return NS_OK; -} - - -NS_IMETHODIMP -nsDiskCacheStreamIO::Close(nsresult status) +void +nsDiskCacheStreamIO::Close() { // this should only be called from our destructor // no one is interested in us anymore, so we don't need to grab any locks @@ -362,18 +332,18 @@ nsDiskCacheStreamIO::Close(nsresult status) NS_ASSERTION(!mFD, "file descriptor not closed"); DeleteBuffer(); - - return NS_OK; } -NS_IMETHODIMP -nsDiskCacheStreamIO::GetInputStream(nsIInputStream ** inputStream) +// NOTE: called with service lock held +nsresult +nsDiskCacheStreamIO::GetInputStream(PRUint32 offset, nsIInputStream ** inputStream) { NS_ENSURE_ARG_POINTER(inputStream); + NS_ENSURE_TRUE(offset == 0, NS_ERROR_NOT_IMPLEMENTED); + *inputStream = nsnull; - nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock if (!mBinding) return NS_ERROR_NOT_AVAILABLE; if (mOutStream) { @@ -413,13 +383,13 @@ nsDiskCacheStreamIO::GetInputStream(nsIInputStream ** inputStream) } -NS_IMETHODIMP -nsDiskCacheStreamIO::GetOutputStream(nsIOutputStream ** outputStream) +// NOTE: called with service lock held +nsresult +nsDiskCacheStreamIO::GetOutputStream(PRUint32 offset, nsIOutputStream ** outputStream) { NS_ENSURE_ARG_POINTER(outputStream); *outputStream = nsnull; - nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock if (!mBinding) return NS_ERROR_NOT_AVAILABLE; NS_ASSERTION(!mOutStream, "already have an output stream open"); @@ -432,6 +402,14 @@ nsDiskCacheStreamIO::GetOutputStream(nsIOutputStream ** outputStream) mStreamPos = 0; mStreamEnd = mBinding->mCacheEntry->DataSize(); + nsresult rv; + if (offset) { + rv = Seek(PR_SEEK_SET, offset); + if (NS_FAILED(rv)) return rv; + } + rv = SetEOF(); + if (NS_FAILED(rv)) return rv; + // create a new output stream mOutStream = new nsDiskCacheOutputStream(this); if (!mOutStream) return NS_ERROR_OUT_OF_MEMORY; @@ -440,40 +418,6 @@ nsDiskCacheStreamIO::GetOutputStream(nsIOutputStream ** outputStream) return NS_OK; } - -NS_IMETHODIMP -nsDiskCacheStreamIO::GetName(nsACString & name) -{ - name = NS_LITERAL_CSTRING("nsDiskCacheStreamIO"); - return NS_OK; -} - - -NS_IMETHODIMP -nsDiskCacheStreamIO::GetContentType(nsACString & contentType) -{ - contentType.Truncate(); - return NS_OK; -} - - -NS_IMETHODIMP -nsDiskCacheStreamIO::GetContentCharset(nsACString & contentCharset) -{ - contentCharset.Truncate(); - return NS_OK; -} - - -NS_IMETHODIMP -nsDiskCacheStreamIO::GetContentLength(PRInt32 *contentLength) -{ - NS_ENSURE_ARG_POINTER(contentLength); - *contentLength = -1; - return NS_OK; -} - - void nsDiskCacheStreamIO::ClearBinding() { @@ -799,12 +743,12 @@ nsDiskCacheStreamIO::DeleteBuffer() } -// called only from nsDiskCacheOutputStream::Seek +// NOTE: called with service lock held nsresult nsDiskCacheStreamIO::Seek(PRInt32 whence, PRInt32 offset) { PRInt32 newPos; - nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock + //nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock if (!mBinding) return NS_ERROR_NOT_AVAILABLE; if (PRUint32(offset) > mStreamEnd) return NS_ERROR_FAILURE; @@ -891,17 +835,11 @@ nsDiskCacheStreamIO::Tell(PRUint32 * result) } - -// SetEOF() will only be called by FileTransport. -// nsCacheEntryDescriptor::TransportWrapper::OpenOutputStream() will eventually update -// the cache entry, so we need only update the underlying data structure here. -// -// called only from nsDiskCacheOutputStream::SetEOF +// NOTE: called with service lock held nsresult nsDiskCacheStreamIO::SetEOF() { nsresult rv; - nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock NS_ASSERTION(mStreamPos <= mStreamEnd, "bad stream"); if (!mBinding) return NS_ERROR_NOT_AVAILABLE; diff --git a/mozilla/netwerk/cache/src/nsDiskCacheStreams.h b/mozilla/netwerk/cache/src/nsDiskCacheStreams.h index 800d228f561..d5f9efea4ed 100644 --- a/mozilla/netwerk/cache/src/nsDiskCacheStreams.h +++ b/mozilla/netwerk/cache/src/nsDiskCacheStreams.h @@ -29,7 +29,6 @@ #include "nsCache.h" -#include "nsIStreamIO.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" @@ -39,20 +38,17 @@ class nsDiskCacheInputStream; class nsDiskCacheOutputStream; class nsDiskCacheDevice; -class nsDiskCacheStreamIO : public nsIStreamIO { - -// we're implementing nsIStreamIO to leverage the AsyncRead on the FileTransport thread - +class nsDiskCacheStreamIO : public nsISupports { public: nsDiskCacheStreamIO(nsDiskCacheBinding * binding); virtual ~nsDiskCacheStreamIO(); NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMIO -// NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISUPPORTS_IID) - - void CloseInputStream(nsDiskCacheInputStream * inputStream); - nsresult CloseOutputStream(nsDiskCacheOutputStream * outputStream); + + nsresult GetInputStream(PRUint32 offset, nsIInputStream ** inputStream); + nsresult GetOutputStream(PRUint32 offset, nsIOutputStream ** outputStream); + + nsresult CloseOutputStream(nsDiskCacheOutputStream * outputStream); nsresult Write( const char * buffer, PRUint32 count, @@ -77,6 +73,7 @@ public: private: + void Close(); nsresult OpenCacheFile(PRIntn flags, PRFileDesc ** fd); nsresult ReadCacheBlocks(); nsresult FlushBufferToFile(PRBool clearBuffer); // XXX clearBuffer is always PR_TRUE diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp index e04d17c381a..d601b1b479c 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp @@ -25,19 +25,11 @@ #include "nsMemoryCacheDevice.h" #include "nsCacheService.h" #include "nsICacheService.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" -#include "nsNetCID.h" -#include "nsIObserverService.h" -#include "nsIPref.h" +#include "nsIStorageStream.h" #include "nsICacheVisitor.h" -#include "nsITransport.h" #include "nsCRT.h" -#include -static NS_DEFINE_CID(kStorageTransportCID, NS_STORAGETRANSPORT_CID); - const char *gMemoryDeviceID = "memory"; @@ -69,7 +61,7 @@ nsMemoryCacheDevice::Init() nsresult rv = mMemCacheEntries.Init(); // set some default memory limits, in case prefs aren't available - mSoftLimit = mHardLimit * 0.9; + mSoftLimit = (mHardLimit * 9) / 10; mInitialized = NS_SUCCEEDED(rv); return rv; @@ -208,32 +200,65 @@ nsMemoryCacheDevice::DoomEntry(nsCacheEntry * entry) nsresult -nsMemoryCacheDevice::GetTransportForEntry( nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport ** transport ) +nsMemoryCacheDevice::OpenInputStreamForEntry( nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result) { NS_ENSURE_ARG_POINTER(entry); - NS_ENSURE_ARG_POINTER(transport); + NS_ENSURE_ARG_POINTER(result); nsCOMPtr data; + nsCOMPtr storage; nsresult rv = entry->GetData(getter_AddRefs(data)); if (NS_FAILED(rv)) return rv; - if (data) - return CallQueryInterface(data, transport); - else { - // create a new transport for this entry - rv = nsComponentManager::CreateInstance(kStorageTransportCID, - nsnull, - NS_GET_IID(nsITransport), - (void **) transport); - if (NS_FAILED(rv)) return rv; - - entry->SetData(*transport); - return NS_OK; + if (data) { + storage = do_QueryInterface(data, &rv); + if (NS_FAILED(rv)) + return rv; } + else { + rv = NS_NewStorageStream(4096, PRUint32(-1), getter_AddRefs(storage)); + if (NS_FAILED(rv)) + return rv; + entry->SetData(storage); + } + + return storage->NewInputStream(offset, result); +} + +nsresult +nsMemoryCacheDevice::OpenOutputStreamForEntry( nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result) +{ + NS_ENSURE_ARG_POINTER(entry); + NS_ENSURE_ARG_POINTER(result); + + nsCOMPtr data; + nsCOMPtr storage; + + nsresult rv = entry->GetData(getter_AddRefs(data)); + if (NS_FAILED(rv)) + return rv; + + if (data) { + storage = do_QueryInterface(data, &rv); + if (NS_FAILED(rv)) + return rv; + } + else { + rv = NS_NewStorageStream(4096, PRUint32(-1), getter_AddRefs(storage)); + if (NS_FAILED(rv)) + return rv; + entry->SetData(storage); + } + + return storage->GetOutputStream(offset, result); } @@ -251,7 +276,7 @@ nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize) if (entry->IsStreamData()) { // we have the right to refuse or pre-evict PRUint32 newSize = entry->DataSize() + deltaSize; - if (newSize > mSoftLimit) { + if ((PRInt32) newSize > mSoftLimit) { nsresult rv = nsCacheService::DoomEntry(entry); NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed."); return NS_ERROR_ABORT; @@ -407,7 +432,7 @@ void nsMemoryCacheDevice::SetCapacity(PRInt32 capacity) { PRInt32 hardLimit = capacity * 1024; // convert k into bytes - PRInt32 softLimit = hardLimit * 0.9; + PRInt32 softLimit = (hardLimit * 9) / 10; AdjustMemoryLimits(softLimit, hardLimit); } diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h index ad8a0a4634e..a7130cc5cc7 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h @@ -50,9 +50,15 @@ public: virtual void DoomEntry( nsCacheEntry * entry ); virtual nsresult DeactivateEntry( nsCacheEntry * entry ); - virtual nsresult GetTransportForEntry( nsCacheEntry * entry, - nsCacheAccessMode mode, - nsITransport **transport ); + virtual nsresult OpenInputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIInputStream ** result); + + virtual nsresult OpenOutputStreamForEntry(nsCacheEntry * entry, + nsCacheAccessMode mode, + PRUint32 offset, + nsIOutputStream ** result); virtual nsresult GetFileForEntry( nsCacheEntry * entry, nsIFile ** result ); diff --git a/mozilla/netwerk/macbuild/netwerk.xml b/mozilla/netwerk/macbuild/netwerk.xml index 72455239f6f..4e149e5b95f 100644 --- a/mozilla/netwerk/macbuild/netwerk.xml +++ b/mozilla/netwerk/macbuild/netwerk.xml @@ -1008,14 +1008,14 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Text Debug Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS Text Debug @@ -1085,14 +1085,14 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Text Debug Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS Text Debug @@ -1386,28 +1386,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - Text - Debug - - - Name - nsStreamListenerProxy.cpp - MacOS - Text - Debug - - - Name - nsStreamProviderProxy.cpp - MacOS - Text - Debug - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS Text Debug @@ -1765,12 +1744,12 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS @@ -1780,12 +1759,12 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS @@ -2050,22 +2029,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - - - Name - nsStreamListenerProxy.cpp - MacOS - - - Name - nsStreamProviderProxy.cpp - MacOS - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS @@ -3260,14 +3224,14 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Text Debug Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS Text Debug @@ -3337,14 +3301,14 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Text Debug Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS Text Debug @@ -3638,28 +3602,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - Text - Debug - - - Name - nsStreamListenerProxy.cpp - MacOS - Text - Debug - - - Name - nsStreamProviderProxy.cpp - MacOS - Text - Debug - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS Text Debug @@ -4017,12 +3960,12 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS @@ -4032,12 +3975,12 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS @@ -4302,22 +4245,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - - - Name - nsStreamListenerProxy.cpp - MacOS - - - Name - nsStreamProviderProxy.cpp - MacOS - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS @@ -5512,14 +5440,14 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Text Debug Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS Text Debug @@ -5589,14 +5517,14 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Text Debug Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS Text Debug @@ -5876,28 +5804,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - Text - Debug - - - Name - nsStreamListenerProxy.cpp - MacOS - Text - Debug - - - Name - nsStreamProviderProxy.cpp - MacOS - Text - Debug - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS Text Debug @@ -6255,12 +6162,12 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS @@ -6270,12 +6177,12 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS @@ -6530,22 +6437,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - - - Name - nsStreamListenerProxy.cpp - MacOS - - - Name - nsStreamProviderProxy.cpp - MacOS - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS @@ -7740,14 +7632,14 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Text Debug Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS Text Debug @@ -7817,14 +7709,14 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Text Debug Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS Text Debug @@ -8104,28 +7996,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - Text - Debug - - - Name - nsStreamListenerProxy.cpp - MacOS - Text - Debug - - - Name - nsStreamProviderProxy.cpp - MacOS - Text - Debug - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS Text Debug @@ -8483,12 +8354,12 @@ Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS @@ -8498,12 +8369,12 @@ Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS @@ -8758,22 +8629,7 @@ Name - nsSimpleStreamProvider.cpp - MacOS - - - Name - nsStreamListenerProxy.cpp - MacOS - - - Name - nsStreamProviderProxy.cpp - MacOS - - - Name - nsStorageTransport.cpp + nsAsyncStreamCopier.cpp MacOS @@ -9063,13 +8919,13 @@ Necko.shlb Name - nsFileTransport.cpp + nsInputStreamPump.cpp MacOS Necko.shlb Name - nsFileTransportService.cpp + nsStreamTransportService.cpp MacOS @@ -9135,7 +8991,7 @@ Necko.shlb Name - nsSimpleStreamProvider.cpp + nsAsyncStreamCopier.cpp MacOS @@ -9147,13 +9003,13 @@ Necko.shlb Name - nsSocketTransport.cpp + nsSocketTransport2.cpp MacOS Necko.shlb Name - nsSocketTransportService.cpp + nsSocketTransportService2.cpp MacOS @@ -9162,18 +9018,6 @@ nsStandardURL.cpp MacOS - - Necko.shlb - Name - nsStorageTransport.cpp - MacOS - - - Necko.shlb - Name - nsStreamListenerProxy.cpp - MacOS - Necko.shlb Name @@ -9192,12 +9036,6 @@ nsUnicharStreamLoader.cpp MacOS - - Necko.shlb - Name - nsStreamProviderProxy.cpp - MacOS - Necko.shlb Name diff --git a/mozilla/netwerk/macbuild/netwerkIDL.xml b/mozilla/netwerk/macbuild/netwerkIDL.xml index b1e8741a54d..005f1579ae4 100644 --- a/mozilla/netwerk/macbuild/netwerkIDL.xml +++ b/mozilla/netwerk/macbuild/netwerkIDL.xml @@ -982,7 +982,7 @@ Name - nsIFileTransportService.idl + nsIStreamTransportService.idl MacOS Text @@ -1008,6 +1008,13 @@ Text + + Name + nsIBufferedStreams.idl + MacOS + Text + + Name nsIStreamLoader.idl @@ -1059,7 +1066,7 @@ Name - nsIStreamIO.idl + nsIInputStreamPump.idl MacOS Text @@ -1183,20 +1190,6 @@ Text - - Name - nsIAuthenticator.idl - MacOS - Text - - - - Name - nsIWebFilters.idl - MacOS - Text - - Name nsIFTPChannel.idl @@ -1283,14 +1276,7 @@ Name - nsIStreamProvider.idl - MacOS - Text - - - - Name - nsIStreamProviderProxy.idl + nsIAsyncStreamCopier.idl MacOS Text @@ -1318,7 +1304,7 @@ Name - nsIStreamIOChannel.idl + nsIInputStreamChannel.idl MacOS Text @@ -1351,13 +1337,6 @@ Text - - Name - nsISimpleStreamProvider.idl - MacOS - Text - - Name nsIAuthPrompt.idl @@ -1616,7 +1595,7 @@ Name - nsIFileTransportService.idl + nsIStreamTransportService.idl MacOS @@ -1634,6 +1613,11 @@ nsIFileStreams.idl MacOS + + Name + nsIBufferedStreams.idl + MacOS + Name nsIStreamLoader.idl @@ -1671,7 +1655,7 @@ Name - nsIStreamIO.idl + nsIInputStreamPump.idl MacOS @@ -1759,16 +1743,6 @@ nsIProxyAutoConfig.idl MacOS - - Name - nsIAuthenticator.idl - MacOS - - - Name - nsIWebFilters.idl - MacOS - Name nsIFTPChannel.idl @@ -1831,12 +1805,7 @@ Name - nsIStreamProvider.idl - MacOS - - - Name - nsIStreamProviderProxy.idl + nsIAsyncStreamCopier.idl MacOS @@ -1856,7 +1825,7 @@ Name - nsIStreamIOChannel.idl + nsIInputStreamChannel.idl MacOS @@ -1879,11 +1848,6 @@ nsISimpleStreamListener.idl MacOS - - Name - nsISimpleStreamProvider.idl - MacOS - Name nsIAuthPrompt.idl @@ -2925,7 +2889,7 @@ Name - nsIFileTransportService.idl + nsIStreamTransportService.idl MacOS Text @@ -2951,6 +2915,13 @@ Text + + Name + nsIBufferedStreams.idl + MacOS + Text + + Name nsIStreamLoader.idl @@ -3002,7 +2973,7 @@ Name - nsIStreamIO.idl + nsIInputStreamPump.idl MacOS Text @@ -3119,20 +3090,6 @@ Text - - Name - nsIAuthenticator.idl - MacOS - Text - - - - Name - nsIWebFilters.idl - MacOS - Text - - Name nsIFTPChannel.idl @@ -3219,14 +3176,7 @@ Name - nsIStreamProvider.idl - MacOS - Text - - - - Name - nsIStreamProviderProxy.idl + nsIAsyncStreamCopier.idl MacOS Text @@ -3254,7 +3204,7 @@ Name - nsIStreamIOChannel.idl + nsIInputStreamChannel.idl MacOS Text @@ -3287,13 +3237,6 @@ Text - - Name - nsISimpleStreamProvider.idl - MacOS - Text - - Name nsIAuthPrompt.idl @@ -3552,7 +3495,7 @@ Name - nsIFileTransportService.idl + nsIStreamTransportService.idl MacOS @@ -3570,6 +3513,11 @@ nsIFileStreams.idl MacOS + + Name + nsIBufferedStreams.idl + MacOS + Name nsIStreamLoader.idl @@ -3607,7 +3555,7 @@ Name - nsIStreamIO.idl + nsIInputStreamPump.idl MacOS @@ -3690,16 +3638,6 @@ nsIProxyAutoConfig.idl MacOS - - Name - nsIAuthenticator.idl - MacOS - - - Name - nsIWebFilters.idl - MacOS - Name nsIFTPChannel.idl @@ -3762,12 +3700,7 @@ Name - nsIStreamProvider.idl - MacOS - - - Name - nsIStreamProviderProxy.idl + nsIAsyncStreamCopier.idl MacOS @@ -3787,7 +3720,7 @@ Name - nsIStreamIOChannel.idl + nsIInputStreamChannel.idl MacOS @@ -3810,11 +3743,6 @@ nsISimpleStreamListener.idl MacOS - - Name - nsISimpleStreamProvider.idl - MacOS - Name nsIAuthPrompt.idl @@ -3980,12 +3908,6 @@ nsIProxiedProtocolHandler.idl MacOS - - headers - Name - nsIAuthenticator.idl - MacOS - headers Name @@ -4028,12 +3950,6 @@ nsIEventSinkGetter.idl MacOS - - headers - Name - nsIFileChannel.idl - MacOS - headers Name @@ -4043,7 +3959,13 @@ headers Name - nsIFileTransportService.idl + nsIBufferedStreams.idl + MacOS + + + headers + Name + nsIStreamTransportService.idl MacOS @@ -4157,7 +4079,7 @@ headers Name - nsIStreamIOChannel.idl + nsIInputStreamChannel.idl MacOS @@ -4217,7 +4139,7 @@ headers Name - nsIStreamIO.idl + nsIInputStreamPump.idl MacOS @@ -4241,13 +4163,7 @@ headers Name - nsIStreamProvider.idl - MacOS - - - headers - Name - nsIStreamProviderProxy.idl + nsIAsyncStreamCopier.idl MacOS @@ -4286,12 +4202,6 @@ nsIURLParser.idl MacOS - - headers - Name - nsIWebFilters.idl - MacOS - headers Name @@ -4310,12 +4220,6 @@ nsISimpleStreamListener.idl MacOS - - headers - Name - nsISimpleStreamProvider.idl - MacOS - headers Name @@ -4447,6 +4351,12 @@ nsIFileProtocolHandler.idl MacOS + + headers + Name + nsIFileChannel.idl + MacOS + ftp diff --git a/mozilla/netwerk/protocol/Makefile.in b/mozilla/netwerk/protocol/Makefile.in index 5509a80a537..9289ebf8b7f 100644 --- a/mozilla/netwerk/protocol/Makefile.in +++ b/mozilla/netwerk/protocol/Makefile.in @@ -26,8 +26,16 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = about data file ftp http keyword jar res \ - gopher viewsource +DIRS = about \ + data \ + keyword \ + res \ + file \ + jar \ + http \ + viewsource \ + ftp \ + gopher \ + $(NULL) include $(topsrcdir)/config/rules.mk - diff --git a/mozilla/netwerk/protocol/about/src/nsAboutBlank.cpp b/mozilla/netwerk/protocol/about/src/nsAboutBlank.cpp index d874194c916..9d3f9c27a4b 100644 --- a/mozilla/netwerk/protocol/about/src/nsAboutBlank.cpp +++ b/mozilla/netwerk/protocol/about/src/nsAboutBlank.cpp @@ -58,8 +58,7 @@ nsAboutBlank::NewChannel(nsIURI *aURI, nsIChannel **result) rv = NS_NewInputStreamChannel(&channel, aURI, in, NS_LITERAL_CSTRING("text/html"), - NS_LITERAL_CSTRING(""), - strlen(kBlankPage)); + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; *result = channel; diff --git a/mozilla/netwerk/protocol/about/src/nsAboutBloat.cpp b/mozilla/netwerk/protocol/about/src/nsAboutBloat.cpp index 44d19210165..305ef0b418d 100644 --- a/mozilla/netwerk/protocol/about/src/nsAboutBloat.cpp +++ b/mozilla/netwerk/protocol/about/src/nsAboutBloat.cpp @@ -81,15 +81,12 @@ nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result) } nsCOMPtr inStr; - PRUint32 size; if (clear) { nsTraceRefcnt::ResetStatistics(); const char* msg = "Bloat statistics cleared."; rv = NS_NewCStringInputStream(getter_AddRefs(inStr), nsDependentCString(msg)); if (NS_FAILED(rv)) return rv; - - size = strlen(msg); } else if (leaks) { // dump the current set of leaks. @@ -98,8 +95,6 @@ nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result) const char* msg = "Memory leaks dumped."; rv = NS_NewCStringInputStream(getter_AddRefs(inStr), nsDependentCString(msg)); if (NS_FAILED(rv)) return rv; - - size = strlen(msg); } else { nsCOMPtr file; @@ -146,11 +141,6 @@ nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result) ::fclose(out); if (NS_FAILED(rv)) return rv; - PRInt64 bigSize; - rv = file->GetFileSize(&bigSize); - if (NS_FAILED(rv)) return rv; - LL_L2UI(size, bigSize); - rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file); if (NS_FAILED(rv)) return rv; } @@ -158,8 +148,7 @@ nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result) nsIChannel* channel; rv = NS_NewInputStreamChannel(&channel, aURI, inStr, NS_LITERAL_CSTRING("text/plain"), - NS_LITERAL_CSTRING(""), - size); + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; *result = channel; diff --git a/mozilla/netwerk/protocol/about/src/nsAboutCache.cpp b/mozilla/netwerk/protocol/about/src/nsAboutCache.cpp index b81caaa3cd1..359b626d41e 100644 --- a/mozilla/netwerk/protocol/about/src/nsAboutCache.cpp +++ b/mozilla/netwerk/protocol/about/src/nsAboutCache.cpp @@ -139,10 +139,6 @@ nsAboutCache::NewChannel(nsIURI *aURI, nsIChannel **result) outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); nsCOMPtr inStr; - PRUint32 size; - - rv = storageStream->GetLength(&size); - if (NS_FAILED(rv)) return rv; rv = storageStream->NewInputStream(0, getter_AddRefs(inStr)); if (NS_FAILED(rv)) return rv; @@ -150,8 +146,7 @@ nsAboutCache::NewChannel(nsIURI *aURI, nsIChannel **result) nsIChannel* channel; rv = NS_NewInputStreamChannel(&channel, aURI, inStr, NS_LITERAL_CSTRING("text/html"), - NS_LITERAL_CSTRING(""), - size); + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; *result = channel; diff --git a/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.cpp b/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.cpp index 80240240959..ff79a070547 100644 --- a/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.cpp +++ b/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.cpp @@ -66,11 +66,13 @@ nsAboutCacheEntry::NewChannel(nsIURI *aURI, nsIChannel **result) { nsresult rv; - nsCOMPtr chan; - rv = NS_NewStreamIOChannel(getter_AddRefs(chan), aURI, nsnull); + nsCOMPtr chan; + rv = NS_NewInputStreamChannel(getter_AddRefs(chan), aURI, nsnull, + NS_LITERAL_CSTRING("application/xhtml+xml")); if (NS_FAILED(rv)) return rv; - mStreamChannel = do_QueryInterface(chan); + mStreamChannel = do_QueryInterface(chan, &rv); + if (NS_FAILED(rv)) return rv; return CallQueryInterface((nsIAboutModule *) this, result); } @@ -125,24 +127,7 @@ nsAboutCacheEntry::OnCacheEntryAvailable(nsICacheEntryDescriptor *descriptor, rv = storageStream->NewInputStream(0, getter_AddRefs(inStr)); if (NS_FAILED(rv)) return rv; - nsCOMPtr uri; - rv = mStreamChannel->GetURI(getter_AddRefs(uri)); - if (NS_FAILED(rv)) return rv; - - nsCAutoString spec; - rv = uri->GetSpec(spec); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr io; - rv = NS_NewInputStreamIO(getter_AddRefs(io), spec, inStr, - NS_LITERAL_CSTRING("application/xhtml+xml"), - NS_LITERAL_CSTRING(""), - size); - - nsCOMPtr chan = do_QueryInterface(mStreamChannel, &rv); - if (NS_FAILED(rv)) return rv; - - rv = chan->Init(uri, io); + rv = mStreamChannel->SetContentStream(inStr); if (NS_FAILED(rv)) return rv; return mStreamChannel->AsyncOpen(mListener, mListenerContext); diff --git a/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.h b/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.h index 5bc5533d6b5..f864163ee42 100644 --- a/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.h +++ b/mozilla/netwerk/protocol/about/src/nsAboutCacheEntry.h @@ -46,6 +46,8 @@ #include "nsICacheEntryDescriptor.h" #include "nsIStreamListener.h" #include "nsIOutputStream.h" +#include "nsIInputStreamChannel.h" +#include "nsIURI.h" #include "nsCOMPtr.h" #include "nsString.h" @@ -76,7 +78,8 @@ private: nsresult ParseURI(nsCString &, PRBool &, nsCString &); private: - nsCOMPtr mStreamChannel; + nsCOMPtr mURI; + nsCOMPtr mStreamChannel; nsCOMPtr mListener; nsCOMPtr mListenerContext; nsCOMPtr mCacheSession; diff --git a/mozilla/netwerk/protocol/data/src/nsDataHandler.h b/mozilla/netwerk/protocol/data/src/nsDataHandler.h index ba5bb0f0410..4448005082a 100644 --- a/mozilla/netwerk/protocol/data/src/nsDataHandler.h +++ b/mozilla/netwerk/protocol/data/src/nsDataHandler.h @@ -39,9 +39,6 @@ #define nsDataHandler_h___ #include "nsIProtocolHandler.h" -// {B6ED3030-6183-11d3-A178-0050041CAF44} -#define NS_DATAHANDLER_CID \ - { 0xb6ed3030, 0x6183, 0x11d3, { 0xa1, 0x78, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44 } } class nsDataHandler : public nsIProtocolHandler { diff --git a/mozilla/netwerk/protocol/file/public/MANIFEST_IDL b/mozilla/netwerk/protocol/file/public/MANIFEST_IDL index 9825a70c942..9de07681d37 100644 --- a/mozilla/netwerk/protocol/file/public/MANIFEST_IDL +++ b/mozilla/netwerk/protocol/file/public/MANIFEST_IDL @@ -1 +1,2 @@ nsIFileProtocolHandler.idl +nsIFileChannel.idl diff --git a/mozilla/netwerk/protocol/file/public/Makefile.in b/mozilla/netwerk/protocol/file/public/Makefile.in index bf14a1fef57..ae75711b234 100644 --- a/mozilla/netwerk/protocol/file/public/Makefile.in +++ b/mozilla/netwerk/protocol/file/public/Makefile.in @@ -32,6 +32,7 @@ GRE_MODULE = 1 XPIDLSRCS = \ nsIFileProtocolHandler.idl \ + nsIFileChannel.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/netwerk/protocol/file/src/Makefile.in b/mozilla/netwerk/protocol/file/src/Makefile.in index 9909d0e091e..f1a99fd7069 100644 --- a/mozilla/netwerk/protocol/file/src/Makefile.in +++ b/mozilla/netwerk/protocol/file/src/Makefile.in @@ -30,17 +30,17 @@ MODULE = necko LIBRARY_NAME = nkfile_s REQUIRES = xpcom \ string \ - exthandler \ mimetype \ pref \ uconv \ $(NULL) CPPSRCS = \ - nsFileChannel.cpp \ nsFileProtocolHandler.cpp \ + nsFileChannel.cpp \ $(NULL) + # we don't want the shared lib, but we want to force the creation of a # static lib. FORCE_STATIC_LIB = 1 diff --git a/mozilla/netwerk/protocol/file/src/nsFileChannel.cpp b/mozilla/netwerk/protocol/file/src/nsFileChannel.cpp index 8625150bf78..5ace777dd5a 100644 --- a/mozilla/netwerk/protocol/file/src/nsFileChannel.cpp +++ b/mozilla/netwerk/protocol/file/src/nsFileChannel.cpp @@ -36,398 +36,267 @@ * ***** END LICENSE BLOCK ***** */ #include "nsFileChannel.h" -#include "nsIFileChannel.h" -#include "nsIStreamConverterService.h" -#include "nsIFileURL.h" -#include "nsIURL.h" -#include "nsIServiceManager.h" -#include "nsCExternalHandlerService.h" -#include "nsIMIMEService.h" -#include "nsIFileTransportService.h" -#include "nsIFile.h" -#include "nsIEventQueueService.h" -#include "nsIOutputStream.h" -#include "nsXPIDLString.h" -#include "nsStandardURL.h" -#include "nsReadableUtils.h" -#include "nsInt64.h" +#include "nsDirectoryIndexStream.h" #include "nsMimeTypes.h" #include "nsNetUtil.h" -#include "prio.h" // Need to pick up def of PR_RDONLY +#include "nsEventQueueUtils.h" + +#include "nsIServiceManager.h" +#include "nsIStreamConverterService.h" +#include "nsIStreamTransportService.h" +#include "nsITransport.h" +#include "nsIFileURL.h" +#include "nsIMIMEService.h" -static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); -static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID); static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); +static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- nsFileChannel::nsFileChannel() - : mIOFlags(-1), - mPerm(-1), - mLoadFlags(LOAD_NORMAL), - mTransferOffset(0), - mTransferCount(-1), - mBufferSegmentSize(0), - mBufferMaxSize(0), - mStatus(NS_OK) -#ifdef DEBUG - ,mInitiator(nsnull) -#endif + : mContentLength(-1) + , mUploadLength(-1) + , mLoadFlags(LOAD_NORMAL) + , mStatus(NS_OK) + , mConvertToHTML(PR_FALSE) + , mIsDir(PR_FALSE) + , mUploading(PR_FALSE) { } nsresult -nsFileChannel::Init(PRInt32 ioFlags, - PRInt32 perm, - nsIURI* uri, - PRBool generateHTMLDirs) +nsFileChannel::Init(nsIURI *uri, PRBool htmlDirs) { - mIOFlags = ioFlags; - mPerm = perm; - mURI = uri; - mGenerateHTMLDirs = generateHTMLDirs; + nsresult rv; + mURL = do_QueryInterface(uri, &rv); + mConvertToHTML = htmlDirs; + return rv; +} + +nsresult +nsFileChannel::GetClonedFile(nsIFile **result) +{ + nsresult rv; + + nsCOMPtr file; + rv = mURL->GetFile(getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + + return file->Clone(result); +} + +nsresult +nsFileChannel::EnsureStream() +{ + NS_ENSURE_TRUE(mURL, NS_ERROR_NOT_INITIALIZED); + + nsresult rv; + nsCOMPtr file; + + // don't assume nsIFile impl is threadsafe; pass a clone to the stream. + rv = GetClonedFile(getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + + // we accept that this might result in a disk hit to stat the file + rv = file->IsDirectory(&mIsDir); + if (NS_FAILED(rv)) { + // canonicalize error message + if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) + rv = NS_ERROR_FILE_NOT_FOUND; + return rv; + } + + if (mIsDir) { + rv = nsDirectoryIndexStream::Create(file, getter_AddRefs(mStream)); + if (NS_FAILED(rv)) return rv; + + // set content type + if (mConvertToHTML) + mContentType = NS_LITERAL_CSTRING(TEXT_HTML); + else + mContentType = NS_LITERAL_CSTRING(APPLICATION_HTTP_INDEX_FORMAT); + } + else { + rv = NS_NewLocalFileInputStream(getter_AddRefs(mStream), file); + if (NS_FAILED(rv)) return rv; + + // get content type from file extension + nsXPIDLCString mimeType; + nsCOMPtr mime = do_GetService("@mozilla.org/mime;1", &rv); + if (NS_SUCCEEDED(rv)) + mime->GetTypeFromFile(file, getter_Copies(mimeType)); + + if (mimeType.IsEmpty()) + mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); + else + mContentType = mimeType; + } + + // fixup content length + if (mStream && (mContentLength < 0)) + mStream->Available((PRUint32 *) &mContentLength); + return NS_OK; } -nsFileChannel::~nsFileChannel() -{ -} +//----------------------------------------------------------------------------- +// nsISupports +//----------------------------------------------------------------------------- -nsresult -nsFileChannel::SetStreamConverter() -{ - nsresult rv; - nsCOMPtr converterListener = mRealListener; +// XXX this only needs to be threadsafe because of bug 101252 +NS_IMPL_THREADSAFE_ISUPPORTS7(nsFileChannel, + nsIRequest, + nsIChannel, + nsIStreamListener, + nsIRequestObserver, + nsIUploadChannel, + nsIFileChannel, + nsITransportEventSink) - nsCOMPtr scs = do_GetService(kStreamConverterServiceCID, &rv); - - if (NS_FAILED(rv)) - return rv; - - rv = scs->AsyncConvertData(NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), - NS_LITERAL_STRING(TEXT_HTML).get(), - converterListener, - mURI, - getter_AddRefs(mRealListener)); - - return rv; -} - -NS_IMPL_THREADSAFE_ADDREF(nsFileChannel) -NS_IMPL_THREADSAFE_RELEASE(nsFileChannel) -NS_INTERFACE_MAP_BEGIN(nsFileChannel) - NS_INTERFACE_MAP_ENTRY(nsIFileChannel) - NS_INTERFACE_MAP_ENTRY(nsIChannel) - NS_INTERFACE_MAP_ENTRY(nsIRequest) - NS_INTERFACE_MAP_ENTRY(nsIStreamListener) - NS_INTERFACE_MAP_ENTRY(nsIStreamProvider) - NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) - NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) - NS_INTERFACE_MAP_ENTRY(nsIUploadChannel) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequestObserver, nsIStreamListener) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFileChannel) -NS_INTERFACE_MAP_END - -NS_METHOD -nsFileChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) -{ - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - - nsFileChannel* fc = new nsFileChannel(); - if (fc == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(fc); - nsresult rv = fc->QueryInterface(aIID, aResult); - NS_RELEASE(fc); - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// -// From nsIRequest -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsIRequest +//----------------------------------------------------------------------------- NS_IMETHODIMP nsFileChannel::GetName(nsACString &result) { - if (mCurrentRequest) - return mCurrentRequest->GetName(result); - return mURI->GetSpec(result); + return mURL->GetSpec(result); } NS_IMETHODIMP nsFileChannel::IsPending(PRBool *result) { - if (mCurrentRequest) - return mCurrentRequest->IsPending(result); - *result = PR_FALSE; + *result = (mRequest != nsnull); return NS_OK; } NS_IMETHODIMP nsFileChannel::GetStatus(nsresult *status) { - *status = mStatus; + if (NS_SUCCEEDED(mStatus) && mRequest) + mRequest->GetStatus(status); + else + *status = mStatus; return NS_OK; } NS_IMETHODIMP nsFileChannel::Cancel(nsresult status) { - NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - mStatus = status; - if (mCurrentRequest) - return mCurrentRequest->Cancel(status); - return NS_OK; + NS_ENSURE_TRUE(mRequest, NS_ERROR_UNEXPECTED); + return mRequest->Cancel(status); } NS_IMETHODIMP nsFileChannel::Suspend() { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - if (mCurrentRequest) - return mCurrentRequest->Suspend(); - return NS_OK; + NS_ENSURE_TRUE(mRequest, NS_ERROR_UNEXPECTED); + return mRequest->Suspend(); } NS_IMETHODIMP nsFileChannel::Resume() { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - if (mCurrentRequest) - return mCurrentRequest->Resume(); - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// From nsIChannel -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::GetOriginalURI(nsIURI* *aURI) -{ - *aURI = mOriginalURI ? mOriginalURI : mURI; - NS_ADDREF(*aURI); - return NS_OK; + NS_ENSURE_TRUE(mRequest, NS_ERROR_UNEXPECTED); + return mRequest->Resume(); } NS_IMETHODIMP -nsFileChannel::SetOriginalURI(nsIURI* aURI) -{ - mOriginalURI = aURI; - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::GetURI(nsIURI* *aURI) -{ - *aURI = mURI; - NS_ADDREF(*aURI); - return NS_OK; -} - -nsresult -nsFileChannel::EnsureFile() -{ - if (mFile) - return NS_OK; - - nsresult rv; - // if we support the nsIURL interface then use it to get just - // the file path with no other garbage! - nsCOMPtr fileURL = do_QueryInterface(mURI, &rv); - NS_ENSURE_TRUE(fileURL, NS_ERROR_UNEXPECTED); - - rv = fileURL->GetFile(getter_AddRefs(mFile)); - if (NS_FAILED(rv)) return NS_ERROR_FILE_NOT_FOUND; - - nsCOMPtr localFile = do_QueryInterface(mFile); - if (localFile) - localFile->SetFollowLinks(PR_TRUE); - - return NS_OK; -} -nsresult -nsFileChannel::GetFileTransport(nsITransport **trans) -{ - nsresult rv = EnsureFile(); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = fts->CreateTransport(mFile, mIOFlags, mPerm, PR_TRUE, trans); - if (NS_FAILED(rv)) return rv; - - // XXX why should file:// URLs be loaded in the background? - (*trans)->SetNotificationCallbacks(mCallbacks, (mLoadFlags & LOAD_BACKGROUND)); - return rv; -} - -NS_IMETHODIMP -nsFileChannel::Open(nsIInputStream **result) -{ - nsresult rv; - - if (mFileTransport) - return NS_ERROR_IN_PROGRESS; // AsyncOpen in progress - - nsCOMPtr fileTransport; - rv = GetFileTransport(getter_AddRefs(fileTransport)); - if (NS_FAILED(rv)) return rv; - - if (mUploadStream) { - // open output stream for "uploading" - nsCOMPtr fileOut; - rv = fileTransport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(fileOut)); - if (NS_FAILED(rv)) return rv; - - // write all of mUploadStream to fileOut before returning - while (mUploadStreamLength) { - PRUint32 bytesWritten = 0; - - rv = fileOut->WriteFrom(mUploadStream, mUploadStreamLength, &bytesWritten); - if (NS_FAILED(rv)) return rv; - - if (bytesWritten == 0) { - NS_WARNING("wrote zero bytes"); - return NS_ERROR_UNEXPECTED; - } - - mUploadStreamLength -= bytesWritten; - } - if (NS_FAILED(rv)) return rv; - - // return empty stream to caller... - nsCOMPtr emptyIn; - rv = NS_NewByteInputStream(getter_AddRefs(emptyIn), "", 0); - if (NS_FAILED(rv)) return rv; - - rv = CallQueryInterface(emptyIn, result); - } - else - rv = fileTransport->OpenInputStream(0, PRUint32(-1), 0, result); - - return rv; -} - -NS_IMETHODIMP -nsFileChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) -{ - nsresult rv; - nsCOMPtr request; - -#ifdef DEBUG - NS_ASSERTION(mInitiator == nsnull || mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); - mInitiator = PR_GetCurrentThread(); -#endif - - if (mFileTransport) - return NS_ERROR_IN_PROGRESS; // AsyncOpen in progress - - NS_ASSERTION(listener, "null listener"); - mRealListener = listener; - - if (mLoadGroup) { - rv = mLoadGroup->AddRequest(this, nsnull); - if (NS_FAILED(rv)) return rv; - } - - nsCOMPtr fileTransport; - rv = GetFileTransport(getter_AddRefs(fileTransport)); - - if (NS_SUCCEEDED(rv)) { - - if (mUploadStream) - rv = fileTransport->AsyncWrite(this, ctxt, 0, PRUint32(-1), 0, - getter_AddRefs(request)); - else - rv = fileTransport->AsyncRead(this, ctxt, 0, PRUint32(-1), 0, - getter_AddRefs(request)); - - // remember the transport and request; these will be released when - // OnStopRequest is called. - mFileTransport = fileTransport; - mCurrentRequest = request; - } - - if (NS_FAILED(rv)) { - - mStatus = rv; - - nsCOMPtr asyncObserver; - NS_NewRequestObserverProxy(getter_AddRefs(asyncObserver), - NS_STATIC_CAST(nsIRequestObserver*, /* Ambiguous conversion */ - NS_STATIC_CAST(nsIStreamListener*, this)), - NS_CURRENT_EVENTQ); - if(asyncObserver) { - (void) asyncObserver->OnStartRequest(this, ctxt); - (void) asyncObserver->OnStopRequest(this, ctxt, rv); - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::GetLoadFlags(PRUint32 *aLoadFlags) +nsFileChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) { *aLoadFlags = mLoadFlags; return NS_OK; } NS_IMETHODIMP -nsFileChannel::SetLoadFlags(PRUint32 aLoadFlags) +nsFileChannel::SetLoadFlags(nsLoadFlags aLoadFlags) { mLoadFlags = aLoadFlags; return NS_OK; } +NS_IMETHODIMP +nsFileChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) +{ + NS_IF_ADDREF(*aLoadGroup = mLoadGroup); + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) +{ + mLoadGroup = aLoadGroup; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// nsIChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsFileChannel::GetOriginalURI(nsIURI **aURI) +{ + if (mOriginalURI) + *aURI = mOriginalURI; + else + *aURI = mURL; + NS_IF_ADDREF(*aURI); + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::SetOriginalURI(nsIURI *aURI) +{ + mOriginalURI = aURI; + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::GetURI(nsIURI **aURI) +{ + NS_IF_ADDREF(*aURI = mURL); + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::GetOwner(nsISupports **aOwner) +{ + NS_IF_ADDREF(*aOwner = mOwner); + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::SetOwner(nsISupports *aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) +{ + NS_IF_ADDREF(*aCallbacks = mCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) +{ + mCallbacks = aCallbacks; + mProgressSink = do_GetInterface(mCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::GetSecurityInfo(nsISupports **aSecurityInfo) +{ + *aSecurityInfo = nsnull; + return NS_OK; +} + NS_IMETHODIMP nsFileChannel::GetContentType(nsACString &aContentType) { - aContentType.Truncate(); - - if (!mFile) { - return NS_ERROR_NOT_AVAILABLE; - } - - if (mContentType.IsEmpty()) { - PRBool directory; - mFile->IsDirectory(&directory); - if (directory) { - if (mGenerateHTMLDirs) - mContentType = NS_LITERAL_CSTRING(TEXT_HTML); - else - mContentType = NS_LITERAL_CSTRING(APPLICATION_HTTP_INDEX_FORMAT); - } - else { - nsresult rv; - nsCOMPtr MIMEService(do_GetService(NS_MIMESERVICE_CONTRACTID, &rv)); - if (NS_FAILED(rv)) return rv; - - nsXPIDLCString mimeType; - rv = MIMEService->GetTypeFromFile(mFile, getter_Copies(mimeType)); - if (NS_SUCCEEDED(rv)) - mContentType = mimeType; - } - - if (mContentType.IsEmpty()) - mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); - } aContentType = mContentType; return NS_OK; } @@ -435,7 +304,7 @@ nsFileChannel::GetContentType(nsACString &aContentType) NS_IMETHODIMP nsFileChannel::SetContentType(const nsACString &aContentType) { - // only modifies mContentCharset if a charset is parsed + // mContentCharset is unchanged if not parsed NS_ParseContentType(aContentType, mContentType, mContentCharset); return NS_OK; } @@ -457,350 +326,210 @@ nsFileChannel::SetContentCharset(const nsACString &aContentCharset) NS_IMETHODIMP nsFileChannel::GetContentLength(PRInt32 *aContentLength) { - if (!mFile) { - return NS_ERROR_NOT_AVAILABLE; - } - - nsresult rv; - PRInt64 size; - rv = mFile->GetFileSize(&size); - if (NS_SUCCEEDED(rv)) { - *aContentLength = nsInt64(size); - } else { - *aContentLength = -1; - } - return rv; + *aContentLength = mContentLength; + return NS_OK; } NS_IMETHODIMP nsFileChannel::SetContentLength(PRInt32 aContentLength) { - NS_NOTREACHED("nsFileChannel::SetContentLength"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsFileChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) -{ - *aLoadGroup = mLoadGroup; - NS_IF_ADDREF(*aLoadGroup); + // XXX does this really make any sense at all? + mContentLength = aContentLength; return NS_OK; } NS_IMETHODIMP -nsFileChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) +nsFileChannel::Open(nsIInputStream **result) { - mLoadGroup = aLoadGroup; - return NS_OK; -} + NS_ENSURE_TRUE(!mRequest, NS_ERROR_IN_PROGRESS); + NS_ENSURE_TRUE(!mUploading, NS_ERROR_NOT_IMPLEMENTED); // XXX implement me! -NS_IMETHODIMP -nsFileChannel::GetOwner(nsISupports* *aOwner) -{ - *aOwner = mOwner.get(); - NS_IF_ADDREF(*aOwner); - return NS_OK; -} + nsresult rv; -NS_IMETHODIMP -nsFileChannel::SetOwner(nsISupports* aOwner) -{ - mOwner = aOwner; - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) -{ - *aNotificationCallbacks = mCallbacks.get(); - NS_IF_ADDREF(*aNotificationCallbacks); - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) -{ - mCallbacks = aNotificationCallbacks; - - // Cache the new nsIProgressEventSink instance... - if (mCallbacks) { - (void)mCallbacks->GetInterface(NS_GET_IID(nsIProgressEventSink), - getter_AddRefs(mProgress)); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) -{ - *aSecurityInfo = nsnull; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIRequestObserver methods: -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::OnStartRequest(nsIRequest* request, nsISupports* context) -{ - // unconditionally inherit the status of the file transport - request->GetStatus(&mStatus); -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - NS_ASSERTION(mRealListener, "No listener..."); - nsresult rv = NS_OK; - if (mRealListener) { - if (mGenerateHTMLDirs) { - // GetFileTransport ensures that mFile is valid before calling - // AsyncRead or AsyncWrite on the underlying transport. Since - // these transports use |this| as the nsIRequestObserver, there - // should be no way that mFile is null here. - NS_ENSURE_TRUE(mFile, NS_ERROR_UNEXPECTED); - PRBool directory; - mFile->IsDirectory(&directory); // this stat should be cached and will not hit disk. - if (directory) { - rv = SetStreamConverter(); - if (NS_FAILED(rv)) - return rv; - } - } - - rv = mRealListener->OnStartRequest(this, context); - } - return rv; -} - -NS_IMETHODIMP -nsFileChannel::OnStopRequest(nsIRequest* request, nsISupports* context, - nsresult aStatus) -{ - // if we were canceled, we should not overwrite the cancelation status - // since that could break security assumptions made in upper layers. - if (NS_SUCCEEDED(mStatus)) - mStatus = aStatus; - -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - - NS_ENSURE_TRUE(mRealListener, NS_ERROR_UNEXPECTED); - - // no point to capturing the return value of OnStopRequest - mRealListener->OnStopRequest(this, context, mStatus); - - if (mLoadGroup) - mLoadGroup->RemoveRequest(this, context, mStatus); - - // Release the reference to the consumer stream listener... - mRealListener = 0; - mFileTransport = 0; - mCurrentRequest = 0; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamListener methods: -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::OnDataAvailable(nsIRequest* request, nsISupports* context, - nsIInputStream *aIStream, PRUint32 aSourceOffset, - PRUint32 aLength) -{ -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - - NS_ENSURE_TRUE(mRealListener, NS_ERROR_UNEXPECTED); - - return mRealListener->OnDataAvailable(this, context, aIStream, - aSourceOffset, aLength); -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamProvider methods: -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::OnDataWritable(nsIRequest *aRequest, nsISupports *aContext, - nsIOutputStream *aOStream, PRUint32 aOffset, - PRUint32 aLength) -{ -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), - "wrong thread calling this routine"); -#endif - - NS_ENSURE_TRUE(mUploadStream, NS_ERROR_UNEXPECTED); - - if (mUploadStreamLength == 0) - return NS_BASE_STREAM_CLOSED; // done writing - - PRUint32 bytesToWrite = PR_MIN(mUploadStreamLength, aLength); - PRUint32 bytesWritten = 0; - - nsresult rv = aOStream->WriteFrom(mUploadStream, bytesToWrite, &bytesWritten); + rv = EnsureStream(); if (NS_FAILED(rv)) return rv; - if (bytesWritten == 0) { - NS_WARNING("wrote zero bytes"); - return NS_BASE_STREAM_CLOSED; - } - - mUploadStreamLength -= bytesWritten; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// From nsIInterfaceRequestor -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::GetInterface(const nsIID &anIID, void **aResult ) -{ - // capture the progress event sink stuff. pass the rest through. - if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) { - *aResult = NS_STATIC_CAST(nsIProgressEventSink*, this); - NS_ADDREF(this); - return NS_OK; - } - else if (mCallbacks) { - return mCallbacks->GetInterface(anIID, aResult); - } - return NS_ERROR_NO_INTERFACE; -} - -//////////////////////////////////////////////////////////////////////////////// -// From nsIProgressEventSink -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::OnStatus(nsIRequest *request, nsISupports* ctxt, - nsresult aStatus, const PRUnichar* aStatusArg) -{ - nsresult rv = NS_OK; - if (mProgress) { - rv = mProgress->OnStatus(this, ctxt, aStatus, aStatusArg); - } - return rv; -} - -NS_IMETHODIMP -nsFileChannel::OnProgress(nsIRequest *request, - nsISupports* aContext, - PRUint32 aProgress, - PRUint32 aProgressMax) -{ - nsresult rv; - if (mProgress) { - rv = mProgress->OnProgress(this, aContext, aProgress, aProgressMax); - NS_ASSERTION(NS_SUCCEEDED(rv), "dropping error result"); - } - return NS_OK; -} - - -//////////////////////////////////////////////////////////////////////////////// -// From nsIFileChannel -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::Init(nsIFile* file, - PRInt32 ioFlags, - PRInt32 perm) -{ - nsresult rv; - nsCOMPtr url = new nsStandardURL(PR_TRUE); - if (!url) - return NS_ERROR_OUT_OF_MEMORY; - - // XXX shouldn't we set nsIURI::originCharset ?? - - rv = url->SetFile(file); - if (NS_FAILED(rv)) return rv; - - return Init(ioFlags, perm, url); -} - -NS_IMETHODIMP -nsFileChannel::GetFile(nsIFile* *result) -{ - nsresult rv = EnsureFile(); - if (NS_FAILED(rv)) - return rv; - - *result = mFile; - NS_ADDREF(*result); - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::GetIoFlags(PRInt32 *aIoFlags) -{ - *aIoFlags = mIOFlags; - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::SetIoFlags(PRInt32 aIoFlags) -{ - mIOFlags = aIoFlags; - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::GetPermissions(PRInt32 *aPermissions) -{ - *aPermissions = mPerm; - return NS_OK; -} - -NS_IMETHODIMP -nsFileChannel::SetPermissions(PRInt32 aPermissions) -{ - mPerm = aPermissions; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// From nsIUploadChannel -//////////////////////////////////////////////////////////////////////////////// - -NS_IMETHODIMP -nsFileChannel::SetUploadStream(nsIInputStream *aStream, - const nsACString &aContentType, - PRInt32 aContentLength) -{ - if (mFileTransport) - return NS_ERROR_IN_PROGRESS; // channel is pending, so we can't add - // or remove an upload stream. - - // ignore aContentType argument; query the stream for its length if not - // specified (allow upload of a partial stream). - - if (aContentLength < 0) { - nsresult rv = aStream->Available(&mUploadStreamLength); + if (mIsDir && mConvertToHTML) { + nsCOMPtr scs = + do_GetService(kStreamConverterServiceCID, &rv); if (NS_FAILED(rv)) return rv; + + nsCOMPtr temp; + + rv = scs->Convert(mStream, + NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), + NS_LITERAL_STRING(TEXT_HTML).get(), + nsnull, getter_AddRefs(temp)); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = temp); } else - mUploadStreamLength = aContentLength; - mUploadStream = aStream; + NS_ADDREF(*result = mStream); - if (mUploadStream) { - // configure mIOFlags for writing - mIOFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; - if (mPerm == -1) - mPerm = PR_IRUSR | PR_IWUSR; // pick something reasonable + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) +{ + NS_ENSURE_TRUE(!mRequest, NS_ERROR_IN_PROGRESS); + + nsCOMPtr grip; + nsCOMPtr currentEventQ; + nsresult rv; + + rv = NS_GetCurrentEventQ(getter_AddRefs(currentEventQ)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr sts = + do_GetService(kStreamTransportServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + if (mUploading) { + // + // open file output stream. since output stream will be accessed on a + // background thread, we should not give it a reference to "our" nsIFile + // instance. + // + nsCOMPtr file; + rv = GetClonedFile(getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr fileOut; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut), file, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + PR_IRUSR | PR_IWUSR); + if (NS_FAILED(rv)) return rv; + + // + // create asynchronous output stream wrapping file output stream. + // + nsCOMPtr transport; + rv = sts->CreateOutputTransport(fileOut, -1, mUploadLength, PR_TRUE, + getter_AddRefs(transport)); + if (NS_FAILED(rv)) return rv; + + rv = transport->SetEventSink(this, currentEventQ); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr asyncOut; + rv = transport->OpenOutputStream(0, 0, 0, getter_AddRefs(asyncOut)); + if (NS_FAILED(rv)) return rv; + + // + // create async stream copier + // + // XXX copier might read more than mUploadLength from mStream!! not + // a huge deal, but probably should be fixed. + // + nsCOMPtr copier; + rv = NS_NewAsyncStreamCopier(getter_AddRefs(copier), mStream, asyncOut, + PR_FALSE, // assume the upload stream is unbuffered + PR_TRUE); // but, the async output stream is buffered! + if (NS_FAILED(rv)) return rv; + + rv = copier->AsyncCopy(this, nsnull); + if (NS_FAILED(rv)) return rv; + + mRequest = copier; } else { - // configure mIOFlags for reading - mIOFlags = PR_RDONLY; + // + // create file input stream + // + rv = EnsureStream(); + if (NS_FAILED(rv)) return rv; + + // + // push stream converter if opening a directory. + // + if (mIsDir && mConvertToHTML) { + nsCOMPtr scs = + do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = scs->AsyncConvertData(NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), + NS_LITERAL_STRING(TEXT_HTML).get(), + listener, nsnull, + getter_AddRefs(grip)); + if (NS_FAILED(rv)) return rv; + + listener = grip; + } + + // + // create asynchronous input stream wrapping file input stream. + // + nsCOMPtr transport; + rv = sts->CreateInputTransport(mStream, -1, -1, PR_TRUE, + getter_AddRefs(transport)); + if (NS_FAILED(rv)) return rv; + + rv = transport->SetEventSink(this, currentEventQ); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr asyncIn; + rv = transport->OpenInputStream(0, 0, 0, getter_AddRefs(asyncIn)); + if (NS_FAILED(rv)) return rv; + + // + // create input stream pump + // + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), asyncIn); + if (NS_FAILED(rv)) return rv; + + rv = pump->AsyncRead(this, nsnull); + if (NS_FAILED(rv)) return rv; + + mRequest = pump; + } + + if (mLoadGroup) + mLoadGroup->AddRequest(this, nsnull); + + mListener = listener; + mListenerContext = ctx; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// nsIFileChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsFileChannel::GetFile(nsIFile **file) +{ + return mURL->GetFile(file); +} + +//----------------------------------------------------------------------------- +// nsIUploadChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsFileChannel::SetUploadStream(nsIInputStream *stream, + const nsACString &contentType, + PRInt32 contentLength) +{ + NS_ENSURE_TRUE(!mRequest, NS_ERROR_IN_PROGRESS); + + mStream = stream; + + if (mStream) { + mUploading = PR_TRUE; + mUploadLength = contentLength; + + if (mUploadLength < 0) { + // make sure we know how much data we are uploading. + nsresult rv = mStream->Available((PRUint32 *) &mUploadLength); + if (NS_FAILED(rv)) return rv; + } + } + else { + mUploading = PR_FALSE; + mUploadLength = -1; } return NS_OK; } @@ -808,10 +537,64 @@ nsFileChannel::SetUploadStream(nsIInputStream *aStream, NS_IMETHODIMP nsFileChannel::GetUploadStream(nsIInputStream **stream) { - NS_ENSURE_ARG_POINTER(stream); - *stream = mUploadStream; - NS_IF_ADDREF(*stream); + if (mUploading) + NS_IF_ADDREF(*stream = mStream); + else + *stream = nsnull; return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsIStreamListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsFileChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx) +{ + return mListener->OnStartRequest(this, mListenerContext); +} + +NS_IMETHODIMP +nsFileChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) +{ + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, mStatus); + + mRequest = 0; + mStream = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsFileChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, + PRUint32 offset, PRUint32 count) +{ + return mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); +} + +//----------------------------------------------------------------------------- +// nsITransportEventSink +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsFileChannel::OnTransportStatus(nsITransport *trans, nsresult status, + PRUint32 progress, PRUint32 progressMax) +{ + // suppress status notification if channel is no longer pending! + if (mProgressSink && mRequest && !(mLoadFlags & LOAD_BACKGROUND)) { + // file channel does not send OnStatus events! + if (status == nsITransport::STATUS_READING || + status == nsITransport::STATUS_WRITING) { + mProgressSink->OnProgress(this, nsnull, progress, progressMax); + } + } + return NS_OK; +} diff --git a/mozilla/netwerk/protocol/file/src/nsFileChannel.h b/mozilla/netwerk/protocol/file/src/nsFileChannel.h index 7f57d94ffe5..86abf15f558 100644 --- a/mozilla/netwerk/protocol/file/src/nsFileChannel.h +++ b/mozilla/netwerk/protocol/file/src/nsFileChannel.h @@ -38,83 +38,64 @@ #ifndef nsFileChannel_h__ #define nsFileChannel_h__ -#include "nsIChannel.h" +#include "nsIFileChannel.h" +#include "nsIFileURL.h" +#include "nsIUploadChannel.h" +#include "nsIRequest.h" #include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" +#include "nsIProgressEventSink.h" #include "nsILoadGroup.h" #include "nsIStreamListener.h" -#include "nsIStreamProvider.h" -#include "nsIURI.h" -#include "nsIFile.h" /* Solaris/gcc needed this here. */ -#include "nsIFileChannel.h" -#include "nsIUploadChannel.h" #include "nsIInputStream.h" -#include "nsIProgressEventSink.h" #include "nsITransport.h" -#include "nsString.h" #include "nsCOMPtr.h" -#include "prthread.h" +#include "nsString.h" -class nsFileChannel : public nsIFileChannel, - public nsIUploadChannel, - public nsIInterfaceRequestor, - public nsIStreamListener, - public nsIStreamProvider, - public nsIProgressEventSink +class nsFileChannel : public nsIFileChannel + , public nsIUploadChannel + , public nsIStreamListener + , public nsITransportEventSink { -public: +public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL NS_DECL_NSIFILECHANNEL NS_DECL_NSIUPLOADCHANNEL - NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSISTREAMPROVIDER - NS_DECL_NSIPROGRESSEVENTSINK + NS_DECL_NSITRANSPORTEVENTSINK nsFileChannel(); - // Always make the destructor virtual: - virtual ~nsFileChannel(); + virtual ~nsFileChannel() {} - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); - - nsresult Init(PRInt32 ioFlags, PRInt32 perm, nsIURI* uri, PRBool generateHTMLDirs = PR_FALSE); - nsresult GetFileTransport(nsITransport **); - nsresult SetStreamConverter(); - nsresult EnsureFile(); + nsresult Init(nsIURI *uri, PRBool htmlDirs); -protected: - nsCOMPtr mFile; - nsCOMPtr mOriginalURI; - nsCOMPtr mURI; - nsCOMPtr mCallbacks; - PRInt32 mIOFlags; - PRInt32 mPerm; - nsCOMPtr mFileTransport; - nsCString mContentType; - nsCString mContentCharset; - PRUint32 mLoadFlags; - nsCOMPtr mLoadGroup; - nsCOMPtr mOwner; - nsCOMPtr mRealListener; - PRUint32 mTransferOffset; - PRInt32 mTransferCount; - PRUint32 mBufferSegmentSize; - PRUint32 mBufferMaxSize; - nsresult mStatus; - nsCOMPtr mProgress; - nsCOMPtr mCurrentRequest; - nsCOMPtr mUploadStream; - PRUint32 mUploadStreamLength; - PRBool mGenerateHTMLDirs; +private: -#ifdef DEBUG - PRThread* mInitiator; -#endif + nsresult GetClonedFile(nsIFile **); + nsresult EnsureStream(); + + nsCOMPtr mURL; + nsCOMPtr mOriginalURI; + nsCOMPtr mOwner; + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; + nsCOMPtr mLoadGroup; + nsCOMPtr mListener; + nsCOMPtr mListenerContext; + nsCString mContentType; + nsCString mContentCharset; + PRInt32 mContentLength; + PRInt32 mUploadLength; + PRUint32 mLoadFlags; + nsresult mStatus; + + nsCOMPtr mRequest; + nsCOMPtr mStream; + PRBool mConvertToHTML; // applies only if is directory + PRBool mIsDir; + PRBool mUploading; }; -#endif // nsFileChannel_h__ +#endif // !nsFileChannel_h__ diff --git a/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.cpp b/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.cpp index 3e8d5e83abc..5477bddd1d4 100644 --- a/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.cpp +++ b/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.cpp @@ -35,87 +35,58 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsFileChannel.h" #include "nsFileProtocolHandler.h" -#include "nsIURL.h" -#include "nsIURLParser.h" -#include "nsIStandardURL.h" -#include "nsIFileURL.h" -#include "nsIPref.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIProgressEventSink.h" -#include "nsIThread.h" -#include "nsIThreadPool.h" -#include "nsISupportsArray.h" -#include "nsXPIDLString.h" +#include "nsFileChannel.h" +#include "nsInputStreamChannel.h" #include "nsStandardURL.h" -#include "nsNetCID.h" #include "nsURLHelper.h" +#include "nsNetCID.h" + +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIServiceManager.h" #include "nsIDirectoryListing.h" static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID); -static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); +static NS_DEFINE_CID(kPrefServiceCID, NS_PREFSERVICE_CID); -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- nsFileProtocolHandler::nsFileProtocolHandler() + : mGenerateHTMLDirs(PR_FALSE) { - mGenerateHTMLContent = PR_FALSE; } nsresult nsFileProtocolHandler::Init() { nsresult rv; - nsCOMPtr pPref(do_GetService(kPrefCID, &rv)); - if (NS_SUCCEEDED(rv) || pPref) { - PRInt32 sFormat; - rv = pPref->GetIntPref("network.dir.format", &sFormat); - - if (NS_SUCCEEDED(rv) && sFormat == nsIDirectoryListing::FORMAT_HTML) - mGenerateHTMLContent = PR_TRUE; + nsCOMPtr prefService = do_GetService(kPrefServiceCID, &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr prefBranch; + rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch)); + if (NS_SUCCEEDED(rv)) { + PRInt32 sFormat; + rv = prefBranch->GetIntPref("network.dir.format", &sFormat); + if (NS_SUCCEEDED(rv) && sFormat == nsIDirectoryListing::FORMAT_HTML) + mGenerateHTMLDirs = PR_TRUE; + } } - return NS_OK; } -nsFileProtocolHandler::~nsFileProtocolHandler() -{ -} - NS_IMPL_THREADSAFE_ISUPPORTS3(nsFileProtocolHandler, nsIFileProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference); -NS_METHOD -nsFileProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) -{ - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - - nsFileProtocolHandler* ph = new nsFileProtocolHandler(); - if (ph == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(ph); - nsresult rv = ph->Init(); - if (NS_SUCCEEDED(rv)) { - rv = ph->QueryInterface(aIID, aResult); - } - NS_RELEASE(ph); - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // nsIProtocolHandler methods: NS_IMETHODIMP nsFileProtocolHandler::GetScheme(nsACString &result) { - result = "file"; + result = NS_LITERAL_CSTRING("file"); return NS_OK; } @@ -134,54 +105,49 @@ nsFileProtocolHandler::GetProtocolFlags(PRUint32 *result) } NS_IMETHODIMP -nsFileProtocolHandler::NewURI(const nsACString &aSpec, - const char *aCharset, - nsIURI *aBaseURI, +nsFileProtocolHandler::NewURI(const nsACString &spec, + const char *charset, + nsIURI *baseURI, nsIURI **result) { - nsresult rv; - nsCOMPtr url = new nsStandardURL(PR_TRUE); if (!url) return NS_ERROR_OUT_OF_MEMORY; - rv = url->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, aSpec, aCharset, aBaseURI); + nsresult rv = url->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, + spec, charset, baseURI); if (NS_FAILED(rv)) return rv; return CallQueryInterface(url, result); } NS_IMETHODIMP -nsFileProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result) +nsFileProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result) { - nsresult rv; - - nsFileChannel* channel; - rv = nsFileChannel::Create(nsnull, NS_GET_IID(nsIFileChannel), (void**)&channel); - if (NS_FAILED(rv)) return rv; + nsFileChannel *chan = new nsFileChannel(); + if (!chan) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(chan); - rv = channel->Init(-1, // ioFlags unspecified - -1, // permissions unspecified - url, - mGenerateHTMLContent); + nsresult rv = chan->Init(uri, mGenerateHTMLDirs); if (NS_FAILED(rv)) { - NS_RELEASE(channel); + NS_RELEASE(chan); return rv; } - *result = channel; + *result = chan; return NS_OK; } NS_IMETHODIMP -nsFileProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval) +nsFileProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *result) { // don't override anything. - *_retval = PR_FALSE; + *result = PR_FALSE; return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- // nsIFileProtocolHandler methods: NS_IMETHODIMP @@ -202,13 +168,13 @@ nsFileProtocolHandler::NewFileURI(nsIFile *file, nsIURI **result) } NS_IMETHODIMP -nsFileProtocolHandler::GetURLSpecFromFile(nsIFile *aFile, nsACString &result) +nsFileProtocolHandler::GetURLSpecFromFile(nsIFile *file, nsACString &result) { - return net_GetURLSpecFromFile(aFile, result); + return net_GetURLSpecFromFile(file, result); } NS_IMETHODIMP -nsFileProtocolHandler::GetFileFromURLSpec(const nsACString &aURL, nsIFile **result) +nsFileProtocolHandler::GetFileFromURLSpec(const nsACString &spec, nsIFile **result) { - return net_GetFileFromURLSpec(aURL, result); + return net_GetFileFromURLSpec(spec, result); } diff --git a/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.h b/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.h index d72a7423e1e..dbca09def79 100644 --- a/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.h +++ b/mozilla/netwerk/protocol/file/src/nsFileProtocolHandler.h @@ -35,29 +35,14 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsFileProtocolHandler_h___ -#define nsFileProtocolHandler_h___ +#ifndef nsFileProtocolHandler_h__ +#define nsFileProtocolHandler_h__ #include "nsIFileProtocolHandler.h" #include "nsWeakReference.h" -class nsISupportsArray; -class nsIRunnable; -class nsFileChannel; -class nsIThreadPool; - -#define NS_FILE_TRANSPORT_WORKER_COUNT 1//4 - -// {25029490-F132-11d2-9588-00805F369F95} -#define NS_FILEPROTOCOLHANDLER_CID \ -{ /* fbc81170-1f69-11d3-9344-00104ba0fd40 */ \ - 0xfbc81170, \ - 0x1f69, \ - 0x11d3, \ - {0x93, 0x44, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ -} - -class nsFileProtocolHandler : public nsIFileProtocolHandler, public nsSupportsWeakReference +class nsFileProtocolHandler : public nsIFileProtocolHandler + , public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS @@ -65,15 +50,12 @@ public: NS_DECL_NSIFILEPROTOCOLHANDLER nsFileProtocolHandler(); - virtual ~nsFileProtocolHandler(); - - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + virtual ~nsFileProtocolHandler() {} nsresult Init(); protected: - PRBool mGenerateHTMLContent; + PRBool mGenerateHTMLDirs; }; -#endif /* nsFileProtocolHandler_h___ */ +#endif // !nsFileProtocolHandler_h__ diff --git a/mozilla/netwerk/protocol/ftp/public/ftpCore.h b/mozilla/netwerk/protocol/ftp/public/ftpCore.h index a024405e4e2..c0d70339cf0 100644 --- a/mozilla/netwerk/protocol/ftp/public/ftpCore.h +++ b/mozilla/netwerk/protocol/ftp/public/ftpCore.h @@ -50,9 +50,3 @@ NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_NETWORK, 28) #endif // __ftpCore_h___ - - - - - - diff --git a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp index 96959ba198e..528ccd9593f 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp @@ -46,6 +46,7 @@ #include "nsReadableUtils.h" #include "nsIPref.h" #include "nsIStreamConverterService.h" +#include "nsISocketTransport.h" #if defined(PR_LOGGING) extern PRLogModuleInfo* gFTPLog; @@ -590,7 +591,7 @@ nsFTPChannel::OnStatus(nsIRequest *request, nsISupports *aContext, (void) mFTPState->DataConnectionEstablished(); } - if (!mEventSink) + if (!mEventSink || (mLoadFlags & LOAD_BACKGROUND) || !mIsPending) return NS_OK; return mEventSink->OnStatus(this, mUserContext, aStatus, @@ -599,8 +600,9 @@ nsFTPChannel::OnStatus(nsIRequest *request, nsISupports *aContext, NS_IMETHODIMP nsFTPChannel::OnProgress(nsIRequest *request, nsISupports* aContext, - PRUint32 aProgress, PRUint32 aProgressMax) { - if (!mEventSink) + PRUint32 aProgress, PRUint32 aProgressMax) +{ + if (!mEventSink || (mLoadFlags & LOAD_BACKGROUND) || !mIsPending) return NS_OK; return mEventSink->OnProgress(this, mUserContext, diff --git a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h index 92a7d2f62ec..3531172c91a 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h +++ b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h @@ -70,10 +70,10 @@ #include "nsICacheSession.h" #define FTP_COMMAND_CHANNEL_SEG_SIZE 64 -#define FTP_COMMAND_CHANNEL_MAX_SIZE 512 +#define FTP_COMMAND_CHANNEL_SEG_COUNT 8 -#define FTP_DATA_CHANNEL_SEG_SIZE (4*1024) -#define FTP_DATA_CHANNEL_MAX_SIZE (8 * FTP_DATA_CHANNEL_SEG_SIZE) +#define FTP_DATA_CHANNEL_SEG_SIZE (4*1024) +#define FTP_DATA_CHANNEL_SEG_COUNT 8 #define FTP_CACHE_CONTROL_CONNECTION 1 diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp index 8be8f10053b..2c3ec6d61c2 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp @@ -67,6 +67,7 @@ #include "nsIPref.h" #include "nsMimeTypes.h" #include "nsIStringBundle.h" +#include "nsEventQueueUtils.h" #include "nsICacheEntryDescriptor.h" #include "nsICacheListener.h" @@ -84,13 +85,12 @@ static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); extern PRLogModuleInfo* gFTPLog; #endif /* PR_LOGGING */ -#define NS_SUCCESS_IGNORE_NOTIFICATION 0x00000666 +#define NS_ERROR_IGNORE_NOTIFICATION 0x80000666 class DataRequestForwarder : public nsIFTPChannel, public nsIStreamListener, - public nsIInterfaceRequestor, - public nsIProgressEventSink, - public nsIResumableChannel + public nsIResumableChannel, + public nsITransportEventSink { public: DataRequestForwarder(); @@ -104,16 +104,15 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSIPROGRESSEVENTSINK NS_DECL_NSIRESUMABLECHANNEL + NS_DECL_NSITRANSPORTEVENTSINK NS_FORWARD_NSIREQUEST(mRequest->) NS_FORWARD_NSICHANNEL(mFTPChannel->) NS_FORWARD_NSIFTPCHANNEL(mFTPChannel->) PRUint32 GetBytesTransfered() {return mBytesTransfered;} ; - void Uploading(PRBool value); + void Uploading(PRBool value, PRUint32 uploadCount); void SetRetrying(PRBool retry); protected: @@ -126,6 +125,7 @@ protected: nsCOMPtr mEntityID; PRUint32 mBytesTransfered; + PRUint32 mBytesToUpload; PRPackedBool mDelayedOnStartFired; PRPackedBool mUploading; PRPackedBool mRetrying; @@ -138,15 +138,14 @@ protected: // the socket transport so that clients only see // the same nsIChannel/nsIRequest that they started. -NS_IMPL_THREADSAFE_ISUPPORTS8(DataRequestForwarder, +NS_IMPL_THREADSAFE_ISUPPORTS7(DataRequestForwarder, nsIStreamListener, nsIRequestObserver, nsIFTPChannel, nsIResumableChannel, nsIChannel, nsIRequest, - nsIInterfaceRequestor, - nsIProgressEventSink); + nsITransportEventSink) DataRequestForwarder::DataRequestForwarder() @@ -154,6 +153,7 @@ DataRequestForwarder::DataRequestForwarder() PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) DataRequestForwarder CREATED\n", this)); mBytesTransfered = 0; + mBytesToUpload = 0; mRetrying = mUploading = mDelayedOnStartFired = PR_FALSE; } @@ -161,20 +161,6 @@ DataRequestForwarder::~DataRequestForwarder() { } -// nsIInterfaceRequestor method -NS_IMETHODIMP -DataRequestForwarder::GetInterface(const nsIID &anIID, void **aResult ) -{ - if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) - { - *aResult = NS_STATIC_CAST(nsIProgressEventSink*, this); - NS_ADDREF_THIS(); - return NS_OK; - } - return NS_ERROR_NO_INTERFACE; -} - - nsresult DataRequestForwarder::Init(nsIRequest *request) { @@ -195,9 +181,10 @@ DataRequestForwarder::Init(nsIRequest *request) } void -DataRequestForwarder::Uploading(PRBool value) +DataRequestForwarder::Uploading(PRBool value, PRUint32 uploadCount) { mUploading = value; + mBytesToUpload = uploadCount; } nsresult @@ -211,12 +198,9 @@ DataRequestForwarder::SetCacheEntry(nsICacheEntryDescriptor *cacheEntry, PRBool if (!writing) return NS_OK; - nsCOMPtr cacheTransport; - nsresult rv = cacheEntry->GetTransport(getter_AddRefs(cacheTransport)); - if (NS_FAILED(rv)) return rv; - + nsresult rv; nsCOMPtr out; - rv = cacheTransport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(out)); + rv = cacheEntry->OpenOutputStream(0, getter_AddRefs(out)); if (NS_FAILED(rv)) return rv; nsCOMPtr tee = @@ -296,14 +280,10 @@ DataRequestForwarder::OnStartRequest(nsIRequest *request, nsISupports *ctxt) NS_ASSERTION(mListener, "No Listener Set."); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) DataRequestForwarder OnStartRequest \n[mRetrying=%d]", this, mRetrying)); - if (mRetrying) { - mRetrying = PR_FALSE; - return NS_OK; - } - if (!mListener) return NS_ERROR_NOT_INITIALIZED; + // OnStartRequest is delayed. return NS_OK; } @@ -312,8 +292,12 @@ DataRequestForwarder::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsre { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) DataRequestForwarder OnStopRequest [status=%x, mRetrying=%d]\n", this, statusCode, mRetrying)); - if (mRetrying || statusCode == NS_SUCCESS_IGNORE_NOTIFICATION) + if (statusCode == NS_ERROR_IGNORE_NOTIFICATION) return NS_OK; + if (mRetrying) { + mRetrying = PR_FALSE; + return NS_OK; + } // If there were no calls to ODA, then the onstart won't have been // fired - bug 122913 @@ -322,16 +306,6 @@ DataRequestForwarder::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsre nsresult rv = DelayedOnStartRequest(request, ctxt); if (NS_FAILED(rv)) return rv; } - - nsCOMPtr trequest(do_QueryInterface(request)); - if (trequest) - { - nsCOMPtr trans; - trequest->GetTransport(getter_AddRefs(trans)); - nsCOMPtr sTrans (do_QueryInterface(trans)); - if (sTrans) - sTrans->SetReuseConnection(PR_FALSE); - } if (!mListener) return NS_ERROR_NOT_INITIALIZED; @@ -357,48 +331,38 @@ DataRequestForwarder::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, ns } rv = mListener->OnDataAvailable(this, ctxt, input, mBytesTransfered, count); - mBytesTransfered += count; + if (NS_SUCCEEDED(rv)) + mBytesTransfered += count; return rv; } - -// nsIProgressEventSink methods +// nsITransportEventSink methods NS_IMETHODIMP -DataRequestForwarder::OnStatus(nsIRequest *request, nsISupports *aContext, - nsresult aStatus, const PRUnichar* aStatusArg) +DataRequestForwarder::OnTransportStatus(nsITransport *transport, nsresult status, + PRUint32 progress, PRUint32 progressMax) { - if (!mEventSink) - return NS_OK; + if (mEventSink) { + mEventSink->OnStatus(nsnull, nsnull, status, nsnull); - return mEventSink->OnStatus(nsnull, nsnull, aStatus, nsnull); -} - -NS_IMETHODIMP -DataRequestForwarder::OnProgress(nsIRequest *request, nsISupports* aContext, - PRUint32 aProgress, PRUint32 aProgressMax) { - if (!mEventSink) - return NS_OK; - - // we want to delay firing the onStartRequest until we know that there is data - if (!mDelayedOnStartFired) { - mDelayedOnStartFired = PR_TRUE; - nsresult rv = DelayedOnStartRequest(request, aContext); - NS_ASSERTION(NS_SUCCEEDED(rv), "DelayedOnStartRequest failed"); + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + status == nsISocketTransport::STATUS_SENDING_TO) { + // compute progress based on whether we are uploading or receiving... + PRUint32 count = mUploading ? progress : mBytesTransfered; + PRUint32 max = mUploading ? mBytesToUpload : progressMax; + mEventSink->OnProgress(this, nsnull, count, max); + } } - - PRUint32 count = mUploading ? aProgress : mBytesTransfered; - PRUint32 max = mUploading ? aProgressMax : 0; - return mEventSink->OnProgress(this, nsnull, count, max); + return NS_OK; } - NS_IMPL_THREADSAFE_ISUPPORTS3(nsFtpState, nsIStreamListener, nsIRequestObserver, nsIRequest); -nsFtpState::nsFtpState() { +nsFtpState::nsFtpState() +{ PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("(%x) nsFtpState created", this)); // bool init mRETRFailed = PR_FALSE; @@ -416,6 +380,8 @@ nsFtpState::nsFtpState() { mReceivedControlData = PR_FALSE; mControlStatus = NS_OK; + mWriteCount = 0; + mIPv6Checked = PR_FALSE; mIPv6ServerAddress = nsnull; @@ -1665,22 +1631,36 @@ nsFtpState::R_stor() { } if (mResponseCode/100 == 1) { - PRUint32 len; - mWriteStream->Available(&len); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) writing on Data Transport\n", this)); // Close the read pipe since we are going to be writing data. - if (mDPipeRequest) - mDPipeRequest->Cancel(NS_SUCCESS_IGNORE_NOTIFICATION); - - nsresult rv = NS_AsyncWriteFromStream(getter_AddRefs(mDPipeRequest), - mDPipe, - mWriteStream, - 0, - len, - 0, - mDRequestForwarder); + if (mDPipeRequest) { + mDPipeRequest->Cancel(NS_ERROR_IGNORE_NOTIFICATION); + mDPipeRequest = 0; + } + + nsresult rv; + + // nsIUploadChannel requires the upload stream to support ReadSegments. + // therefore, we can open an unbuffered socket output stream. + nsCOMPtr output; + rv = mDPipe->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, + getter_AddRefs(output)); if (NS_FAILED(rv)) return FTP_ERROR; + + nsCOMPtr copier; + rv = NS_NewAsyncStreamCopier(getter_AddRefs(copier), + mWriteStream, + output, + PR_TRUE, // mWriteStream is buffered + PR_FALSE); // output is NOT buffered + if (NS_FAILED(rv)) return FTP_ERROR; + + rv = copier->AsyncCopy(mDRequestForwarder, nsnull); + if (NS_FAILED(rv)) return FTP_ERROR; + + // hold a reference to the copier so we can cancel it if necessary. + mDPipeRequest = copier; return FTP_READ_BUF; } @@ -1702,21 +1682,22 @@ nsFtpState::S_pasv() { nsCOMPtr sTrans = do_QueryInterface(controlSocket, &rv); if (sTrans) { - rv = sTrans->GetIPStr(100, &mIPv6ServerAddress); - } - - if (NS_SUCCEEDED(rv)) { PRNetAddr addr; - if (PR_StringToNetAddr(mIPv6ServerAddress, &addr) != PR_SUCCESS || - PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { - nsMemory::Free(mIPv6ServerAddress); - mIPv6ServerAddress = 0; + rv = sTrans->GetAddress(&addr); + if (NS_SUCCEEDED(rv)) { + if (addr.raw.family == PR_AF_INET6 && !PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { + mIPv6ServerAddress = (char *) nsMemory::Alloc(100); + if (mIPv6ServerAddress) { + if (PR_NetAddrToString(&addr, mIPv6ServerAddress, 100) != PR_SUCCESS) { + nsMemory::Free(mIPv6ServerAddress); + mIPv6ServerAddress = 0; + } + } + } } - PR_ASSERT(!mIPv6ServerAddress || addr.raw.family == PR_AF_INET6); } } - const char * string; if (mIPv6ServerAddress) string = "EPSV" CRLF; @@ -1820,27 +1801,22 @@ nsFtpState::R_pasv() { // Reuse this connection only if its still alive, and the port // is the same - nsCOMPtr st = do_QueryInterface(mDPipe); - - if (st) { + if (mDPipe) { PRInt32 oldPort; - nsresult rv = st->GetPort(&oldPort); + nsresult rv = mDPipe->GetPort(&oldPort); if (NS_SUCCEEDED(rv)) { if (oldPort == port) { PRBool isAlive; - if (NS_SUCCEEDED(st->IsAlive(0, &isAlive)) && isAlive) { + if (NS_SUCCEEDED(mDPipe->IsAlive(&isAlive)) && isAlive) newDataConn = PR_FALSE; - } } } } if (newDataConn) { - if (st) - st->SetReuseConnection(PR_FALSE); - mDPipe = 0; - mDPipeRequest->Cancel(NS_OK); + mDPipeRequest->Cancel(NS_ERROR_ABORT); mDPipeRequest = 0; + mDPipe = 0; } else { mDRequestForwarder->SetRetrying(PR_FALSE); } @@ -1850,21 +1826,13 @@ nsFtpState::R_pasv() { // now we know where to connect our data channel nsCOMPtr sts = do_GetService(kSocketTransportServiceCID, &rv); - rv = sts->CreateTransport(hostStr, - port, - mProxyInfo, - FTP_DATA_CHANNEL_SEG_SIZE, - FTP_DATA_CHANNEL_MAX_SIZE, - getter_AddRefs(mDPipe)); // the data channel + rv = sts->CreateTransport(nsnull, 0, + nsDependentCString(hostStr), port, mProxyInfo, + getter_AddRefs(mDPipe)); // the data socket if (NS_FAILED(rv)) return FTP_ERROR; PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Created Data Transport (%s:%x)\n", this, hostStr, port)); - nsCOMPtr sTrans = do_QueryInterface(mDPipe, &rv); - if (NS_FAILED(rv)) return FTP_ERROR; - - if (NS_FAILED(sTrans->SetReuseConnection(PR_TRUE))) return FTP_ERROR; - if (!mDRequestForwarder) { mDRequestForwarder = new DataRequestForwarder; if (!mDRequestForwarder) return FTP_ERROR; @@ -1877,24 +1845,52 @@ nsFtpState::R_pasv() { } } - // hook ourself up as a proxy for progress notifications mWaitingForDConn = PR_TRUE; - rv = mDPipe->SetNotificationCallbacks(NS_STATIC_CAST(nsIInterfaceRequestor*, mDRequestForwarder), PR_FALSE); + + // hook ourself up as a proxy for status notifications + nsCOMPtr eventQ; + rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ)); if (NS_FAILED(rv)){ - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) forwarder->SetNotificationCallbacks failed (rv=%x)\n", this, rv)); + PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) NS_GetCurrentEventQ failed (rv=%x)\n", this, rv)); + return FTP_ERROR; + } + rv = mDPipe->SetEventSink(NS_STATIC_CAST(nsITransportEventSink*, mDRequestForwarder), eventQ); + if (NS_FAILED(rv)){ + PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) forwarder->SetEventSink failed (rv=%x)\n", this, rv)); + return FTP_ERROR; + } + + // open a buffered, asynchronous socket input stream + nsCOMPtr input; + rv = mDPipe->OpenInputStream(0, + FTP_DATA_CHANNEL_SEG_SIZE, + FTP_DATA_CHANNEL_SEG_COUNT, + getter_AddRefs(input)); + if (NS_FAILED(rv)) { + PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) OpenInputStream failed (rv=%x)\n", this, rv)); + return FTP_ERROR; + } + + // pump data to the request forwarder... + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), input, -1, -1, 0, 0, PR_TRUE); + if (NS_FAILED(rv)) { + PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) NS_NewInputStreamPump failed (rv=%x)\n", this, rv)); return FTP_ERROR; } - // we need to get mDPipe going so tcp connection is made - rv = mDPipe->AsyncRead(mDRequestForwarder, nsnull, 0, PRUint32(-1), 0, getter_AddRefs(mDPipeRequest)); - if (NS_FAILED(rv)){ - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) forwarder->AsyncRead failed (rv=%x)\n", this, rv)); + rv = pump->AsyncRead(mDRequestForwarder, nsnull); + if (NS_FAILED(rv)) { + PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) AsyncRead failed (rv=%x)\n", this, rv)); return FTP_ERROR; } + + // hold a reference to the input stream pump so we can cancel it. + mDPipeRequest = pump; if (mAction == PUT) { NS_ASSERTION(!mRETRFailed, "Failed before uploading"); - mDRequestForwarder->Uploading(PR_TRUE); + mDRequestForwarder->Uploading(PR_TRUE, mWriteCount); return FTP_S_STOR; } @@ -2007,11 +2003,10 @@ nsFtpState::Resume(void) PRBool dataAlive = PR_FALSE; - nsCOMPtr dataSocket = do_QueryInterface(mDPipe); - if (dataSocket) - dataSocket->IsAlive(0, &dataAlive); + if (mDPipe) + mDPipe->IsAlive(&dataAlive); - if (dataSocket && dataAlive && mControlConnection->IsAlive()) + if (mDPipe && dataAlive && mControlConnection->IsAlive()) { nsCOMPtr controlRequest; mControlConnection->GetReadRequest(getter_AddRefs(controlRequest)); @@ -2200,15 +2195,19 @@ nsFtpState::Init(nsIFTPChannel* aChannel, mDRequestForwarder->SetEntityID(nsnull); // Get a transport to the cached data... - nsCOMPtr transport; - rv = mCacheEntry->GetTransport(getter_AddRefs(transport)); + nsCOMPtr input; + rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(input)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), input); if (NS_FAILED(rv)) return rv; // Pump the cache data downstream - return transport->AsyncRead(mDRequestForwarder, - nsnull, - 0, PRUint32(-1), 0, - getter_AddRefs(mDPipeRequest)); + rv = pump->AsyncRead(mDRequestForwarder, nsnull); + if (NS_FAILED(rv)) return rv; + + mDPipeRequest = pump; } } @@ -2302,6 +2301,7 @@ nsFtpState::SetWriteStream(nsIInputStream* aInStream) { mAction = PUT; mWriteStream = aInStream; + mWriteStream->Available(&mWriteCount); return NS_OK; } @@ -2310,7 +2310,8 @@ nsFtpState::KillControlConnection() { mControlReadCarryOverBuf.Truncate(0); if (mDPipe) { - mDPipe->SetNotificationCallbacks(nsnull, PR_FALSE); + mDPipe->SetSecurityCallbacks(nsnull); + mDPipe->SetEventSink(nsnull, nsnull); mDPipe = 0; } @@ -2491,7 +2492,7 @@ nsFtpState::DataConnectionEstablished() { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Data Connection established.", this)); - mWaitingForDConn= PR_FALSE; + mWaitingForDConn = PR_FALSE; // sending empty string with (mWaitingForDConn == PR_FALSE) will cause the // control socket to write out its buffer. diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h index 4814e88ec8c..8d8c9e587e3 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h @@ -42,6 +42,7 @@ #include "nsIThread.h" #include "nsIRunnable.h" #include "nsISocketTransportService.h" +#include "nsISocketTransport.h" #include "nsIServiceManager.h" #include "nsIStreamListener.h" #include "nsIURI.h" @@ -186,7 +187,7 @@ private: PRPackedBool mTryingCachedControl; // retrying the password PRPackedBool mWaitingForDConn; // Are we wait for a data connection PRPackedBool mRETRFailed; // Did we already try a RETR and it failed? - nsCOMPtr mDPipe; // the data transport + nsCOMPtr mDPipe; // the data transport nsCOMPtr mDPipeRequest; DataRequestForwarder* mDRequestForwarder; PRUint32 mFileSize; @@ -221,6 +222,7 @@ private: PRUint32 mBufferMaxSize; PRLock *mLock; nsCOMPtr mWriteStream; // This stream is written to the server. + PRUint32 mWriteCount; PRPackedBool mIPv6Checked; nsCOMPtr mPrompter; nsCOMPtr mFTPEventSink; diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.cpp b/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.cpp index bcd01170159..4a498fd09f2 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.cpp @@ -41,9 +41,9 @@ #include "prlog.h" #include "nsIPipe.h" #include "nsIInputStream.h" -#include "nsIStreamProvider.h" #include "nsISocketTransportService.h" #include "nsISocketTransport.h" +#include "nsNetUtil.h" #include "nsCRT.h" #if defined(PR_LOGGING) @@ -52,54 +52,6 @@ extern PRLogModuleInfo* gFTPLog; static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); -class nsFtpStreamProvider : public nsIStreamProvider { -public: - NS_DECL_ISUPPORTS - - nsFtpStreamProvider() {} - virtual ~nsFtpStreamProvider() {} - - // - // nsIRequestObserver implementation ... - // - NS_IMETHODIMP OnStartRequest(nsIRequest *req, nsISupports *ctxt) { return NS_OK; } - NS_IMETHODIMP OnStopRequest(nsIRequest *req, nsISupports *ctxt, nsresult status) { return NS_OK; } - - // - // nsIStreamProvider implementation ... - // - NS_IMETHODIMP OnDataWritable(nsIRequest *aRequest, nsISupports *aContext, - nsIOutputStream *aOutStream, - PRUint32 aOffset, PRUint32 aCount) - { - NS_ASSERTION(mInStream, "not initialized"); - - nsresult rv; - PRUint32 avail; - - // Write whatever is available in the pipe. If the pipe is empty, then - // return NS_BASE_STREAM_WOULD_BLOCK; we will resume the write when there - // is more data. - - rv = mInStream->Available(&avail); - if (NS_FAILED(rv)) return rv; - - if (avail == 0) { - NS_STATIC_CAST(nsFtpControlConnection*, (nsIStreamListener*)aContext)->mSuspendedWrite = 1; - return NS_BASE_STREAM_WOULD_BLOCK; - } - PRUint32 bytesWritten; - return aOutStream->WriteFrom(mInStream, PR_MIN(avail, aCount), &bytesWritten); - } - - nsCOMPtr mInStream; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpStreamProvider, - nsIStreamProvider, - nsIRequestObserver) - - // // nsFtpControlConnection implementation ... // @@ -110,7 +62,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpControlConnection, nsFtpControlConnection::nsFtpControlConnection(const char* host, PRUint32 port) - : mServerType(0), mSuspendedWrite(0), mPort(port) + : mServerType(0), mPort(port) { PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("(%x) nsFtpControlConnection created", this)); @@ -134,10 +86,7 @@ nsFtpControlConnection::IsAlive() return PR_FALSE; PRBool isAlive = PR_FALSE; - nsCOMPtr sTrans = do_QueryInterface(mCPipe); - if (!sTrans) return PR_FALSE; - - sTrans->IsAlive(0, &isAlive); + mCPipe->IsAlive(&isAlive); return isAlive; } nsresult @@ -145,59 +94,41 @@ nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo) { nsresult rv; - if (!mCPipe) { - nsCOMPtr transport; + if (!mCPipe) { // build our own - nsCOMPtr sts = do_GetService(kSocketTransportServiceCID, &rv); + nsCOMPtr sts = + do_GetService(kSocketTransportServiceCID, &rv); - rv = sts->CreateTransport(mHost, - mPort, - proxyInfo, - FTP_COMMAND_CHANNEL_SEG_SIZE, - FTP_COMMAND_CHANNEL_MAX_SIZE, + rv = sts->CreateTransport(nsnull, 0, mHost, mPort, proxyInfo, getter_AddRefs(mCPipe)); // the command transport if (NS_FAILED(rv)) return rv; - } - nsCOMPtr sTrans (do_QueryInterface(mCPipe)); - if (!sTrans) - return NS_ERROR_FAILURE; - - sTrans->SetReuseConnection(PR_TRUE); - - nsCOMPtr inStream; - - rv = NS_NewPipe(getter_AddRefs(inStream), - getter_AddRefs(mOutStream), - 1024, // segmentSize - 1024, // maxSize - PR_TRUE, - PR_TRUE); - - if (NS_FAILED(rv)) return rv; - - nsCOMPtr provider; - NS_NEWXPCOM(provider, nsFtpStreamProvider); - if (!provider) return NS_ERROR_OUT_OF_MEMORY; - - // setup the stream provider to get data from the pipe. - NS_STATIC_CAST(nsFtpStreamProvider*, - NS_STATIC_CAST(nsIStreamProvider*, provider))->mInStream = inStream; - - rv = mCPipe->AsyncWrite(provider, - NS_STATIC_CAST(nsISupports*, (nsIStreamListener*)this), - 0, PRUint32(-1), - nsITransport::DONT_PROXY_PROVIDER | - nsITransport::DONT_PROXY_OBSERVER, - getter_AddRefs(mWriteRequest)); + // open buffered, blocking output stream to socket. so long as commands + // do not exceed 1024 bytes in length, the writing thread (the main thread) + // will not block. this should be OK. + rv = mCPipe->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1, + getter_AddRefs(mOutStream)); + if (NS_FAILED(rv)) return rv; + + // open buffered, non-blocking/asynchronous input stream to socket. + rv = mCPipe->OpenInputStream(0, + FTP_COMMAND_CHANNEL_SEG_SIZE, + FTP_COMMAND_CHANNEL_SEG_COUNT, + getter_AddRefs(mInStream)); + if (NS_FAILED(rv)) return rv; + } + + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), mInStream); if (NS_FAILED(rv)) return rv; // get the ball rolling by reading on the control socket. - rv = mCPipe->AsyncRead(NS_STATIC_CAST(nsIStreamListener*, this), - nsnull, 0, PRUint32(-1), 0, - getter_AddRefs(mReadRequest)); + rv = pump->AsyncRead(NS_STATIC_CAST(nsIStreamListener*, this), nsnull); + if (NS_FAILED(rv)) return rv; - return rv; + // cyclic reference! + mReadRequest = pump; + return NS_OK; } nsresult @@ -207,14 +138,16 @@ nsFtpControlConnection::Disconnect(nsresult status) PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("(%x) nsFtpControlConnection disconnecting (%x)", this, status)); - if (mWriteRequest) { - mWriteRequest->Cancel(status); - mWriteRequest = nsnull; - } - if (mReadRequest) { + if (NS_FAILED(status)) { mReadRequest->Cancel(status); - mReadRequest = nsnull; + mCPipe->Close(status); + mCPipe = 0; + mInStream = 0; + mOutStream = 0; } + + // break cyclic reference! + mReadRequest = 0; return NS_OK; } @@ -227,22 +160,17 @@ nsFtpControlConnection::Write(nsCString& command, PRBool suspend) PRUint32 len = command.Length(); PRUint32 cnt; nsresult rv = mOutStream->Write(command.get(), len, &cnt); - + if (NS_FAILED(rv)) return rv; - - if (len!=cnt) - return NS_ERROR_FAILURE; + if (len != cnt) + return NS_ERROR_FAILURE; + if (suspend) return NS_OK; - PRInt32 writeWasSuspended = PR_AtomicSet(&mSuspendedWrite, 0); - if (writeWasSuspended) - mWriteRequest->Resume(); - return NS_OK; - } nsresult @@ -283,7 +211,7 @@ nsFtpControlConnection::OnStartRequest(nsIRequest *request, nsISupports *aContex NS_IMETHODIMP nsFtpControlConnection::OnStopRequest(nsIRequest *request, nsISupports *aContext, - nsresult aStatus) + nsresult aStatus) { if (!mCPipe) @@ -307,10 +235,10 @@ nsFtpControlConnection::OnStopRequest(nsIRequest *request, nsISupports *aContext NS_IMETHODIMP nsFtpControlConnection::OnDataAvailable(nsIRequest *request, - nsISupports *aContext, - nsIInputStream *aInStream, - PRUint32 aOffset, - PRUint32 aCount) + nsISupports *aContext, + nsIInputStream *aInStream, + PRUint32 aOffset, + PRUint32 aCount) { if (!mCPipe) return NS_OK; diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.h b/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.h index 0a8e36f10da..34f0f1cfb50 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.h +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpControlConnection.h @@ -43,10 +43,10 @@ #include "nsIURI.h" #include "nsIStreamListener.h" #include "nsIRequest.h" -#include "nsITransport.h" -#include "nsString.h" +#include "nsISocketTransport.h" #include "nsIOutputStream.h" #include "nsAutoLock.h" +#include "nsString.h" class nsIProxyInfo; @@ -65,7 +65,6 @@ public: nsresult Write(nsCString& command, PRBool suspend); void GetReadRequest(nsIRequest** request) { NS_IF_ADDREF(*request=mReadRequest); } - void GetWriteRequest(nsIRequest** request) { NS_IF_ADDREF(*request=mWriteRequest); } PRBool IsAlive(); @@ -84,12 +83,12 @@ private: nsXPIDLCString mHost; PRUint32 mPort; - nsCOMPtr mReadRequest; - nsCOMPtr mWriteRequest; - nsCOMPtr mCPipe; - nsCOMPtr mOutStream; - nsCOMPtr mListener; - PRPackedBool mWriteSuspened; + + nsCOMPtr mReadRequest; + nsCOMPtr mCPipe; + nsCOMPtr mInStream; + nsCOMPtr mOutStream; + nsCOMPtr mListener; }; diff --git a/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.cpp b/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.cpp index 2c000d2e796..c2829c4ee0c 100644 --- a/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.cpp +++ b/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.cpp @@ -18,29 +18,31 @@ * * Contributor(s): * Bradley Baetz + * Darin Fisher */ // gopher implementation - based on datetime and finger implimentations // and documentation #include "nsGopherChannel.h" +#include "nsMimeTypes.h" +#include "nsEscape.h" +#include "nsNetUtil.h" +#include "netCore.h" +#include "nsCRT.h" +#include "prlog.h" + #include "nsIServiceManager.h" #include "nsILoadGroup.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsXPIDLString.h" -#include "nsReadableUtils.h" #include "nsISocketTransportService.h" #include "nsIStringStream.h" -#include "nsMimeTypes.h" #include "nsIStreamConverterService.h" -#include "nsEscape.h" #include "nsITXTToHTMLConv.h" -#include "nsIProgressEventSink.h" -#include "nsNetUtil.h" -#include "prlog.h" +#include "nsIEventQueue.h" +#include "nsEventQueueUtils.h" #include "nsIPref.h" -#include "nsCRT.h" static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); @@ -55,10 +57,10 @@ extern PRLogModuleInfo* gGopherLog; // nsGopherChannel methods nsGopherChannel::nsGopherChannel() : mContentLength(-1), - mActAsObserver(PR_TRUE), mListFormat(FORMAT_HTML), mType(-1), - mStatus(NS_OK) + mStatus(NS_OK), + mIsPending(PR_FALSE) { } @@ -71,12 +73,13 @@ nsGopherChannel::~nsGopherChannel() #endif } -NS_IMPL_THREADSAFE_ISUPPORTS5(nsGopherChannel, +NS_IMPL_THREADSAFE_ISUPPORTS6(nsGopherChannel, nsIChannel, nsIRequest, nsIStreamListener, nsIRequestObserver, - nsIDirectoryListing); + nsIDirectoryListing, + nsITransportEventSink); nsresult nsGopherChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo) @@ -142,18 +145,6 @@ nsGopherChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo) } -NS_METHOD -nsGopherChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) -{ - nsGopherChannel* gc = new nsGopherChannel(); - if (!gc) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(gc); - nsresult rv = gc->QueryInterface(aIID, aResult); - NS_RELEASE(gc); - return rv; -} - //////////////////////////////////////////////////////////////////////////////// // nsIRequest methods: @@ -166,14 +157,17 @@ nsGopherChannel::GetName(nsACString &result) NS_IMETHODIMP nsGopherChannel::IsPending(PRBool *result) { - NS_NOTREACHED("nsGopherChannel::IsPending"); - return NS_ERROR_NOT_IMPLEMENTED; + *result = mIsPending; + return NS_OK; } NS_IMETHODIMP nsGopherChannel::GetStatus(nsresult *status) { - *status = mStatus; + if (mPump && NS_SUCCEEDED(mStatus)) + mPump->GetStatus(status); + else + *status = mStatus; return NS_OK; } @@ -188,25 +182,28 @@ nsGopherChannel::Cancel(nsresult status) NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); mStatus = status; - if (mTransportRequest) { - return mTransportRequest->Cancel(status); - } + if (mPump) + return mPump->Cancel(status); - return NS_ERROR_FAILURE; + return NS_OK; } NS_IMETHODIMP -nsGopherChannel::Suspend(void) +nsGopherChannel::Suspend() { - NS_NOTREACHED("nsGopherChannel::Suspend"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mPump) + return mPump->Suspend(); + + return NS_OK; } NS_IMETHODIMP -nsGopherChannel::Resume(void) +nsGopherChannel::Resume() { - NS_NOTREACHED("nsGopherChannel::Resume"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mPump) + return mPump->Resume(); + + return NS_OK; } //////////////////////////////////////////////////////////////////////////////// @@ -238,34 +235,8 @@ nsGopherChannel::GetURI(nsIURI* *aURI) NS_IMETHODIMP nsGopherChannel::Open(nsIInputStream **_retval) { - nsresult rv = NS_OK; - - PRInt32 port; - rv = mUrl->GetPort(&port); - if (NS_FAILED(rv)) - return rv; - - rv = NS_CheckPortSafety(port, "gopher"); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr socketService = - do_GetService(kSocketTransportServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = socketService->CreateTransport(mHost, - mPort, - mProxyInfo, - BUFFER_SEG_SIZE, - BUFFER_MAX_SIZE, - getter_AddRefs(mTransport)); - - if (NS_FAILED(rv)) return rv; - - mTransport->SetNotificationCallbacks(mCallbacks, - (mLoadFlags & LOAD_BACKGROUND)); - - return mTransport->OpenInputStream(0, (PRUint32)-1, 0, _retval); + NS_NOTREACHED("nsGopherChannel::Open"); + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP @@ -284,26 +255,58 @@ nsGopherChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) rv = NS_CheckPortSafety(port, "gopher"); if (NS_FAILED(rv)) return rv; - - mListener = aListener; - mResponseContext = ctxt; + // push stream converters in front of the consumer... + nsCOMPtr converter; + rv = PushStreamConverters(aListener, getter_AddRefs(converter)); + if (NS_FAILED(rv)) return rv; + + // create socket transport nsCOMPtr socketService = do_GetService(kSocketTransportServiceCID, &rv); if (NS_FAILED(rv)) return rv; - rv = socketService->CreateTransport(mHost, + rv = socketService->CreateTransport(nsnull, 0, + mHost, mPort, mProxyInfo, - BUFFER_SEG_SIZE, - BUFFER_MAX_SIZE, getter_AddRefs(mTransport)); if (NS_FAILED(rv)) return rv; - mTransport->SetNotificationCallbacks(mCallbacks, - (mLoadFlags & LOAD_BACKGROUND)); - - return SendRequest(mTransport); + // setup notification callbacks... + if (!(mLoadFlags & LOAD_BACKGROUND)) { + nsCOMPtr eventQ; + NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (eventQ) + mTransport->SetEventSink(this, eventQ); + } + mTransport->SetSecurityCallbacks(mCallbacks); + + // open buffered, asynchronous socket input stream, and use a input stream + // pump to read from it. + nsCOMPtr input; + rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(input)); + if (NS_FAILED(rv)) return rv; + + rv = SendRequest(); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input); + if (NS_FAILED(rv)) return rv; + + rv = mPump->AsyncRead(this, nsnull); + if (NS_FAILED(rv)) return rv; + + if (mLoadGroup) + mLoadGroup->AddRequest(this, nsnull); + + mIsPending = PR_TRUE; + if (converter) + mListener = converter; + else + mListener = aListener; + mListenerContext = ctxt; + return NS_OK; } NS_IMETHODIMP @@ -476,8 +479,12 @@ nsGopherChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCa { mCallbacks = aNotificationCallbacks; if (mCallbacks) { - mCallbacks->GetInterface(NS_GET_IID(nsIPrompt), - getter_AddRefs(mPrompter)); + mPrompter = do_GetInterface(mCallbacks); + mProgressSink = do_GetInterface(mCallbacks); + } + else { + mPrompter = 0; + mProgressSink = 0; } return NS_OK; } @@ -485,8 +492,10 @@ nsGopherChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCa NS_IMETHODIMP nsGopherChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) { - *aSecurityInfo = nsnull; - return NS_OK; + if (mTransport) + return mTransport->GetSecurityInfo(aSecurityInfo); + + return NS_ERROR_NOT_AVAILABLE; } // nsIRequestObserver methods @@ -498,14 +507,7 @@ nsGopherChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) ("nsGopherChannel::OnStartRequest called [this=%x, aRequest=%x]\n", this, aRequest)); - if (!mActAsObserver) { - // acting as a listener - return mListener->OnStartRequest(this, aContext); - } else { - // we don't want to pass our AsyncWrite's OnStart through - // we just ignore this - return NS_OK; - } + return mListener->OnStartRequest(this, mListenerContext); } NS_IMETHODIMP @@ -517,112 +519,42 @@ nsGopherChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, ("nsGopherChannel::OnStopRequest called [this=%x, aRequest=%x, aStatus=%x]\n", this,aRequest,aStatus)); - nsresult rv = NS_OK; + if (NS_SUCCEEDED(mStatus)) + mStatus = aStatus; - if (NS_FAILED(aStatus) || !mActAsObserver) { - if (mListener) { - rv = mListener->OnStopRequest(this, mResponseContext, aStatus); - if (NS_FAILED(rv)) return rv; - } - - if (mLoadGroup) { - rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus); - } - - mTransport = 0; - return rv; - } else { - // at this point we know the request has been sent. - // we're no longer acting as an observer. - mActAsObserver = PR_FALSE; - - nsCOMPtr converterListener; - - nsCOMPtr StreamConvService = - do_GetService(kStreamConverterServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - // What we now do depends on what type of file we have - if (mType=='1' || mType=='7') { - // Send the directory format back for a directory - switch (mListFormat) { - case nsIDirectoryListing::FORMAT_RAW: - converterListener = this; - break; - default: - // fall through - case nsIDirectoryListing::FORMAT_HTML: - // XXX - work arround bug 126417. We have to do the chaining - // manually so that we don't crash - { - nsCOMPtr tmpListener; - rv = StreamConvService->AsyncConvertData( - NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), - NS_LITERAL_STRING(TEXT_HTML).get(), - this, - mUrl, - getter_AddRefs(tmpListener)); - if (NS_FAILED(rv)) break; - rv = StreamConvService->AsyncConvertData(NS_LITERAL_STRING("text/gopher-dir").get(), - NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), - tmpListener, - mUrl, - getter_AddRefs(converterListener)); - } - break; - case nsIDirectoryListing::FORMAT_HTTP_INDEX: - rv = StreamConvService->AsyncConvertData(NS_LITERAL_STRING("text/gopher-dir").get(), - NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), - this, - mUrl, - getter_AddRefs(converterListener)); - break; - } - if (NS_FAILED(rv)) return rv; - } else if (mType=='0') { - // Convert general file - rv = StreamConvService->AsyncConvertData(NS_LITERAL_STRING("text/plain").get(), - NS_LITERAL_STRING("text/html").get(), - this, - mResponseContext, - getter_AddRefs(converterListener)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr converter(do_QueryInterface(converterListener)); - if (converter) { - nsCAutoString spec; - rv = mUrl->GetSpec(spec); - converter->SetTitle(NS_ConvertUTF8toUCS2(spec).get()); - converter->PreFormatHTML(PR_TRUE); - } - } else - // other file type - no conversions - converterListener = this; - - return mTransport->AsyncRead(converterListener, mResponseContext, 0, - (PRUint32)-1, 0, getter_AddRefs(mTransportRequest)); + if (mListener) { + mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener = 0; + mListenerContext = 0; } + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, mStatus); + + mTransport->Close(mStatus); + mTransport = 0; + mPump = 0; + return NS_OK; } + // nsIStreamListener method NS_IMETHODIMP -nsGopherChannel::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, - nsIInputStream *aInputStream, - PRUint32 aSourceOffset, PRUint32 aLength) +nsGopherChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, + PRUint32 offset, PRUint32 count) { PR_LOG(gGopherLog, PR_LOG_DEBUG, - ("OnDataAvailable called - [this=%x, aLength=%d]\n",this,aLength)); - mContentLength = aLength; - return mListener->OnDataAvailable(this, aContext, aInputStream, - aSourceOffset, aLength); + ("OnDataAvailable called - [this=%x, aLength=%d]\n",this,count)); + + return mListener->OnDataAvailable(this, mListenerContext, stream, + offset, count); } nsresult -nsGopherChannel::SendRequest(nsITransport* aTransport) +nsGopherChannel::SendRequest() { nsresult rv = NS_OK; - nsCOMPtr result; - nsCOMPtr charstream; // Note - you have to keep this as a class member, because the char input // stream doesn't copy its buffer @@ -696,11 +628,6 @@ nsGopherChannel::SendRequest(nsITransport* aTransport) if (!res || !(*search.get())) return NS_ERROR_FAILURE; - if (mLoadGroup) { - rv = mLoadGroup->AddRequest(this, nsnull); - if (NS_FAILED(rv)) return rv; - } - mRequest.Append('\t'); mRequest.AppendWithConversion(search.get()); @@ -723,24 +650,98 @@ nsGopherChannel::SendRequest(nsITransport* aTransport) mRequest.Append(CRLF); - rv = NS_NewCharInputStream(getter_AddRefs(result), mRequest.get()); - if (NS_FAILED(rv)) return rv; - - charstream = do_QueryInterface(result, &rv); - if (NS_FAILED(rv)) return rv; - PR_LOG(gGopherLog,PR_LOG_DEBUG, ("Sending: %s\n", mRequest.get())); - rv = NS_AsyncWriteFromStream(getter_AddRefs(mTransportRequest), - aTransport, charstream, - 0, mRequest.Length(), 0, - this, nsnull); - return rv; + // open a buffered, blocking output stream. (it should never block because + // the buffer is big enough for our entire request.) + nsCOMPtr output; + rv = mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, + mRequest.Length(), 1, + getter_AddRefs(output)); + if (NS_FAILED(rv)) return rv; + + PRUint32 n; + rv = output->Write(mRequest.get(), mRequest.Length(), &n); + if (NS_FAILED(rv)) return rv; + + if (n != mRequest.Length()) + return NS_ERROR_UNEXPECTED; + + return NS_OK; +} + +nsresult +nsGopherChannel::PushStreamConverters(nsIStreamListener *listener, nsIStreamListener **result) +{ + nsresult rv; + nsCOMPtr converterListener; + + nsCOMPtr StreamConvService = + do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + // What we now do depends on what type of file we have + if (mType=='1' || mType=='7') { + // Send the directory format back for a directory + switch (mListFormat) { + case nsIDirectoryListing::FORMAT_RAW: + break; + default: + // fall through + case nsIDirectoryListing::FORMAT_HTML: + // XXX - work arround bug 126417. We have to do the chaining + // manually so that we don't crash + { + nsCOMPtr tmpListener; + rv = StreamConvService->AsyncConvertData( + NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), + NS_LITERAL_STRING(TEXT_HTML).get(), + listener, + mUrl, + getter_AddRefs(tmpListener)); + if (NS_FAILED(rv)) break; + rv = StreamConvService->AsyncConvertData(NS_LITERAL_STRING("text/gopher-dir").get(), + NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), + tmpListener, + mUrl, + getter_AddRefs(converterListener)); + } + break; + case nsIDirectoryListing::FORMAT_HTTP_INDEX: + rv = StreamConvService->AsyncConvertData(NS_LITERAL_STRING("text/gopher-dir").get(), + NS_LITERAL_STRING(APPLICATION_HTTP_INDEX_FORMAT).get(), + listener, + mUrl, + getter_AddRefs(converterListener)); + break; + } + if (NS_FAILED(rv)) return rv; + } else if (mType=='0') { + // Convert general file + rv = StreamConvService->AsyncConvertData(NS_LITERAL_STRING("text/plain").get(), + NS_LITERAL_STRING("text/html").get(), + listener, + mListenerContext, + getter_AddRefs(converterListener)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr converter(do_QueryInterface(converterListener)); + if (converter) { + nsCAutoString spec; + rv = mUrl->GetSpec(spec); + converter->SetTitle(NS_ConvertUTF8toUCS2(spec).get()); + converter->PreFormatHTML(PR_TRUE); + } + } + + NS_IF_ADDREF(*result = converterListener); + return NS_OK; } NS_IMETHODIMP -nsGopherChannel::SetListFormat(PRUint32 format) { +nsGopherChannel::SetListFormat(PRUint32 format) +{ if (format != FORMAT_PREF && format != FORMAT_RAW && format != FORMAT_HTML && @@ -771,8 +772,25 @@ nsGopherChannel::SetListFormat(PRUint32 format) { } NS_IMETHODIMP -nsGopherChannel::GetListFormat(PRUint32 *format) { +nsGopherChannel::GetListFormat(PRUint32 *format) +{ *format = mListFormat; return NS_OK; } +NS_IMETHODIMP +nsGopherChannel::OnTransportStatus(nsITransport *trans, nsresult status, + PRUint32 progress, PRUint32 progressMax) +{ + // suppress status notification if channel is no longer pending! + if (mProgressSink && mPump && !(mLoadFlags & LOAD_BACKGROUND)) { + NS_ConvertUTF8toUCS2 host(mHost); + mProgressSink->OnStatus(this, nsnull, status, host.get()); + + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + status == nsISocketTransport::STATUS_SENDING_TO) { + mProgressSink->OnProgress(this, nsnull, progress, progressMax); + } + } + return NS_OK; +} diff --git a/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.h b/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.h index c8db3e4fde0..8659c3fd166 100644 --- a/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.h +++ b/mozilla/netwerk/protocol/gopher/src/nsGopherChannel.h @@ -18,33 +18,38 @@ * * Contributor(s): * Bradley Baetz + * Darin Fisher */ -#ifndef nsGopherChannel_h___ -#define nsGopherChannel_h___ +#ifndef nsGopherChannel_h__ +#define nsGopherChannel_h__ +#include "nsGopherHandler.h" +#include "nsXPIDLString.h" #include "nsString.h" +#include "nsCOMPtr.h" + #include "nsILoadGroup.h" #include "nsIInputStream.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsCOMPtr.h" -#include "nsXPIDLString.h" #include "nsIChannel.h" #include "nsIURI.h" #include "nsIURL.h" -#include "nsGopherHandler.h" #include "nsIPrompt.h" #include "nsIProxy.h" #include "nsIStreamListener.h" -#include "nsITransport.h" +#include "nsISocketTransport.h" +#include "nsIProgressEventSink.h" #include "nsIProxyInfo.h" #include "nsIDirectoryListing.h" #include "nsIStringBundle.h" +#include "nsIInputStreamPump.h" class nsGopherChannel : public nsIChannel, public nsIStreamListener, - public nsIDirectoryListing { + public nsIDirectoryListing, + public nsITransportEventSink { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST @@ -52,21 +57,19 @@ public: NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSIDIRECTORYLISTING + NS_DECL_NSITRANSPORTEVENTSINK // nsGopherChannel methods: nsGopherChannel(); virtual ~nsGopherChannel(); - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); - nsresult Init(nsIURI* uri, nsIProxyInfo* proxyInfo); protected: nsCOMPtr mOriginalURI; nsCOMPtr mCallbacks; nsCOMPtr mPrompter; + nsCOMPtr mProgressSink; nsCOMPtr mUrl; nsCOMPtr mListener; PRUint32 mLoadFlags; @@ -75,9 +78,6 @@ protected: nsCString mContentCharset; PRInt32 mContentLength; nsCOMPtr mOwner; - PRUint32 mBufferSegmentSize; - PRUint32 mBufferMaxSize; - PRBool mActAsObserver; PRUint32 mListFormat; nsXPIDLCString mHost; @@ -86,15 +86,17 @@ protected: nsCString mSelector; nsCString mRequest; - nsCOMPtr mResponseContext; - nsCOMPtr mTransport; - nsCOMPtr mTransportRequest; + nsCOMPtr mListenerContext; + nsCOMPtr mTransport; + nsCOMPtr mPump; nsCOMPtr mProxyInfo; - nsresult mStatus; nsCOMPtr mStringBundle; - nsresult SendRequest(nsITransport* aTransport); + nsresult mStatus; + PRBool mIsPending; + nsresult SendRequest(); + nsresult PushStreamConverters(nsIStreamListener *, nsIStreamListener **); }; -#endif /* nsGopherChannel_h___ */ +#endif // !nsGopherChannel_h__ diff --git a/mozilla/netwerk/protocol/gopher/src/nsGopherHandler.cpp b/mozilla/netwerk/protocol/gopher/src/nsGopherHandler.cpp index 6c596aa896e..7d889045968 100644 --- a/mozilla/netwerk/protocol/gopher/src/nsGopherHandler.cpp +++ b/mozilla/netwerk/protocol/gopher/src/nsGopherHandler.cpp @@ -117,18 +117,18 @@ NS_IMETHODIMP nsGopherHandler::NewProxiedChannel(nsIURI* url, nsIProxyInfo* proxyInfo, nsIChannel* *result) { - nsresult rv; - nsGopherChannel* channel; - rv = nsGopherChannel::Create(nsnull, NS_GET_IID(nsIChannel), - (void**)&channel); - if (NS_FAILED(rv)) return rv; + nsGopherChannel *chan = new nsGopherChannel(); + if (!chan) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(chan); - rv = channel->Init(url, proxyInfo); + nsresult rv = chan->Init(url, proxyInfo); if (NS_FAILED(rv)) { + NS_RELEASE(chan); return rv; } - *result = channel; + *result = chan; return rv; } diff --git a/mozilla/netwerk/protocol/http/src/Makefile.in b/mozilla/netwerk/protocol/http/src/Makefile.in index 1ee824408da..c0ab08d61aa 100644 --- a/mozilla/netwerk/protocol/http/src/Makefile.in +++ b/mozilla/netwerk/protocol/http/src/Makefile.in @@ -43,20 +43,23 @@ REQUIRES = xpcom \ CPPSRCS = \ nsHttp.cpp \ - nsHttpHandler.cpp \ nsHttpHeaderArray.cpp \ + nsHttpConnectionInfo.cpp \ nsHttpConnection.cpp \ - nsHttpTransaction.cpp \ - nsHttpChannel.cpp \ + nsHttpConnectionMgr.cpp \ nsHttpRequestHead.cpp \ nsHttpResponseHead.cpp \ nsHttpChunkedDecoder.cpp \ nsHttpAuthCache.cpp \ nsHttpBasicAuth.cpp \ nsHttpDigestAuth.cpp \ + nsHttpTransaction.cpp \ + nsHttpHandler.cpp \ + nsHttpChannel.cpp \ nsHttpPipeline.cpp \ $(NULL) + LOCAL_INCLUDES=-I$(srcdir)/../../../base/src # we don't want the shared lib, but we want to force the creation of a diff --git a/mozilla/netwerk/protocol/http/src/nsAHttpConnection.h b/mozilla/netwerk/protocol/http/src/nsAHttpConnection.h index aca59f7e3e6..4c6b26dac80 100644 --- a/mozilla/netwerk/protocol/http/src/nsAHttpConnection.h +++ b/mozilla/netwerk/protocol/http/src/nsAHttpConnection.h @@ -1,3 +1,40 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * 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. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 + * 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 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 MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + #ifndef nsAHttpConnection_h__ #define nsAHttpConnection_h__ @@ -8,35 +45,59 @@ class nsHttpRequestHead; class nsHttpResponseHead; class nsHttpConnectionInfo; -//---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Abstract base class for a HTTP connection -//---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- class nsAHttpConnection : public nsISupports { public: + //------------------------------------------------------------------------- + // NOTE: these methods may only be called on the socket thread. + //------------------------------------------------------------------------- + + // // called by a transaction when the response headers have all been read. // the connection can force the transaction to reset it's response headers, // and prepare for a new set of response headers, by setting |*reset=TRUE|. + // + // @return failure code to close the transaction. + // virtual nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpRequestHead *, nsHttpResponseHead *, PRBool *reset) = 0; - // called by a transaction when it completes normally. - virtual nsresult OnTransactionComplete(nsAHttpTransaction *, - nsresult status) = 0; + // + // called by a transaction to resume either sending or receiving data + // after a transaction returned NS_BASE_STREAM_WOULD_BLOCK from its + // ReadSegments/WriteSegments methods. + // + virtual nsresult ResumeSend() = 0; + virtual nsresult ResumeRecv() = 0; - // called by a transaction to suspend/resume the connection. - virtual nsresult OnSuspend() = 0; - virtual nsresult OnResume() = 0; - - // get a reference to the connection's connection-info object. + // + // called by the connection manager to close a transaction being processed + // by this connection. + // + // @param transaction + // the transaction being closed. + // @param reason + // the reason for closing the transaction. NS_BASE_STREAM_CLOSED + // is equivalent to NS_OK. + // + virtual void CloseTransaction(nsAHttpTransaction *transaction, + nsresult reason) = 0; + + // get a reference to the connection's connection info object. virtual void GetConnectionInfo(nsHttpConnectionInfo **) = 0; + // called by a transaction to get the security info from the socket. + virtual void GetSecurityInfo(nsISupports **) = 0; + // called by a transaction to remove itself from the connection (eg. when // it reads premature EOF and must restart itself). - virtual void DropTransaction(nsAHttpTransaction *) = 0; + //virtual void DropTransaction(nsAHttpTransaction *) = 0; // called by a transaction to determine whether or not the connection is // persistent... important in determining the end of a response. diff --git a/mozilla/netwerk/protocol/http/src/nsAHttpTransaction.h b/mozilla/netwerk/protocol/http/src/nsAHttpTransaction.h index 07ca4d4f8c8..bfd8391d5ee 100644 --- a/mozilla/netwerk/protocol/http/src/nsAHttpTransaction.h +++ b/mozilla/netwerk/protocol/http/src/nsAHttpTransaction.h @@ -1,15 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * 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. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 + * 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 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 MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + #ifndef nsAHttpTransaction_h__ #define nsAHttpTransaction_h__ #include "nsISupports.h" class nsAHttpConnection; -class nsIInputStream; -class nsIOutputStream; +class nsAHttpSegmentReader; +class nsAHttpSegmentWriter; class nsIInterfaceRequestor; //---------------------------------------------------------------------------- -// Abstract base class for a HTTP transaction +// Abstract base class for a HTTP transaction: +// +// A transaction is a "sink" for the response data. The connection pushes +// data to the transaction by writing to it. The transaction supports +// WriteSegments and may refuse to accept data if its buffers are full (its +// write function returns NS_BASE_STREAM_WOULD_BLOCK in this case). //---------------------------------------------------------------------------- class nsAHttpTransaction : public nsISupports @@ -18,37 +60,56 @@ public: // called by the connection when it takes ownership of the transaction. virtual void SetConnection(nsAHttpConnection *) = 0; - // called by the connection to pass socket security-info to the transaction. - virtual void SetSecurityInfo(nsISupports *) = 0; - - // called by the connection to get notification callbacks to set on the + // called by the connection to get security callbacks to set on the // socket transport. - virtual void GetNotificationCallbacks(nsIInterfaceRequestor **) = 0; + virtual void GetSecurityCallbacks(nsIInterfaceRequestor **) = 0; - // called by the pipelining code to determine how much memory to allocate - // for this transaction's request headers. - virtual PRUint32 GetRequestSize() = 0; + // called to report socket status (see nsITransportEventSink) + virtual void OnTransportStatus(nsresult status, PRUint32 progress) = 0; - // called by the connection to indicate that the socket can be written to. - // the transaction returns NS_BASE_STREAM_CLOSED when it is finished - // writing its request(s). - virtual nsresult OnDataWritable(nsIOutputStream *) = 0; - - // called by the connection to indicate that the socket can be read from. - // the transaction can return NS_BASE_STREAM_WOULD_BLOCK to suspend the - // socket read request. - virtual nsresult OnDataReadable(nsIInputStream *) = 0; - - // called by the connection when the transaction should stop, either due - // to normal completion, cancelation, or some socket transport error. - virtual nsresult OnStopTransaction(nsresult status) = 0; - - // called by the connection to report socket status. - virtual void OnStatus(nsresult status, const PRUnichar *statusText) = 0; - - // called by the connection to check the transaction status. + // called to check the transaction status. virtual PRBool IsDone() = 0; virtual nsresult Status() = 0; + + // called to find out how much request data is available for writing. + virtual PRUint32 Available() = 0; + + // called to read request data from the transaction. + virtual nsresult ReadSegments(nsAHttpSegmentReader *reader, + PRUint32 count, PRUint32 *countRead) = 0; + + // called to write response data to the transaction. + virtual nsresult WriteSegments(nsAHttpSegmentWriter *writer, + PRUint32 count, PRUint32 *countWritten) = 0; + + // called to close the transaction + virtual void Close(nsresult reason) = 0; +}; + +//----------------------------------------------------------------------------- +// nsAHttpSegmentReader +//----------------------------------------------------------------------------- + +class nsAHttpSegmentReader +{ +public: + // any returned failure code stops segment iteration + virtual nsresult OnReadSegment(const char *segment, + PRUint32 count, + PRUint32 *countRead) = 0; +}; + +//----------------------------------------------------------------------------- +// nsAHttpSegmentWriter +//----------------------------------------------------------------------------- + +class nsAHttpSegmentWriter +{ +public: + // any returned failure code stops segment iteration + virtual nsresult OnWriteSegment(char *segment, + PRUint32 count, + PRUint32 *countWritten) = 0; }; #endif // nsAHttpTransaction_h__ diff --git a/mozilla/netwerk/protocol/http/src/nsHttp.h b/mozilla/netwerk/protocol/http/src/nsHttp.h index 0001494c96a..e1d041e1686 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttp.h +++ b/mozilla/netwerk/protocol/http/src/nsHttp.h @@ -64,8 +64,9 @@ extern PRLogModuleInfo *gHttpLog; #define LOG_ENABLED() LOG4_ENABLED() // http default buffer geometry -#define NS_HTTP_SEGMENT_SIZE 4096 -#define NS_HTTP_BUFFER_SIZE 4096*4 // 16k maximum +#define NS_HTTP_SEGMENT_SIZE 4096 +#define NS_HTTP_SEGMENT_COUNT 16 // 64k maximum +#define NS_HTTP_MAX_ODA_SIZE (NS_HTTP_SEGMENT_SIZE * 4) // 16k // http version codes #define NS_HTTP_VERSION_UNKNOWN 0 @@ -76,12 +77,12 @@ extern PRLogModuleInfo *gHttpLog; typedef PRUint8 nsHttpVersion; // http connection capabilities -#define NS_HTTP_ALLOW_KEEPALIVE (1<<0) -#define NS_HTTP_ALLOW_PIPELINING (1<<1) +#define NS_HTTP_ALLOW_KEEPALIVE (1<<0) +#define NS_HTTP_ALLOW_PIPELINING (1<<1) #define NS_HTTP_DONT_REPORT_PROGRESS (1<<2) // hard upper limit on the number of requests that can be pipelined -#define NS_HTTP_MAX_PIPELINED_REQUESTS 10 +#define NS_HTTP_MAX_PIPELINED_REQUESTS 8 //----------------------------------------------------------------------------- // http atoms... diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp index fc478a282e0..b40d1e9967e 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -38,6 +38,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIIDNService.h" #include "nsIStreamListenerTee.h" +#include "nsISeekableStream.h" #include "nsCPasswordManager.h" #include "nsMimeTypes.h" #include "nsNetUtil.h" @@ -67,7 +68,7 @@ nsHttpChannel::nsHttpChannel() , mCacheAccess(0) , mPostID(0) , mRequestTime(0) - , mRedirectionLimit(nsHttpHandler::get()->RedirectionLimit()) + , mRedirectionLimit(gHttpHandler->RedirectionLimit()) , mIsPending(PR_FALSE) , mApplyConversion(PR_TRUE) , mAllowPipelining(PR_TRUE) @@ -80,7 +81,7 @@ nsHttpChannel::nsHttpChannel() LOG(("Creating nsHttpChannel @%x\n", this)); // grab a reference to the handler to ensure that it doesn't go away. - nsHttpHandler *handler = nsHttpHandler::get(); + nsHttpHandler *handler = gHttpHandler; NS_ADDREF(handler); } @@ -102,7 +103,7 @@ nsHttpChannel::~nsHttpChannel() NS_IF_RELEASE(mPrevTransaction); // release our reference to the handler - nsHttpHandler *handler = nsHttpHandler::get(); + nsHttpHandler *handler = gHttpHandler; NS_RELEASE(handler); } @@ -182,7 +183,7 @@ nsHttpChannel::Init(nsIURI *uri, rv = mRequestHead.SetHeader(nsHttp::Host, hostLine); if (NS_FAILED(rv)) return rv; - rv = nsHttpHandler::get()-> + rv = gHttpHandler-> AddStandardRequestHeaders(&mRequestHead.Headers(), caps, !mConnectionInfo->UsingSSL() && mConnectionInfo->UsingHttpProxy()); @@ -204,7 +205,7 @@ nsHttpChannel::AsyncCall(nsAsyncCallback funcPtr) nsCOMPtr eqs; nsCOMPtr eventQ; - nsHttpHandler::get()->GetEventQueueService(getter_AddRefs(eqs)); + gHttpHandler->GetEventQueueService(getter_AddRefs(eqs)); if (eqs) eqs->ResolveEventQueue(NS_CURRENT_EVENTQ, getter_AddRefs(eventQ)); if (!eventQ) @@ -267,7 +268,7 @@ nsHttpChannel::Connect(PRBool firstTime) // are we offline? nsCOMPtr ioService; - rv = nsHttpHandler::get()->GetIOService(getter_AddRefs(ioService)); + rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); if (NS_FAILED(rv)) return rv; ioService->GetOffline(&offline); @@ -315,7 +316,10 @@ nsHttpChannel::Connect(PRBool firstTime) rv = SetupTransaction(); if (NS_FAILED(rv)) return rv; - return nsHttpHandler::get()->InitiateTransaction(mTransaction, mConnectionInfo); + rv = gHttpHandler->InitiateTransaction(mTransaction); + if (NS_FAILED(rv)) return rv; + + return mTransactionPump->AsyncRead(this, nsnull); } // called when Connect fails @@ -329,7 +333,7 @@ nsHttpChannel::AsyncAbort(nsresult status) // create an async proxy for the listener.. nsCOMPtr mgr; - nsHttpHandler::get()->GetProxyObjectManager(getter_AddRefs(mgr)); + gHttpHandler->GetProxyObjectManager(getter_AddRefs(mgr)); if (mgr) { nsCOMPtr observer; mgr->GetProxyForObject(NS_CURRENT_EVENTQ, @@ -414,12 +418,7 @@ nsHttpChannel::SetupTransaction() { NS_ENSURE_TRUE(!mTransaction, NS_ERROR_ALREADY_INITIALIZED); - nsCOMPtr listenerProxy; - nsresult rv = NS_NewStreamListenerProxy(getter_AddRefs(listenerProxy), - this, nsnull, - NS_HTTP_SEGMENT_SIZE, - NS_HTTP_BUFFER_SIZE); - if (NS_FAILED(rv)) return rv; + nsresult rv; // figure out if we should disallow pipelining. disallow if // the method is not GET or HEAD. we also disallow pipelining @@ -427,7 +426,7 @@ nsHttpChannel::SetupTransaction() // XXX does the toplevel document check really belong here? // XXX or, should we push it out entirely to necko consumers? PRUint8 caps = mCapabilities; - if (!mAllowPipelining || (mLoadFlags && LOAD_INITIAL_DOCUMENT_URI) || + if (!mAllowPipelining || (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) || !(mRequestHead.Method() == nsHttp::Get || mRequestHead.Method() == nsHttp::Head)) { LOG(("nsHttpChannel::SetupTransaction [this=%x] pipelining disallowed\n", this)); @@ -437,12 +436,6 @@ nsHttpChannel::SetupTransaction() if (mLoadFlags & nsIRequest::LOAD_BACKGROUND) caps |= NS_HTTP_DONT_REPORT_PROGRESS; - // create the transaction object - mTransaction = new nsHttpTransaction(listenerProxy, this, caps); - if (!mTransaction) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(mTransaction); - // use the URI path if not proxying (transparent proxying such as SSL proxy // does not count here). also, figure out what version we should be speaking. nsCAutoString buf, path; @@ -455,7 +448,7 @@ nsHttpChannel::SetupTransaction() requestURI = buf.get(); else requestURI = path.get(); - mRequestHead.SetVersion(nsHttpHandler::get()->HttpVersion()); + mRequestHead.SetVersion(gHttpHandler->HttpVersion()); } else { rv = mURI->GetUserPass(buf); @@ -473,7 +466,7 @@ nsHttpChannel::SetupTransaction() } else requestURI = mSpec.get(); - mRequestHead.SetVersion(nsHttpHandler::get()->ProxyHttpVersion()); + mRequestHead.SetVersion(gHttpHandler->ProxyHttpVersion()); } // trim off the #ref portion if any... @@ -508,10 +501,30 @@ nsHttpChannel::SetupTransaction() mRequestHead.SetHeader(nsHttp::Pragma, NS_LITERAL_CSTRING("no-cache"), PR_TRUE); } - return mTransaction->SetupRequest(&mRequestHead, mUploadStream, - mUploadStreamHasHeaders, - mConnectionInfo->UsingSSL() && - mConnectionInfo->UsingHttpProxy()); + if (!mEventQ) { + // grab a reference to the calling thread's event queue. + nsCOMPtr eqs; + gHttpHandler->GetEventQueueService(getter_AddRefs(eqs)); + if (eqs) + eqs->ResolveEventQueue(NS_CURRENT_EVENTQ, getter_AddRefs(mEventQ)); + } + + // create the transaction object + mTransaction = new nsHttpTransaction(); + if (!mTransaction) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mTransaction); + + nsCOMPtr responseStream; + rv = mTransaction->Init(caps, mConnectionInfo, &mRequestHead, + mUploadStream, mUploadStreamHasHeaders, + mEventQ, mCallbacks, this, + getter_AddRefs(responseStream)); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewInputStreamPump(getter_AddRefs(mTransactionPump), + responseStream); + return rv; } void @@ -528,9 +541,9 @@ nsHttpChannel::ApplyContentConversions() } const char *val = mResponseHead->PeekHeader(nsHttp::Content_Encoding); - if (nsHttpHandler::get()->IsAcceptableEncoding(val)) { + if (gHttpHandler->IsAcceptableEncoding(val)) { nsCOMPtr serv; - nsresult rv = nsHttpHandler::get()-> + nsresult rv = gHttpHandler-> GetStreamConverterService(getter_AddRefs(serv)); // we won't fail to load the page just because we couldn't load the // stream converter service.. carry on.. @@ -561,7 +574,7 @@ nsHttpChannel::CallOnStartRequest() // neither does applying the conversion from the URILoader nsCOMPtr serv; - nsresult rv = nsHttpHandler::get()-> + nsresult rv = gHttpHandler-> GetStreamConverterService(getter_AddRefs(serv)); // If we failed, we just fall through to the "normal" case if (NS_SUCCEEDED(rv)) { @@ -597,7 +610,7 @@ nsHttpChannel::ProcessResponse() this, httpStatus)); // notify nsIHttpNotify implementations - rv = nsHttpHandler::get()->OnExamineResponse(this); + rv = gHttpHandler->OnExamineResponse(this); NS_ASSERTION(NS_SUCCEEDED(rv), "OnExamineResponse failed"); // handle different server response categories @@ -758,8 +771,8 @@ nsHttpChannel::ProcessPartialContent() NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED); - // suspend the current transaction (may still get an OnDataAvailable) - rv = mTransaction->Suspend(); + // suspend the current transaction + rv = mTransactionPump->Suspend(); if (NS_FAILED(rv)) return rv; // merge any new headers with the cached response headers @@ -785,39 +798,6 @@ nsHttpChannel::ProcessPartialContent() return ReadFromCache(); } -nsresult -nsHttpChannel::BufferPartialContent(nsIInputStream *input, PRUint32 count) -{ - nsresult rv; - - LOG(("nsHttpChannel::BufferPartialContent [this=%x count=%u]\n", this, count)); - - if (!mBufferOut) { - LOG(("creating pipe...\n")); - // - // create a pipe for buffering network data (the size of this - // pipe must be equal to or greater than the size of the pipe - // used to proxy data from the socket transport thread). - // - rv = NS_NewPipe(getter_AddRefs(mBufferIn), - getter_AddRefs(mBufferOut), - NS_HTTP_SEGMENT_SIZE, - NS_HTTP_BUFFER_SIZE, - PR_TRUE, - PR_TRUE); - if (NS_FAILED(rv)) return rv; - } - - PRUint32 bytesWritten = 0; - rv = mBufferOut->WriteFrom(input, count, &bytesWritten); - if (NS_FAILED(rv) || (bytesWritten != count)) { - LOG(("writing to pipe failed [rv=%s bytes-written=%u]\n", rv, bytesWritten)); - return NS_ERROR_UNEXPECTED; - } - - return NS_OK; -} - nsresult nsHttpChannel::OnDoneReadingPartialCacheEntry(PRBool *streamDone) { @@ -836,20 +816,6 @@ nsHttpChannel::OnDoneReadingPartialCacheEntry(PRBool *streamDone) rv = InstallCacheListener(size); if (NS_FAILED(rv)) return rv; - // process any buffered data - if (mBufferIn) { - PRUint32 avail; - rv = mBufferIn->Available(&avail); - if (NS_FAILED(rv)) return rv; - - rv = mListener->OnDataAvailable(this, mListenerContext, mBufferIn, size, avail); - if (NS_FAILED(rv)) return rv; - - // done with the pipe - mBufferIn = 0; - mBufferOut = 0; - } - // need to track the logical offset of the data being sent to our listener mLogicalOffset = size; @@ -859,11 +825,13 @@ nsHttpChannel::OnDoneReadingPartialCacheEntry(PRBool *streamDone) // resume the transaction if it exists, otherwise the pipe contained the // remaining part of the document and we've now streamed all of the data. - if (mTransaction) { - rv = mTransaction->Resume(); + if (mTransactionPump) { + rv = mTransactionPump->Resume(); if (NS_SUCCEEDED(rv)) *streamDone = PR_FALSE; } + else + NS_NOTREACHED("no transaction"); return rv; } @@ -902,7 +870,9 @@ nsHttpChannel::ProcessNotModified() // drop our reference to the current transaction... ie. let it finish // in the background, since we can most likely reuse the connection. mPrevTransaction = mTransaction; + mPrevTransactionPump = mTransactionPump; mTransaction = nsnull; + mTransactionPump = 0; mCachedContentIsValid = PR_TRUE; return ReadFromCache(); @@ -927,7 +897,7 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed) // a post transaction via the cache. Otherwise, we need a unique // post id for this transaction. if (mPostID == 0) - mPostID = nsHttpHandler::get()->GenerateUniqueID(); + mPostID = gHttpHandler->GenerateUniqueID(); } else if ((mRequestHead.Method() != nsHttp::Get) && (mRequestHead.Method() != nsHttp::Head)) { @@ -951,7 +921,7 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed) else storagePolicy = nsICache::STORE_ANYWHERE; // allow on disk nsCOMPtr session; - rv = nsHttpHandler::get()->GetCacheSession(storagePolicy, + rv = gHttpHandler->GetCacheSession(storagePolicy, getter_AddRefs(session)); if (NS_FAILED(rv)) return rv; @@ -1092,7 +1062,7 @@ nsHttpChannel::CheckCache() // Determine if this is the first time that this cache entry // has been accessed during this session. PRBool fromPreviousSession = - (nsHttpHandler::get()->SessionStartTime() > lastModifiedTime); + (gHttpHandler->SessionStartTime() > lastModifiedTime); // Get the cached HTTP response headers rv = mCacheEntry->GetMetaDataElement("response-head", getter_Copies(buf)); @@ -1317,20 +1287,16 @@ nsHttpChannel::ReadFromCache() return AsyncCall(&nsHttpChannel::HandleAsyncNotModified); } - // Get a transport to the cached data... - rv = mCacheEntry->GetTransport(getter_AddRefs(mCacheTransport)); + // open input stream for reading... + nsCOMPtr stream; + rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream)); if (NS_FAILED(rv)) return rv; - // Hookup the notification callbacks interface to the new transport... - mCacheTransport->SetNotificationCallbacks(this, - ((mLoadFlags & nsIRequest::LOAD_BACKGROUND) - ? nsITransport::DONT_REPORT_PROGRESS - : 0)); + rv = NS_NewInputStreamPump(getter_AddRefs(mCachePump), + stream, -1, -1, 0, 0, PR_TRUE); + if (NS_FAILED(rv)) return rv; - // Pump the cache data downstream - return mCacheTransport->AsyncRead(this, mListenerContext, - 0, PRUint32(-1), 0, - getter_AddRefs(mCacheReadRequest)); + return mCachePump->AsyncRead(this, mListenerContext); } nsresult @@ -1342,7 +1308,7 @@ nsHttpChannel::CloseCacheEntry(nsresult status) // don't doom the cache entry if only reading from it... if (NS_FAILED(status) - && (mCacheAccess & nsICache::ACCESS_WRITE) && !mCacheReadRequest) { + && (mCacheAccess & nsICache::ACCESS_WRITE) && !mCachePump) { LOG(("dooming cache entry!!")); rv = mCacheEntry->Doom(); } @@ -1352,12 +1318,7 @@ nsHttpChannel::CloseCacheEntry(nsresult status) mCachedResponseHead = 0; } - // make sure the cache transport isn't holding a reference back to us - if (mCacheTransport) - mCacheTransport->SetNotificationCallbacks(nsnull, 0); - - mCacheReadRequest = 0; - mCacheTransport = 0; + mCachePump = 0; mCacheEntry = 0; mCacheAccess = 0; } @@ -1462,13 +1423,8 @@ nsHttpChannel::InstallCacheListener(PRUint32 offset) NS_ASSERTION(mCacheEntry, "no cache entry"); NS_ASSERTION(mListener, "no listener"); - if (!mCacheTransport) { - rv = mCacheEntry->GetTransport(getter_AddRefs(mCacheTransport)); - if (NS_FAILED(rv)) return rv; - } - nsCOMPtr out; - rv = mCacheTransport->OpenOutputStream(offset, PRUint32(-1), 0, getter_AddRefs(out)); + rv = mCacheEntry->OpenOutputStream(offset, getter_AddRefs(out)); if (NS_FAILED(rv)) return rv; // XXX disk cache does not support overlapped i/o yet @@ -1543,7 +1499,7 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType) rv = NS_NewProxyInfo("http", location, proxyPort, getter_AddRefs(pi)); // talk to the http handler directly for this case - rv = nsHttpHandler::get()-> + rv = gHttpHandler-> NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel)); if (NS_FAILED(rv)) return rv; } @@ -1551,7 +1507,7 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType) // create a new URI using the location header and the current URL // as a base... nsCOMPtr ioService; - rv = nsHttpHandler::get()->GetIOService(getter_AddRefs(ioService)); + rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); // the new uri should inherit the origin charset of the current uri nsCAutoString originCharset; @@ -1661,7 +1617,8 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType) // close down this transaction (null if processing a cached redirect) if (mTransaction) - mTransaction->Cancel(NS_BINDING_REDIRECTED); + gHttpHandler->CancelTransaction(mTransaction, NS_BINDING_REDIRECTED); + //mTransaction->Cancel(NS_BINDING_REDIRECTED); // disconnect from our listener mListener = 0; @@ -1705,9 +1662,12 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus) mRequestHead.SetHeader(nsHttp::Authorization, creds); // kill off the current transaction - mTransaction->Cancel(NS_BINDING_REDIRECTED); + gHttpHandler->CancelTransaction(mTransaction, NS_BINDING_REDIRECTED); + //mTransaction->Cancel(NS_BINDING_REDIRECTED); mPrevTransaction = mTransaction; + mPrevTransactionPump = mTransactionPump; mTransaction = nsnull; + mTransactionPump = 0; // toggle mIsPending to allow nsIHttpNotify implementations to modify // the request headers (bug 95044). @@ -1716,7 +1676,7 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus) // notify nsIHttpNotify implementations.. the server response could // have included cookies that must be sent with this authentication // attempt (bug 84794). - rv = nsHttpHandler::get()->OnModifyRequest(this); + rv = gHttpHandler->OnModifyRequest(this); NS_ASSERTION(NS_SUCCEEDED(rv), "OnModifyRequest failed"); mIsPending = PR_TRUE; @@ -1732,10 +1692,10 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus) seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); } - rv = nsHttpHandler::get()->InitiateTransaction(mTransaction, mConnectionInfo); + rv = gHttpHandler->InitiateTransaction(mTransaction); if (NS_FAILED(rv)) return rv; - return NS_OK; + return mTransactionPump->AsyncRead(this, nsnull); } nsresult @@ -1748,7 +1708,7 @@ nsHttpChannel::GetCredentials(const char *challenges, LOG(("nsHttpChannel::GetCredentials [this=%x proxyAuth=%d challenges=%s]\n", this, proxyAuth, challenges)); - nsHttpAuthCache *authCache = nsHttpHandler::get()->AuthCache(); + nsHttpAuthCache *authCache = gHttpHandler->AuthCache(); if (!authCache) return NS_ERROR_NOT_INITIALIZED; @@ -2121,7 +2081,7 @@ void nsHttpChannel::AddAuthorizationHeaders() { LOG(("nsHttpChannel::AddAuthorizationHeaders? [this=%x]\n", this)); - nsHttpAuthCache *authCache = nsHttpHandler::get()->AuthCache(); + nsHttpAuthCache *authCache = gHttpHandler->AuthCache(); if (authCache) { // check if proxy credentials should be sent const char *proxyHost = mConnectionInfo->ProxyHost(); @@ -2169,13 +2129,12 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel) NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) NS_INTERFACE_MAP_ENTRY(nsIStreamListener) NS_INTERFACE_MAP_ENTRY(nsIHttpChannel) - NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) - NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) NS_INTERFACE_MAP_ENTRY(nsICachingChannel) NS_INTERFACE_MAP_ENTRY(nsIUploadChannel) NS_INTERFACE_MAP_ENTRY(nsICacheListener) NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel) NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal) + NS_INTERFACE_MAP_ENTRY(nsITransportEventSink) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel) NS_INTERFACE_MAP_END @@ -2213,9 +2172,9 @@ nsHttpChannel::Cancel(nsresult status) mCanceled = PR_TRUE; mStatus = status; if (mTransaction) - mTransaction->Cancel(status); - else if (mCacheReadRequest) - mCacheReadRequest->Cancel(status); + gHttpHandler->CancelTransaction(mTransaction, status); + else if (mCachePump) + mCachePump->Cancel(status); return NS_OK; } @@ -2223,10 +2182,10 @@ NS_IMETHODIMP nsHttpChannel::Suspend() { LOG(("nsHttpChannel::Suspend [this=%x]\n", this)); - if (mTransaction) - mTransaction->Suspend(); - else if (mCacheReadRequest) - mCacheReadRequest->Suspend(); + if (mTransactionPump) + mTransactionPump->Suspend(); + else if (mCachePump) + mCachePump->Suspend(); return NS_OK; } @@ -2234,10 +2193,10 @@ NS_IMETHODIMP nsHttpChannel::Resume() { LOG(("nsHttpChannel::Resume [this=%x]\n", this)); - if (mTransaction) - mTransaction->Resume(); - else if (mCacheReadRequest) - mCacheReadRequest->Resume(); + if (mTransactionPump) + mTransactionPump->Resume(); + else if (mCachePump) + mCachePump->Resume(); return NS_OK; } @@ -2438,7 +2397,7 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context) return rv; nsCOMPtr ioService; - rv = nsHttpHandler::get()->GetIOService(getter_AddRefs(ioService)); + rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); if (NS_FAILED(rv)) return rv; rv = NS_CheckPortSafety(port, "http", ioService); // this works for https @@ -2446,7 +2405,7 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context) return rv; // Notify nsIHttpNotify implementations - rv = nsHttpHandler::get()->OnModifyRequest(this); + rv = gHttpHandler->OnModifyRequest(this); NS_ASSERTION(NS_SUCCEEDED(rv), "OnModifyRequest failed"); mIsPending = PR_TRUE; @@ -2533,7 +2492,7 @@ nsHttpChannel::SetReferrer(nsIURI *referrer) referrerLevel = 1; // user action else referrerLevel = 2; // inline content - if (nsHttpHandler::get()->ReferrerLevel() < referrerLevel) + if (gHttpHandler->ReferrerLevel() < referrerLevel) return NS_OK; nsCOMPtr referrerGrip; @@ -2610,7 +2569,7 @@ nsHttpChannel::SetReferrer(nsIURI *referrer) if (!match) return NS_OK; - if (!nsHttpHandler::get()->SendSecureXSiteReferrer()) { + if (!gHttpHandler->SendSecureXSiteReferrer()) { nsCAutoString referrerHost; nsCAutoString host; @@ -2804,7 +2763,7 @@ nsHttpChannel::SetResponseHeader(const nsACString &header, // XXX temporary hack until http supports some form of a header change observer if ((atom == nsHttp::Set_Cookie) && NS_SUCCEEDED(rv)) - rv = nsHttpHandler::get()->OnExamineResponse(this); + rv = gHttpHandler->OnExamineResponse(this); mResponseHeadersModified = PR_TRUE; return rv; @@ -2919,7 +2878,7 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt) this, request, mStatus)); // don't enter this block if we're reading from the cache... - if (NS_SUCCEEDED(mStatus) && !mCacheReadRequest && mTransaction) { + if (NS_SUCCEEDED(mStatus) && !mCachePump && mTransaction) { // grab the security info from the connection object; the transaction // is guaranteed to own a reference to the connection. mSecurityInfo = mTransaction->SecurityInfo(); @@ -2953,31 +2912,31 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st status = mStatus; // if the request is a previous transaction, then simply release it. - if (request == mPrevTransaction) { + if (request == mPrevTransactionPump) { NS_RELEASE(mPrevTransaction); mPrevTransaction = nsnull; + mPrevTransactionPump = 0; } if (mCachedContentIsPartial && NS_SUCCEEDED(status)) { - if (request == mTransaction) { - // byte-range transaction finished before we got around to streaming it. - NS_ASSERTION(mCacheReadRequest, "should be reading from cache right now"); - NS_RELEASE(mTransaction); - mTransaction = nsnull; - return NS_OK; - } - if (request == mCacheReadRequest) { + // mTransactionPump should be suspended + NS_ASSERTION(request != mTransactionPump, + "byte-range transaction finished prematurely"); + + if (request == mCachePump) { PRBool streamDone; status = OnDoneReadingPartialCacheEntry(&streamDone); if (NS_SUCCEEDED(status) && !streamDone) return status; // otherwise, fall through and fire OnStopRequest... } + else + NS_NOTREACHED("unexpected request"); } // if the request is for something we no longer reference, then simply // drop this event. - if ((request != mTransaction) && (request != mCacheReadRequest)) + if ((request != mTransactionPump) && (request != mCachePump)) return NS_OK; mIsPending = PR_FALSE; @@ -2988,19 +2947,11 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st if (mCacheEntry) { // find out if the transaction ran to completion... isPartial = !mTransaction->ResponseIsComplete(); -#if 0 - if (!isPartial) { - // even if the transaction ran to completion, we might not - // have written all of the data into the cache. - PRUint32 entrySize = 0; - if (NS_SUCCEEDED(mCacheEntry->GetDataSize(&entrySize))) - isPartial = (entrySize < mTransaction->GetContentRead()); - } -#endif } // at this point, we're done with the transaction NS_RELEASE(mTransaction); mTransaction = nsnull; + mTransactionPump = 0; } // perform any final cache operations before we close the cache entry. @@ -3024,7 +2975,7 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st if (mCanceled) { // we don't want to discard the cache entry if canceled and // reading from the cache. - if (request == mCacheReadRequest) + if (request == mCachePump) closeStatus = NS_OK; // we also don't want to discard the cache entry if the // server supports byte range requests, because we could always @@ -3059,14 +3010,12 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, if (mCanceled) return mStatus; - if (mCachedContentIsPartial && (request == mTransaction)) { - // XXX we can eliminate this buffer once bug 93055 is resolved. - return BufferPartialContent(input, count); - } + NS_ASSERTION(!(mCachedContentIsPartial && (request == mTransactionPump)), + "transaction pump not suspended"); // if the request is for something we no longer reference, then simply // drop this event. - if ((request != mTransaction) && (request != mCacheReadRequest)) { + if ((request != mTransactionPump) && (request != mCachePump)) { NS_WARNING("got stale request... why wasn't it cancelled?"); return NS_BASE_STREAM_CLOSED; } @@ -3083,7 +3032,8 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, input, mLogicalOffset, count); - mLogicalOffset += count; + if (NS_SUCCEEDED(rv)) + mLogicalOffset += count; return rv; } @@ -3091,56 +3041,34 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, } //----------------------------------------------------------------------------- -// nsHttpChannel::nsIInterfaceRequestor +// nsHttpChannel::nsITransportEventSink //----------------------------------------------------------------------------- NS_IMETHODIMP -nsHttpChannel::GetInterface(const nsIID &iid, void **result) +nsHttpChannel::OnTransportStatus(nsITransport *trans, nsresult status, + PRUint32 progress, PRUint32 progressMax) { - if (iid.Equals(NS_GET_IID(nsIProgressEventSink))) { - // - // we return ourselves as the progress event sink so we can intercept - // notifications and set the correct request and context parameters. - // but, if we don't have a progress sink to forward those messages - // to, then there's no point in handing out a reference to ourselves. - // - if (!mProgressSink) - return NS_ERROR_NO_INTERFACE; + // block socket status event after OnStopRequest has been fired. + if (mProgressSink && mIsPending && !(mLoadFlags & LOAD_BACKGROUND)) { + LOG(("sending status notification [status=%x]\n", status)); - return QueryInterface(iid, result); + NS_ConvertASCIItoUCS2 host(mConnectionInfo->Host()); + mProgressSink->OnStatus(this, nsnull, status, host.get()); + + // suppress "sending to" progress event if not uploading + if (status == nsISocketTransport::STATUS_RECEIVING_FROM || + (status == nsISocketTransport::STATUS_SENDING_TO && mUploadStream)) { + mProgressSink->OnProgress(this, nsnull, progress, progressMax); + } } - - if (mCallbacks) - return mCallbacks->GetInterface(iid, result); - - return NS_ERROR_NO_INTERFACE; -} - -//----------------------------------------------------------------------------- -// nsHttpChannel::nsIProgressEventSink -//----------------------------------------------------------------------------- - -// called on the socket thread -NS_IMETHODIMP -nsHttpChannel::OnStatus(nsIRequest *req, nsISupports *ctx, nsresult status, - const PRUnichar *statusText) -{ - if (mProgressSink && !mCanceled) - mProgressSink->OnStatus(this, mListenerContext, status, statusText); +#ifdef DEBUG + else + LOG(("skipping status notification [sink=%x pending=%u background=%x]\n", + mProgressSink.get(), mIsPending, (mLoadFlags & LOAD_BACKGROUND))); +#endif return NS_OK; -} - -// called on the socket thread -NS_IMETHODIMP -nsHttpChannel::OnProgress(nsIRequest *req, nsISupports *ctx, - PRUint32 progress, PRUint32 progressMax) -{ - if (mProgressSink && !mCanceled) - mProgressSink->OnProgress(this, mListenerContext, progress, progressMax); - - return NS_OK; -} +} //----------------------------------------------------------------------------- // nsHttpChannel::nsICachingChannel @@ -3246,7 +3174,7 @@ nsHttpChannel::IsFromCache(PRBool *value) // return false if reading a partial cache entry; the data isn't entirely // from the cache! - *value = (mCacheReadRequest || (mLoadFlags & LOAD_ONLY_IF_MODIFIED)) && + *value = (mCachePump || (mLoadFlags & LOAD_ONLY_IF_MODIFIED)) && mCachedContentIsValid && !mCachedContentIsPartial; return NS_OK; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h index 438f8da0e91..5b284dc9c85 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h @@ -24,8 +24,13 @@ #ifndef nsHttpChannel_h__ #define nsHttpChannel_h__ +#include "nsHttpTransaction.h" #include "nsHttpRequestHead.h" +#include "nsXPIDLString.h" +#include "nsCOMPtr.h" + #include "nsIHttpChannel.h" +#include "nsIHttpChannelInternal.h" #include "nsIHttpHeaderVisitor.h" #include "nsIHttpEventSink.h" #include "nsIStreamListener.h" @@ -43,15 +48,10 @@ #include "nsITransport.h" #include "nsIUploadChannel.h" #include "nsISimpleEnumerator.h" -#include "nsIInputStream.h" #include "nsIOutputStream.h" -#include "nsCOMPtr.h" -#include "nsXPIDLString.h" -#include "nsHttpConnection.h" +#include "nsIAsyncInputStream.h" +#include "nsIInputStreamPump.h" -#include "nsIHttpChannelInternal.h" - -class nsHttpTransaction; class nsHttpResponseHead; class nsHttpAuthCache; class nsIHttpAuthenticator; @@ -62,14 +62,13 @@ class nsIProxyInfo; //----------------------------------------------------------------------------- class nsHttpChannel : public nsIHttpChannel + , public nsIHttpChannelInternal , public nsIStreamListener - , public nsIInterfaceRequestor - , public nsIProgressEventSink , public nsICachingChannel , public nsIUploadChannel , public nsICacheListener , public nsIEncodedChannel - , public nsIHttpChannelInternal + , public nsITransportEventSink { public: NS_DECL_ISUPPORTS @@ -78,13 +77,12 @@ public: NS_DECL_NSIHTTPCHANNEL NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSIPROGRESSEVENTSINK NS_DECL_NSICACHINGCHANNEL NS_DECL_NSIUPLOADCHANNEL NS_DECL_NSICACHELISTENER NS_DECL_NSIENCODEDCHANNEL NS_DECL_NSIHTTPCHANNELINTERNAL + NS_DECL_NSITRANSPORTEVENTSINK nsHttpChannel(); virtual ~nsHttpChannel(); @@ -135,7 +133,6 @@ private: // byte range request specific methods nsresult SetupByteRangeRequest(PRUint32 partialLen); nsresult ProcessPartialContent(); - nsresult BufferPartialContent(nsIInputStream *, PRUint32 count); nsresult OnDoneReadingPartialCacheEntry(PRBool *streamDone); // auth specific methods @@ -167,10 +164,13 @@ private: nsCOMPtr mUploadStream; nsCOMPtr mReferrer; nsCOMPtr mSecurityInfo; + nsCOMPtr mEventQ; nsHttpRequestHead mRequestHead; nsHttpResponseHead *mResponseHead; + nsCOMPtr mTransactionPump; + nsCOMPtr mPrevTransactionPump; nsHttpTransaction *mTransaction; // hard ref nsHttpTransaction *mPrevTransaction; // hard ref nsHttpConnectionInfo *mConnectionInfo; // hard ref @@ -184,17 +184,12 @@ private: // cache specific data nsCOMPtr mCacheEntry; - nsCOMPtr mCacheTransport; - nsCOMPtr mCacheReadRequest; + nsCOMPtr mCachePump; nsHttpResponseHead *mCachedResponseHead; nsCacheAccessMode mCacheAccess; PRUint32 mPostID; PRUint32 mRequestTime; - // byte-range specific data - nsCOMPtr mBufferIn; - nsCOMPtr mBufferOut; - // auth specific data nsXPIDLString mUser; nsXPIDLString mPass; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp b/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp index e8590eeab45..2d220fcc6d7 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp @@ -39,7 +39,7 @@ #ifdef DEBUG // defined by the socket transport service while active -extern PRThread *NS_SOCKET_THREAD; +extern PRThread *gSocketThread; #endif static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); @@ -49,22 +49,24 @@ static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); //----------------------------------------------------------------------------- nsHttpConnection::nsHttpConnection() - : mTransaction(0) - , mConnectionInfo(0) + : mTransaction(nsnull) + , mConnInfo(nsnull) , mLock(nsnull) - , mReadStartTime(0) - , mLastActiveTime(0) + , mSuspendCount(0) + , mLastReadTime(0) , mIdleTimeout(0) - , mKeepAlive(1) // assume to keep-alive by default - , mKeepAliveMask(1) - , mWriteDone(0) - , mReadDone(0) + , mTransactionStatus(NS_OK) + , mTransactionDone(PR_TRUE) + , mKeepAlive(PR_TRUE) // assume to keep-alive by default + , mKeepAliveMask(PR_TRUE) + //, mWriteDone(0) + //, mReadDone(0) , mSupportsPipelining(PR_FALSE) // assume low-grade server { LOG(("Creating nsHttpConnection @%x\n", this)); // grab a reference to the handler to ensure that it doesn't go away. - nsHttpHandler *handler = nsHttpHandler::get(); + nsHttpHandler *handler = gHttpHandler; NS_ADDREF(handler); } @@ -72,7 +74,7 @@ nsHttpConnection::~nsHttpConnection() { LOG(("Destroying nsHttpConnection @%x\n", this)); - NS_IF_RELEASE(mConnectionInfo); + NS_IF_RELEASE(mConnInfo); NS_IF_RELEASE(mTransaction); if (mLock) { @@ -81,7 +83,7 @@ nsHttpConnection::~nsHttpConnection() } // release our reference to the handler - nsHttpHandler *handler = nsHttpHandler::get(); + nsHttpHandler *handler = gHttpHandler; NS_RELEASE(handler); } @@ -91,47 +93,87 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info, PRUint16 maxHangTime) LOG(("nsHttpConnection::Init [this=%x]\n", this)); NS_ENSURE_ARG_POINTER(info); - NS_ENSURE_TRUE(!mConnectionInfo, NS_ERROR_ALREADY_INITIALIZED); + NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED); mLock = PR_NewLock(); if (!mLock) return NS_ERROR_OUT_OF_MEMORY; - mConnectionInfo = info; - NS_ADDREF(mConnectionInfo); + mConnInfo = info; + NS_ADDREF(mConnInfo); mMaxHangTime = maxHangTime; + mLastReadTime = NowInSeconds(); return NS_OK; } -// called from any thread, without the connection lock held +// called on the socket thread nsresult -nsHttpConnection::SetTransaction(nsAHttpTransaction *transaction, - PRUint8 caps) +nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps) { - LOG(("nsHttpConnection::SetTransaction [this=%x trans=%x]\n", - this, transaction)); + LOG(("nsHttpConnection::Activate [this=%x trans=%x caps=%x]\n", + this, trans, caps)); + NS_ENSURE_ARG_POINTER(trans); NS_ENSURE_TRUE(!mTransaction, NS_ERROR_IN_PROGRESS); - NS_ENSURE_ARG_POINTER(transaction); // take ownership of the transaction - mTransaction = transaction; + mTransaction = trans; NS_ADDREF(mTransaction); - // default mKeepAlive according to what will be requested + mTransaction->SetConnection(this); + + nsresult rv; + + // set mKeepAlive according to what will be requested mKeepAliveMask = mKeepAlive = (caps & NS_HTTP_ALLOW_KEEPALIVE); - return ActivateConnection(); + // if we don't have a socket transport then create a new one + if (!mSocketTransport) { + rv = CreateTransport(); + if (NS_SUCCEEDED(rv)) { + // need to handle SSL proxy CONNECT if this is the first time. + if (mConnInfo->UsingSSL() && mConnInfo->UsingHttpProxy()) + rv = SetupSSLProxyConnect(); + } + if (NS_FAILED(rv)) + goto loser; + } + + // wait for the output stream to be readable + rv = mSocketOut->AsyncWait(this, 0, nsnull); + if (NS_SUCCEEDED(rv)) + return rv; + +loser: + NS_RELEASE(mTransaction); + return rv; } -// called from the socket thread +void +nsHttpConnection::Close(nsresult reason) +{ + LOG(("nsHttpConnection::Close [this=%x reason=%x]\n", this, reason)); + + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + if (NS_FAILED(reason)) { + if (mSocketTransport) { + mSocketTransport->SetSecurityCallbacks(nsnull); + mSocketTransport->SetEventSink(nsnull, nsnull); + mSocketTransport->Close(reason); + } + mKeepAlive = PR_FALSE; + } +} + +// called on the socket thread nsresult nsHttpConnection::ProxyStartSSL() { LOG(("nsHttpConnection::ProxyStartSSL [this=%x]\n", this)); #ifdef DEBUG - NS_PRECONDITION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); + NS_PRECONDITION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); #endif nsCOMPtr securityInfo; @@ -147,7 +189,7 @@ nsHttpConnection::ProxyStartSSL() PRBool nsHttpConnection::CanReuse() { - return IsKeepAlive() && (NowInSeconds() - mLastActiveTime < mIdleTimeout) + return IsKeepAlive() && (NowInSeconds() - mLastReadTime < mIdleTimeout) && IsAlive(); } @@ -157,10 +199,12 @@ nsHttpConnection::IsAlive() if (!mSocketTransport) return PR_FALSE; - PRBool isAlive = PR_FALSE; - nsresult rv = mSocketTransport->IsAlive(0, &isAlive); - NS_ASSERTION(NS_SUCCEEDED(rv), "IsAlive test failed"); - return isAlive; + PRBool alive; + nsresult rv = mSocketTransport->IsAlive(&alive); + if (NS_FAILED(rv)) + alive = PR_FALSE; + + return alive; } PRBool @@ -170,7 +214,7 @@ nsHttpConnection::SupportsPipelining(nsHttpResponseHead *responseHead) // blacklisting. // assuming connection is HTTP/1.1 with keep-alive enabled - if (mConnectionInfo->UsingHttpProxy() && !mConnectionInfo->UsingSSL()) { + if (mConnInfo->UsingHttpProxy() && !mConnInfo->UsingSSL()) { // XXX check for bad proxy servers... return PR_TRUE; } @@ -205,7 +249,6 @@ nsHttpConnection::SupportsPipelining(nsHttpResponseHead *responseHead) // nsHttpConnection::nsAHttpConnection //---------------------------------------------------------------------------- -// called from the socket thread nsresult nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, nsHttpRequestHead *requestHead, @@ -215,6 +258,7 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, LOG(("nsHttpConnection::OnHeadersAvailable [this=%p trans=%p response-head=%p]\n", this, trans, responseHead)); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ENSURE_ARG_POINTER(trans); // we won't change our keep-alive policy unless the server has explicitly @@ -267,7 +311,7 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, if (cp) mIdleTimeout = (PRUint32) atoi(cp + 8); else - mIdleTimeout = nsHttpHandler::get()->IdleTimeout(); + mIdleTimeout = gHttpHandler->IdleTimeout(); LOG(("Connection can be reused [this=%x idle-timeout=%u\n", this, mIdleTimeout)); } @@ -282,206 +326,63 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, LOG(("SSL proxy CONNECT succeeded!\n")); *reset = PR_TRUE; ProxyStartSSL(); - mWriteRequest->Resume(); + nsresult rv = mSocketOut->AsyncWait(this, 0, nsnull); + // XXX what if this fails -- need to handle this error + NS_ASSERTION(NS_SUCCEEDED(rv), "mSocketOut->AsyncWait failed"); } else { LOG(("SSL proxy CONNECT failed!\n")); // close out the write request - mWriteRequest->Cancel(NS_OK); + mSocketOut->Close(); } } return NS_OK; } -// called from any thread -nsresult -nsHttpConnection::OnTransactionComplete(nsAHttpTransaction *trans, nsresult status) -{ - LOG(("nsHttpConnection::OnTransactionComplete [this=%x trans=%x status=%x]\n", - this, trans, status)); - - // trans may not be mTransaction - if (trans != mTransaction) - return NS_OK; - - nsCOMPtr writeReq, readReq; - - // clear the read/write requests atomically. - { - nsAutoLock lock(mLock); - writeReq = mWriteRequest; - readReq = mReadRequest; - } - - // cancel the requests... this will cause OnStopRequest to be fired - if (writeReq) - writeReq->Cancel(status); - if (readReq) - readReq->Cancel(status); - - return NS_OK; -} - -// not called from the socket thread -nsresult -nsHttpConnection::OnSuspend() -{ - // we only bother to suspend the read request, since that's the only - // one that will effect our consumers. - - nsCOMPtr readReq; - { - nsAutoLock lock(mLock); - readReq = mReadRequest; - } - - if (readReq) - readReq->Suspend(); - - return NS_OK; -} - -// not called from the socket thread -nsresult -nsHttpConnection::OnResume() -{ - // we only need to worry about resuming the read request, since that's - // the only one that can be suspended. - - nsCOMPtr readReq; - { - nsAutoLock lock(mLock); - readReq = mReadRequest; - } - - if (readReq) - readReq->Resume(); - - return NS_OK; -} - -// called on the socket thread void -nsHttpConnection::DropTransaction(nsAHttpTransaction *trans) +nsHttpConnection::GetSecurityInfo(nsISupports **secinfo) { - LOG(("nsHttpConnection::DropTransaction [trans=%p]\n", trans)); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); - // the assertion here is that the transaction will not be destroyed - // by this release. we unfortunately don't have a threadsafe way of - // asserting this. - NS_IF_RELEASE(mTransaction); - mTransaction = 0; - - // if the transaction was dropped, then we cannot reuse this connection. - mKeepAliveMask = mKeepAlive = PR_FALSE; + if (mSocketTransport) { + if (NS_FAILED(mSocketTransport->GetSecurityInfo(secinfo))) + *secinfo = nsnull; + } +} + +nsresult +nsHttpConnection::ResumeSend() +{ + LOG(("nsHttpConnection::ResumeSend [this=%p]\n", this)); + + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + if (mSocketOut) + return mSocketOut->AsyncWait(this, 0, nsnull); + + NS_NOTREACHED("no socket output stream"); + return NS_ERROR_UNEXPECTED; +} + +nsresult +nsHttpConnection::ResumeRecv() +{ + LOG(("nsHttpConnection::ResumeRecv [this=%p]\n", this)); + + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + if (mSocketIn) + return mSocketIn->AsyncWait(this, 0, nsnull); + + NS_NOTREACHED("no socket input stream"); + return NS_ERROR_UNEXPECTED; } //----------------------------------------------------------------------------- // nsHttpConnection //----------------------------------------------------------------------------- -// called on any thread -nsresult -nsHttpConnection::ActivateConnection() -{ - nsresult rv; - - // if we don't have a socket transport then create a new one - if (!mSocketTransport) { - rv = CreateTransport(); - if (NS_FAILED(rv)) return rv; - - // need to handle SSL proxy CONNECT if this is the first time. - if (mConnectionInfo->UsingSSL() && - mConnectionInfo->UsingHttpProxy()) { - rv = SetupSSLProxyConnect(); - if (NS_FAILED(rv)) return rv; - } - } - - // allow the socket transport to call us directly on progress - rv = mSocketTransport-> - SetNotificationCallbacks(this, nsITransport::DONT_PROXY_PROGRESS); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr writeReq, readReq; - PRBool mustCancelWrite = PR_FALSE; - PRBool mustCancelRead = PR_FALSE; - - mWriteDone = PR_FALSE; - mReadDone = PR_FALSE; - - // because AsyncRead can result in listener callbacks on the socket - // transport thread before it even runs, we have to addref this in order - // to ensure that we stay around long enough to complete this call. - NS_ADDREF_THIS(); - - // by the same token, we need to ensure that the transaction stays around. - // and we must not access it via mTransaction, since mTransaction is null'd - // in our OnStopRequest. - nsAHttpTransaction *trans = mTransaction; - NS_ADDREF(trans); - - // We need to tell the socket transport what origin server we're - // communicating with. This may not be the same as the original host, - // if we're talking to a proxy server using persistent connections. - // We update the connectionInfo as well, so that our logging is correct. - // See bug 94088 - - mSocketTransport->SetHost(mConnectionInfo->Host()); - mSocketTransport->SetPort(mConnectionInfo->Port()); - - // fire off the read first so that we'll often detect premature EOF before - // writing to the socket, though this is not necessary. - rv = mSocketTransport->AsyncRead(this, nsnull, - 0, PRUint32(-1), - nsITransport::DONT_PROXY_OBSERVER | - nsITransport::DONT_PROXY_LISTENER, - getter_AddRefs(readReq)); - if (NS_FAILED(rv)) goto end; - - // we pass a reference to ourselves as the context so we can - // differentiate the stream listener events. - rv = mSocketTransport->AsyncWrite(this, (nsIStreamListener*) this, - 0, PRUint32(-1), - nsITransport::DONT_PROXY_OBSERVER | - nsITransport::DONT_PROXY_PROVIDER, - getter_AddRefs(writeReq)); - if (NS_FAILED(rv)) goto end; - - // grab pointers to the read/write requests provided they have not - // already finished. check for early cancelation (indicated by the - // transaction being in the DONE state). - { - nsAutoLock lock(mLock); - - if (!mWriteDone) { - mWriteRequest = writeReq; - if (trans->IsDone()) - mustCancelWrite = PR_TRUE; - } - if (!mReadDone) { - mReadRequest = readReq; - if (trans->IsDone()) - mustCancelRead = PR_TRUE; - } - } - - // handle the case of an overlapped cancelation (ie. the transaction - // could have been canceled prior to mReadRequest/mWriteRequest being - // assigned). - if (mustCancelWrite) - writeReq->Cancel(trans->Status()); - if (mustCancelRead) - readReq->Cancel(trans->Status()); - -end: - NS_RELEASE(trans); - NS_RELEASE_THIS(); - return rv; -} - nsresult nsHttpConnection::CreateTransport() { @@ -494,29 +395,215 @@ nsHttpConnection::CreateTransport() if (NS_FAILED(rv)) return rv; // configure the socket type based on the connection type requested. - const char* type = nsnull; + const char* types[1]; - if (mConnectionInfo->UsingSSL()) - type = "ssl"; + if (mConnInfo->UsingSSL()) + types[0] = "ssl"; else - type = nsHttpHandler::get()->DefaultSocketType(); + types[0] = gHttpHandler->DefaultSocketType(); - nsCOMPtr transport; - rv = sts->CreateTransportOfType(type, - mConnectionInfo->Host(), - mConnectionInfo->Port(), - mConnectionInfo->ProxyInfo(), - NS_HTTP_SEGMENT_SIZE, - NS_HTTP_BUFFER_SIZE, - getter_AddRefs(transport)); + nsCOMPtr strans; + PRUint32 typeCount = (types[0] != nsnull); + + rv = sts->CreateTransport(types, typeCount, + nsDependentCString(mConnInfo->Host()), + mConnInfo->Port(), + mConnInfo->ProxyInfo(), + getter_AddRefs(strans)); if (NS_FAILED(rv)) return rv; - // the transport has better be a socket transport !! - mSocketTransport = do_QueryInterface(transport, &rv); + // NOTE: these create cyclical references, which we break inside + // nsHttpConnection::Close + rv = strans->SetEventSink(this, nsnull); + if (NS_FAILED(rv)) return rv; + rv = strans->SetSecurityCallbacks(this); if (NS_FAILED(rv)) return rv; - rv = mSocketTransport->SetReuseConnection(PR_TRUE); + // next open the socket streams + nsCOMPtr sout; + rv = strans->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, + getter_AddRefs(sout)); if (NS_FAILED(rv)) return rv; + nsCOMPtr sin; + rv = strans->OpenInputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, + getter_AddRefs(sin)); + if (NS_FAILED(rv)) return rv; + + mSocketTransport = strans; + mSocketIn = do_QueryInterface(sin); + mSocketOut = do_QueryInterface(sout); + return NS_OK; +} + +void +nsHttpConnection::CloseTransaction(nsAHttpTransaction *trans, nsresult reason) +{ + LOG(("nsHttpConnection::CloseTransaction[this=%x trans=%x reason=%x]\n", + this, trans, reason)); + + NS_ASSERTION(trans == mTransaction, "wrong transaction"); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + // ignore this error code because its not a real error. + if (reason == NS_BASE_STREAM_CLOSED) + reason = NS_OK; + + mTransaction->Close(reason); + NS_RELEASE(mTransaction); + mTransaction = 0; + + if (NS_FAILED(reason)) + Close(reason); + + gHttpHandler->ReclaimConnection(this); +} + +NS_METHOD +nsHttpConnection::ReadFromStream(nsIInputStream *input, + void *closure, + const char *buf, + PRUint32 offset, + PRUint32 count, + PRUint32 *countRead) +{ + // thunk for nsIInputStream instance + nsHttpConnection *conn = (nsHttpConnection *) closure; + return conn->OnReadSegment(buf, count, countRead); +} + +nsresult +nsHttpConnection::OnReadSegment(const char *buf, + PRUint32 count, + PRUint32 *countRead) +{ + nsresult rv = mSocketOut->Write(buf, count, countRead); + if (NS_FAILED(rv)) + mSocketOutCondition = rv; + else if (*countRead == 0) + mSocketOutCondition = NS_BASE_STREAM_CLOSED; + else + mSocketOutCondition = NS_OK; // reset condition + + return mSocketOutCondition; +} + +nsresult +nsHttpConnection::OnSocketWritable() +{ + LOG(("nsHttpConnection::OnSocketWritable [this=%x]\n", this)); + + PRUint32 count, n; + nsresult rv; + + // if we're doing an SSL proxy connect, then we need to bypass calling + // into the transaction. + // + // NOTE: this code path can't be shared since the transaction doesn't + // implement nsIInputStream. doing so is not worth the added cost of + // extra indirections during normal reading. + // + if (mSSLProxyConnectStream) { + LOG((" writing CONNECT request stream\n")); + + rv = mSSLProxyConnectStream->Available(&count); + if (NS_FAILED(rv)) return rv; + + rv = mSSLProxyConnectStream->ReadSegments(ReadFromStream, this, count, &n); + } + else { + LOG((" writing transaction request stream\n")); + + count = mTransaction->Available(); + NS_ENSURE_TRUE(count > 0, NS_ERROR_UNEXPECTED); + + rv = mTransaction->ReadSegments(this, count, &n); + } + + LOG((" ReadSegments returned [rv=%x count=%u read=%u sock-cond=%x]\n", + rv, count, n, mSocketOutCondition)); + + if (NS_SUCCEEDED(rv)) { + if (NS_FAILED(mSocketOutCondition)) { + if (mSocketOutCondition == NS_BASE_STREAM_WOULD_BLOCK) + rv = mSocketOut->AsyncWait(this, 0, nsnull); // continue writing + else + rv = mSocketOutCondition; + } + else if (n == count) { + // + // at this point we've written out the entire transaction, and now we + // must wait for the server's response. we manufacture a status message + // here to reflect the fact that we are waiting. this message will be + // trumped (overwritten) if the server responds quickly. + // + mTransaction->OnTransportStatus(nsISocketTransport::STATUS_WAITING_FOR, 0); + + rv = mSocketIn->AsyncWait(this, 0, nsnull); // start reading + } + else { + NS_WARNING("stopped writing for no reason"); + rv = NS_ERROR_UNEXPECTED; + } + } + + return rv; +} + +nsresult +nsHttpConnection::OnWriteSegment(char *buf, + PRUint32 count, + PRUint32 *countWritten) +{ + nsresult rv = mSocketIn->Read(buf, count, countWritten); + if (NS_FAILED(rv)) + mSocketInCondition = rv; + else if (*countWritten == 0) + mSocketInCondition = NS_BASE_STREAM_CLOSED; + else + mSocketInCondition = NS_OK; // reset condition + + return mSocketInCondition; +} + +nsresult +nsHttpConnection::OnSocketReadable() +{ + LOG(("nsHttpConnection::OnSocketReadable [this=%x]\n", this)); + + PRUint32 now = NowInSeconds(); + + if (mKeepAliveMask && (now - mLastReadTime >= PRUint32(mMaxHangTime))) { + LOG(("max hang time exceeded!\n")); + // give the handler a chance to create a new persistent connection to + // this host if we've been busy for too long. + mKeepAliveMask = PR_FALSE; + gHttpHandler->ProcessPendingQ(mConnInfo); + } + mLastReadTime = now; + + nsresult rv; + PRUint32 n; + PRBool again = PR_TRUE; + + do { + rv = mTransaction->WriteSegments(this, NS_HTTP_SEGMENT_SIZE, &n); + if (NS_FAILED(rv)) { + // if the transaction didn't want to take anymore data, then + // wait for the transaction to call ResumeSend. + if (rv == NS_BASE_STREAM_WOULD_BLOCK) + rv = NS_OK; + again = PR_FALSE; + } + else if (NS_FAILED(mSocketInCondition)) { + // continue waiting for the socket if necessary... + if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) + rv = mSocketIn->AsyncWait(this, 0, nsnull); + else + rv = mSocketInCondition; + again = PR_FALSE; + } + // read more from the socket until error... + } while (again); return rv; } @@ -524,7 +611,6 @@ nsHttpConnection::CreateTransport() nsresult nsHttpConnection::SetupSSLProxyConnect() { - nsresult rv; const char *val; LOG(("nsHttpConnection::SetupSSLProxyConnect [this=%x]\n", this)); @@ -532,16 +618,16 @@ nsHttpConnection::SetupSSLProxyConnect() NS_ENSURE_TRUE(!mSSLProxyConnectStream, NS_ERROR_ALREADY_INITIALIZED); nsCAutoString buf; - buf.Assign(mConnectionInfo->Host()); + buf.Assign(mConnInfo->Host()); buf.Append(':'); - buf.AppendInt(mConnectionInfo->Port()); + buf.AppendInt(mConnInfo->Port()); // CONNECT host:port HTTP/1.1 nsHttpRequestHead request; request.SetMethod(nsHttp::Connect); - request.SetVersion(nsHttpHandler::get()->HttpVersion()); + request.SetVersion(gHttpHandler->HttpVersion()); request.SetRequestURI(buf.get()); - request.SetHeader(nsHttp::User_Agent, nsHttpHandler::get()->UserAgent()); + request.SetHeader(nsHttp::User_Agent, gHttpHandler->UserAgent()); // NOTE: this cast is valid since this connection cannot be processing a // transaction pipeline until after the first HTTP/1.1 response. @@ -565,193 +651,79 @@ nsHttpConnection::SetupSSLProxyConnect() request.Flatten(buf, PR_FALSE); buf.Append("\r\n"); - rv = NS_NewCStringInputStream(getter_AddRefs(mSSLProxyConnectStream), buf); - - return rv; + return NS_NewCStringInputStream(getter_AddRefs(mSSLProxyConnectStream), buf); } //----------------------------------------------------------------------------- // nsHttpConnection::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_THREADSAFE_ADDREF(nsHttpConnection) -NS_IMPL_THREADSAFE_RELEASE(nsHttpConnection) - -NS_INTERFACE_MAP_BEGIN(nsHttpConnection) - NS_INTERFACE_MAP_ENTRY(nsIStreamListener) - NS_INTERFACE_MAP_ENTRY(nsIStreamProvider) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequestObserver, nsIStreamListener) - NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) - NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) -NS_INTERFACE_MAP_END_THREADSAFE +NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpConnection, + nsIInputStreamNotify, + nsIOutputStreamNotify, + nsITransportEventSink, + nsIInterfaceRequestor) //----------------------------------------------------------------------------- -// nsHttpConnection::nsIRequestObserver +// nsHttpConnection::nsIInputStreamNotify //----------------------------------------------------------------------------- // called on the socket transport thread NS_IMETHODIMP -nsHttpConnection::OnStartRequest(nsIRequest *request, nsISupports *ctxt) +nsHttpConnection::OnInputStreamReady(nsIAsyncInputStream *in) { - LOG(("nsHttpConnection::OnStartRequest [this=%x]\n", this)); + NS_ASSERTION(in == mSocketIn, "unexpected stream"); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); - // because this code can run before AsyncWrite (AsyncRead) returns, we need - // to capture the write (read) request object. see bug 90196 for an example - // of why this is necessary. - if (ctxt) { - mWriteRequest = request; - // this only needs to be done once, so do it for the write request. - if (mTransaction) { - nsCOMPtr info; - mSocketTransport->GetSecurityInfo(getter_AddRefs(info)); - mTransaction->SetSecurityInfo(info); - } - } - else { - mReadRequest = request; - mReadStartTime = NowInSeconds(); + // if the transaction was dropped... + if (!mTransaction) { + LOG((" no transaction; ignoring event\n")); + return NS_OK; } + nsresult rv = OnSocketReadable(); + if (NS_FAILED(rv)) + CloseTransaction(mTransaction, rv); + return NS_OK; } -// called on the socket transport thread +//----------------------------------------------------------------------------- +// nsHttpConnection::nsIOutputStreamNotify +//----------------------------------------------------------------------------- + NS_IMETHODIMP -nsHttpConnection::OnStopRequest(nsIRequest *request, nsISupports *ctxt, - nsresult status) +nsHttpConnection::OnOutputStreamReady(nsIAsyncOutputStream *out) { - LOG(("nsHttpConnection::OnStopRequest [this=%x ctxt=%x status=%x]\n", - this, ctxt, status)); + NS_ASSERTION(out == mSocketOut, "unexpected stream"); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); - if (ctxt == (nsISupports *) (nsIStreamListener *) this) { - // Done writing, so mark the write request as complete. - nsAutoLock lock(mLock); - mWriteDone = PR_TRUE; - mWriteRequest = 0; - } - else { - // Done reading, so mark the read request as complete. - nsAutoLock lock(mLock); - mReadDone = PR_TRUE; - mReadRequest = 0; + // if the transaction was dropped... + if (!mTransaction) { + LOG((" no transaction; ignoring event\n")); + return NS_OK; } - if (mReadDone && mWriteDone) { - // if the transaction failed for any reason, the socket will not be - // reusable. - if (NS_FAILED(status)) - DontReuse(); + nsresult rv = OnSocketWritable(); + if (NS_FAILED(rv)) + CloseTransaction(mTransaction, rv); - nsCOMPtr info; - mSocketTransport->GetSecurityInfo(getter_AddRefs(info)); - nsCOMPtr secCtrl(do_QueryInterface(info)); - - // break the cycle between the security info and this - if (secCtrl) - secCtrl->SetNotificationCallbacks(nsnull); - - // break the cycle between the socket transport and this - mSocketTransport->SetNotificationCallbacks(nsnull, 0); - - // make sure mTransaction is clear before calling OnStopTransaction - if (mTransaction) { - nsAHttpTransaction *trans = mTransaction; - mTransaction = nsnull; - - trans->OnStopTransaction(status); - NS_RELEASE(trans); - } - - // reset the keep-alive mask - mKeepAliveMask = mKeepAlive; - - nsHttpHandler::get()->ReclaimConnection(this); - - // release reference to socket transport if were not going to reuse - // the socket connection. - if (!mKeepAlive) - mSocketTransport = 0; - } - // no point in returning anything else but NS_OK return NS_OK; } //----------------------------------------------------------------------------- -// nsHttpConnection::nsIStreamProvider +// nsHttpConnection::nsITransportEventSink //----------------------------------------------------------------------------- -// called on the socket transport thread NS_IMETHODIMP -nsHttpConnection::OnDataWritable(nsIRequest *request, nsISupports *context, - nsIOutputStream *outputStream, - PRUint32 offset, PRUint32 count) +nsHttpConnection::OnTransportStatus(nsITransport *trans, + nsresult status, + PRUint32 progress, + PRUint32 progressMax) { - if (!mTransaction) { - LOG(("nsHttpConnection: no transaction! closing stream\n")); - return NS_BASE_STREAM_CLOSED; - } - - LOG(("nsHttpConnection::OnDataWritable [this=%x]\n", this)); - - // if we're doing an SSL proxy connect, then we need to bypass calling - // into the transaction. - if (mSSLProxyConnectStream) { - PRUint32 n; - - nsresult rv = mSSLProxyConnectStream->Available(&n); - if (NS_FAILED(rv)) return rv; - - // if there are bytes available in the stream, then write them out. - // otherwise, suspend the write request... it'll get restarted once - // we get a response from the proxy server. - if (n) { - LOG(("writing data from proxy connect stream [count=%u]\n", n)); - return outputStream->WriteFrom(mSSLProxyConnectStream, n, &n); - } - - LOG(("done writing proxy connect stream, waiting for response.\n")); - return NS_BASE_STREAM_WOULD_BLOCK; - } - - LOG(("calling mTransaction->OnDataWritable\n")); - - // in the normal case, we just want to defer to the transaction to write - // out the request. - return mTransaction->OnDataWritable(outputStream); -} - -//----------------------------------------------------------------------------- -// nsHttpConnection::nsIStreamListener -//----------------------------------------------------------------------------- - -// called on the socket transport thread -NS_IMETHODIMP -nsHttpConnection::OnDataAvailable(nsIRequest *request, nsISupports *context, - nsIInputStream *inputStream, - PRUint32 offset, PRUint32 count) -{ - LOG(("nsHttpConnection::OnDataAvailable [this=%x]\n", this)); - - if (!mTransaction) { - LOG(("no transaction! closing stream\n")); - return NS_BASE_STREAM_CLOSED; - } - - mLastActiveTime = NowInSeconds(); - - if (mKeepAliveMask && - (mLastActiveTime - mReadStartTime >= PRUint32(mMaxHangTime))) { - LOG(("max hang time exceeded!\n")); - // give the handler a chance to create a new persistent connection to - // this host if we've been busy for too long. - mKeepAliveMask = PR_FALSE; - nsHttpHandler::get()->ProcessTransactionQ(); - } - - nsresult rv = mTransaction->OnDataReadable(inputStream); - - LOG(("mTransaction->OnDataReadable() returned [rv=%x]\n", rv)); - return rv; + if (mTransaction) + mTransaction->OnTransportStatus(status, progress); + return NS_OK; } //----------------------------------------------------------------------------- @@ -762,37 +734,13 @@ nsHttpConnection::OnDataAvailable(nsIRequest *request, nsISupports *context, NS_IMETHODIMP nsHttpConnection::GetInterface(const nsIID &iid, void **result) { - if (iid.Equals(NS_GET_IID(nsIProgressEventSink))) - return QueryInterface(iid, result); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); if (mTransaction) { nsCOMPtr callbacks; - mTransaction->GetNotificationCallbacks(getter_AddRefs(callbacks)); + mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks)); return callbacks->GetInterface(iid, result); } return NS_ERROR_NO_INTERFACE; } - -//----------------------------------------------------------------------------- -// nsHttpConnection::nsIProgressEventSink -//----------------------------------------------------------------------------- - -// called on the socket transport thread -NS_IMETHODIMP -nsHttpConnection::OnStatus(nsIRequest *req, nsISupports *ctx, nsresult status, - const PRUnichar *statusText) -{ - if (mTransaction) - mTransaction->OnStatus(status, statusText); - return NS_OK; -} - -NS_IMETHODIMP -nsHttpConnection::OnProgress(nsIRequest *req, nsISupports *ctx, - PRUint32 progress, PRUint32 progressMax) -{ - // we ignore progress notifications from the socket transport. - // we'll generate these ourselves from OnDataAvailable. - return NS_OK; -} diff --git a/mozilla/netwerk/protocol/http/src/nsHttpConnection.h b/mozilla/netwerk/protocol/http/src/nsHttpConnection.h index 66265bfca66..637ccc32cd9 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpConnection.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpConnection.h @@ -28,37 +28,38 @@ #include "nsHttpConnectionInfo.h" #include "nsAHttpConnection.h" #include "nsAHttpTransaction.h" -#include "nsIStreamListener.h" -#include "nsIStreamProvider.h" -#include "nsISocketTransport.h" -#include "nsIProgressEventSink.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIEventQueue.h" -#include "nsIInputStream.h" #include "nsXPIDLString.h" #include "nsCOMPtr.h" #include "prlock.h" -class nsHttpHandler; +#include "nsIStreamListener.h" +#include "nsISocketTransport.h" +#include "nsIEventQueue.h" +#include "nsIAsyncInputStream.h" +#include "nsIAsyncOutputStream.h" +#include "nsIInterfaceRequestor.h" //----------------------------------------------------------------------------- // nsHttpConnection - represents a connection to a HTTP server (or proxy) +// +// NOTE: this objects lives on the socket thread only. it should not be +// accessed from any other thread. //----------------------------------------------------------------------------- class nsHttpConnection : public nsAHttpConnection - , public nsIStreamListener - , public nsIStreamProvider - , public nsIProgressEventSink + , public nsAHttpSegmentReader + , public nsAHttpSegmentWriter + , public nsIInputStreamNotify + , public nsIOutputStreamNotify + , public nsITransportEventSink , public nsIInterfaceRequestor { public: NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSISTREAMPROVIDER - NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSIINPUTSTREAMNOTIFY + NS_DECL_NSIOUTPUTSTREAMNOTIFY + NS_DECL_NSITRANSPORTEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSIPROGRESSEVENTSINK nsHttpConnection(); virtual ~nsHttpConnection(); @@ -70,12 +71,15 @@ public: // alive. a value of 0xffff indicates no limit. nsresult Init(nsHttpConnectionInfo *info, PRUint16 maxHangTime); - // SetTransaction causes the given transaction to be processed on this + // Activate causes the given transaction to be processed on this // connection. It fails if there is already an existing transaction. - nsresult SetTransaction(nsAHttpTransaction *, PRUint8 capabilities); + nsresult Activate(nsAHttpTransaction *, PRUint8 caps); - // called to cause the underlying socket to start speaking SSL - nsresult ProxyStartSSL(); + // Close the underlying socket transport. + void Close(nsresult reason); + + //------------------------------------------------------------------------- + // XXX document when these are ok to call PRBool SupportsPipelining() { return mSupportsPipelining; } PRBool IsKeepAlive() { return mKeepAliveMask && mKeepAlive; } @@ -86,48 +90,67 @@ public: void DropTransport() { DontReuse(); mSocketTransport = 0; } nsAHttpTransaction *Transaction() { return mTransaction; } - nsHttpConnectionInfo *ConnectionInfo() { return mConnectionInfo; } + nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } // nsAHttpConnection methods: nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpRequestHead *, nsHttpResponseHead *, PRBool *reset); - nsresult OnTransactionComplete(nsAHttpTransaction *, nsresult status); - nsresult OnSuspend(); - nsresult OnResume(); - void GetConnectionInfo(nsHttpConnectionInfo **ci) { NS_IF_ADDREF(*ci = mConnectionInfo); } - void DropTransaction(nsAHttpTransaction *); + void CloseTransaction(nsAHttpTransaction *, nsresult reason); + void GetConnectionInfo(nsHttpConnectionInfo **ci) { NS_IF_ADDREF(*ci = mConnInfo); } + void GetSecurityInfo(nsISupports **); PRBool IsPersistent() { return IsKeepAlive(); } nsresult PushBack(const char *data, PRUint32 length) { NS_NOTREACHED("PushBack"); return NS_ERROR_UNEXPECTED; } + nsresult ResumeSend(); + nsresult ResumeRecv(); + + // nsAHttpSegmentReader methods: + nsresult OnReadSegment(const char *, PRUint32, PRUint32 *); + + // nsAHttpSegmentWriter methods: + nsresult OnWriteSegment(char *, PRUint32, PRUint32 *); + + static NS_METHOD ReadFromStream(nsIInputStream *, void *, const char *, + PRUint32, PRUint32, PRUint32 *); private: - nsresult ActivateConnection(); + // called to cause the underlying socket to start speaking SSL + nsresult ProxyStartSSL(); + nsresult CreateTransport(); + nsresult OnTransactionDone(nsresult reason); + nsresult OnSocketWritable(); + nsresult OnSocketReadable(); nsresult SetupSSLProxyConnect(); PRBool IsAlive(); PRBool SupportsPipelining(nsHttpResponseHead *); - + private: nsCOMPtr mSocketTransport; - nsCOMPtr mWriteRequest; - nsCOMPtr mReadRequest; + nsCOMPtr mSocketIn; + nsCOMPtr mSocketOut; + + nsresult mSocketInCondition; + nsresult mSocketOutCondition; nsCOMPtr mSSLProxyConnectStream; + nsCOMPtr mRequestStream; - nsAHttpTransaction *mTransaction; // hard ref - nsHttpConnectionInfo *mConnectionInfo; // hard ref + nsAHttpTransaction *mTransaction; // hard ref + nsHttpConnectionInfo *mConnInfo; // hard ref PRLock *mLock; + PRInt32 mSuspendCount; - PRUint32 mReadStartTime; // time of OnStartRequest - PRUint32 mLastActiveTime; + PRUint32 mLastReadTime; PRUint16 mMaxHangTime; // max download time before dropping keep-alive status PRUint16 mIdleTimeout; // value of keep-alive: timeout= + nsresult mTransactionStatus; + PRPackedBool mTransactionDone; + PRPackedBool mKeepAlive; PRPackedBool mKeepAliveMask; - PRPackedBool mWriteDone; - PRPackedBool mReadDone; PRPackedBool mSupportsPipelining; }; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h b/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h index 47037d424cd..804df5f6dfb 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h @@ -28,7 +28,7 @@ #include "nsIProxyInfo.h" #include "nsCOMPtr.h" #include "nsDependentString.h" -#include "nsSharableString.h" +#include "nsString.h" #include "plstr.h" #include "nsCRT.h" @@ -71,16 +71,13 @@ public: return n; } - nsresult SetOriginServer(const nsACString &host, PRInt32 port) - { - mHost = host; - mPort = port == -1 ? DefaultPort() : port; - return NS_OK; - } + const nsAFlatCString &HashKey() const { return mHashKey; } - nsresult SetOriginServer(const char *host, PRInt32 port) + void SetOriginServer(const nsACString &host, PRInt32 port); + + void SetOriginServer(const char *host, PRInt32 port) { - return SetOriginServer(nsDependentCString(host), port); + SetOriginServer(nsDependentCString(host), port); } const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host() : nsnull; } @@ -96,21 +93,7 @@ public: // a request will end up at the same host. PRBool Equals(const nsHttpConnectionInfo *info) { - // Strictly speaking, we could talk to a proxy on the same port - // and reuse the connection. Its not worth the extra strcmp. - if ((info->mUsingHttpProxy != mUsingHttpProxy) || - (info->mUsingSSL != mUsingSSL)) - return PR_FALSE; - - // if its a proxy, then compare the proxy servers. - if (mUsingHttpProxy && !mUsingSSL) - return (!PL_strcasecmp(info->ProxyHost(), ProxyHost()) && - info->ProxyPort() == ProxyPort()); - - // otherwise, just check the hosts - return (!PL_strcasecmp(info->Host(), Host()) && - info->mPort == mPort); - + return mHashKey.Equals(info->HashKey()); } const char *Host() const { return mHost.get(); } @@ -122,7 +105,8 @@ public: private: nsrefcnt mRef; - nsSharableCString mHost; + nsCString mHashKey; + nsCString mHost; PRInt32 mPort; nsCOMPtr mProxyInfo; PRPackedBool mUsingHttpProxy; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp b/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp index 5bd1c41e68d..9aaa9ac09c6 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp @@ -34,7 +34,6 @@ #include "nsHttpResponseHead.h" #include "nsHttpTransaction.h" #include "nsHttpAuthCache.h" -#include "nsHttpPipeline.h" #include "nsStandardURL.h" #include "nsIHttpChannel.h" #include "nsIHttpNotify.h" @@ -72,7 +71,7 @@ #ifdef DEBUG // defined by the socket transport service while active -extern PRThread *NS_SOCKET_THREAD; +extern PRThread *gSocketThread; #endif static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); @@ -100,10 +99,10 @@ static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID); // nsHttpHandler //----------------------------------------------------------------------------- -nsHttpHandler *nsHttpHandler::mGlobalInstance = 0; +nsHttpHandler *gHttpHandler = nsnull; nsHttpHandler::nsHttpHandler() - : mAuthCache(nsnull) + : mConnMgr(nsnull) , mHttpVersion(NS_HTTP_VERSION_1_1) , mProxyHttpVersion(NS_HTTP_VERSION_1_1) , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE) @@ -120,10 +119,10 @@ nsHttpHandler::nsHttpHandler() , mRedirectionLimit(10) , mLastUniqueID(NowInSeconds()) , mSessionStartTime(0) - , mActiveConnections(0) - , mIdleConnections(0) - , mTransactionQ(0) - , mConnectionLock(nsnull) + //, mActiveConnections(0) + //, mIdleConnections(0) + //, mTransactionQ(0) + //, mConnectionLock(nsnull) , mUserAgentIsDirty(PR_TRUE) , mUseCache(PR_TRUE) , mSendSecureXSiteReferrer(PR_TRUE) @@ -134,8 +133,8 @@ nsHttpHandler::nsHttpHandler() LOG(("Creating nsHttpHandler [this=%x].\n", this)); - NS_ASSERTION(!mGlobalInstance, "HTTP handler already created!"); - mGlobalInstance = this; + NS_ASSERTION(!gHttpHandler, "HTTP handler already created!"); + gHttpHandler = this; } nsHttpHandler::~nsHttpHandler() @@ -145,26 +144,15 @@ nsHttpHandler::~nsHttpHandler() LOG(("Deleting nsHttpHandler [this=%x]\n", this)); + // make sure the connection manager is shutdown + if (mConnMgr) { + mConnMgr->Shutdown(); + NS_RELEASE(mConnMgr); + } + nsHttp::DestroyAtomTable(); - // If the |nsHttpConnection| objects stop holding references to this - // object (as was done to fix bug 143821), then the code from - // |Observe| to call |DropConnections| should probably move back - // here. - NS_ASSERTION(!mActiveConnections.Count() && !mIdleConnections.Count(), - "Connections should own reference to nsHttpHandler"); - - if (mAuthCache) { - delete mAuthCache; - mAuthCache = nsnull; - } - - if (mConnectionLock) { - PR_DestroyLock(mConnectionLock); - mConnectionLock = nsnull; - } - - mGlobalInstance = nsnull; + gHttpHandler = nsnull; } nsresult @@ -180,9 +168,9 @@ nsHttpHandler::Init() return rv; } - mConnectionLock = PR_NewLock(); - if (!mConnectionLock) - return NS_ERROR_OUT_OF_MEMORY; + //mConnectionLock = PR_NewLock(); + //if (!mConnectionLock) + // return NS_ERROR_OUT_OF_MEMORY; InitUserAgentComponents(); @@ -198,7 +186,7 @@ nsHttpHandler::Init() pbi->AddObserver(INTL_ACCEPT_CHARSET, this, PR_TRUE); pbi->AddObserver(NETWORK_ENABLEIDN, this, PR_TRUE); } - PrefsChanged(prefBranch); + PrefsChanged(prefBranch, nsnull); } #if DEBUG @@ -221,10 +209,10 @@ nsHttpHandler::Init() mSessionStartTime = NowInSeconds(); - mAuthCache = new nsHttpAuthCache(); - if (!mAuthCache) - return NS_ERROR_OUT_OF_MEMORY; - rv = mAuthCache->Init(); + rv = mAuthCache.Init(); + if (NS_FAILED(rv)) return rv; + + rv = InitConnectionMgr(); if (NS_FAILED(rv)) return rv; // Startup the http category @@ -237,19 +225,60 @@ nsHttpHandler::Init() do_GetService("@mozilla.org/observer-service;1", &rv); if (observerSvc) { observerSvc->AddObserver(this, "profile-change-net-teardown", PR_TRUE); + observerSvc->AddObserver(this, "profile-change-net-restore", PR_TRUE); observerSvc->AddObserver(this, "session-logout", PR_TRUE); observerSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE); - observerSvc->AddObserver(this, "network:offline-status-changed", PR_TRUE); + } + + StartPruneDeadConnectionsTimer(); + return NS_OK; +} + +nsresult +nsHttpHandler::InitConnectionMgr() +{ + nsresult rv; + + if (!mConnMgr) { + mConnMgr = new nsHttpConnectionMgr(); + if (!mConnMgr) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mConnMgr); } + rv = mConnMgr->Init(mMaxConnections, + mMaxConnectionsPerServer, + mMaxConnectionsPerServer, + mMaxPersistentConnectionsPerServer, + mMaxPersistentConnectionsPerProxy, + mMaxRequestDelay, + mMaxPipelinedRequests); + return rv; +} + +void +nsHttpHandler::StartPruneDeadConnectionsTimer() +{ + LOG(("nsHttpHandler::StartPruneDeadConnectionsTimer\n")); + mTimer = do_CreateInstance("@mozilla.org/timer;1"); + NS_ASSERTION(mTimer, "no timer"); // failure to create a timer is not a fatal error, but idle connections // may not be cleaned up as aggressively. if (mTimer) - mTimer->InitWithFuncCallback(DeadConnectionCleanupCB, this, 15*1000, // 15 seconds - nsITimer::TYPE_REPEATING_SLACK); - - return NS_OK; + mTimer->Init(this, 15*1000, // every 15 seconds + nsITimer::TYPE_REPEATING_SLACK); +} + +void +nsHttpHandler::StopPruneDeadConnectionsTimer() +{ + LOG(("nsHttpHandler::StopPruneDeadConnectionsTimer\n")); + + if (mTimer) { + mTimer->Cancel(); + mTimer = 0; + } } nsresult @@ -369,133 +398,6 @@ nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy, return NS_OK; } -// may be called from any thread -nsresult -nsHttpHandler::InitiateTransaction(nsHttpTransaction *trans, - nsHttpConnectionInfo *ci) -{ - LOG(("nsHttpHandler::InitiateTransaction\n")); - - NS_ENSURE_ARG_POINTER(trans); - NS_ENSURE_ARG_POINTER(ci); - - PR_Lock(mConnectionLock); - - nsHttpConnection *conn = nsnull; - nsresult rv; - - GetConnection_Locked(ci, trans->Capabilities(), &conn); - if (!conn) { - rv = EnqueueTransaction_Locked(trans, ci); - PR_Unlock(mConnectionLock); - } - else { - rv = DispatchTransaction_Locked(trans, trans->Capabilities(), conn); - NS_RELEASE(conn); - } - return rv; -} - -// called from the socket thread -nsresult -nsHttpHandler::ReclaimConnection(nsHttpConnection *conn) -{ - NS_ENSURE_ARG_POINTER(conn); - NS_ASSERTION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); - - PR_Lock(mConnectionLock); - - PRBool reusable = conn->CanReuse(); - - LOG(("nsHttpHandler::ReclaimConnection [conn=%x(%s:%d) keep-alive=%d]\n", - conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port(), reusable)); - - // remove connection from the active connection list - mActiveConnections.RemoveElement(conn); - - if (reusable) { - LOG(("adding connection to idle list [conn=%x]\n", conn)); - // hold onto this connection in the idle list. we push it - // to the end of the list so as to ensure that we'll visit - // older connections first before getting to this one. - mIdleConnections.AppendElement(conn); - } - else { - LOG(("closing connection: connection can't be reused\n")); - NS_RELEASE(conn); - } - - LOG(("active connection count is now %u\n", mActiveConnections.Count())); - - ProcessTransactionQ_Locked(); - return NS_OK; -} - -nsresult -nsHttpHandler::PurgeDeadConnections() -{ - nsAutoLock lock(mConnectionLock); - // Loop from end to beginning because of |RemoveElement| calls. - for (PRInt32 i = mIdleConnections.Count() - 1; i >= 0; --i) { - nsHttpConnection *conn = (nsHttpConnection *) mIdleConnections[i]; - if (conn && !conn->CanReuse()) { - // Dead and idle connection; purge it - mIdleConnections.RemoveElementAt(i); - NS_RELEASE(conn); - } - } - return NS_OK; -} - -// called from the socket thread (see nsHttpConnection::OnDataAvailable) -nsresult -nsHttpHandler::ProcessTransactionQ() -{ - LOG(("nsHttpHandler::ProcessTransactionQ\n")); - NS_ASSERTION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); - - PR_Lock(mConnectionLock); - - // conn is no longer keep-alive, so we may be able to initiate - // a pending transaction to the same host. - ProcessTransactionQ_Locked(); - return NS_OK; -} - -// called from any thread, by the implementation of nsHttpTransaction::Cancel -nsresult -nsHttpHandler::CancelTransaction(nsHttpTransaction *trans, nsresult status) -{ - nsAHttpConnection *conn; - - LOG(("nsHttpHandler::CancelTransaction [trans=%x status=%x]\n", - trans, status)); - - NS_ENSURE_ARG_POINTER(trans); - - // we need to be inside the connection lock in order to know whether - // or not this transaction has an associated connection. otherwise, - // we'd have a race condition (see bug 85822). - { - nsAutoLock lock(mConnectionLock); - - conn = trans->Connection(); - if (conn) - NS_ADDREF(conn); // make sure the connection stays around. - else - RemovePendingTransaction_Locked(trans); - } - - if (conn) { - conn->OnTransactionComplete(trans, status); - NS_RELEASE(conn); - } - else - trans->OnStopTransaction(status); - - return NS_OK; -} - nsresult nsHttpHandler::GetProxyObjectManager(nsIProxyObjectManager **result) { @@ -656,391 +558,6 @@ nsHttpHandler::UserAgent() return mUserAgent; } -nsresult -nsHttpHandler::GetConnection_Locked(nsHttpConnectionInfo *ci, - PRUint8 caps, - nsHttpConnection **result) -{ - nsresult rv; - - LOG(("nsHttpHandler::GetConnection_Locked\n")); - - *result = nsnull; - - if (AtActiveConnectionLimit_Locked(ci, caps)) - return NS_ERROR_FAILURE; - - nsHttpConnection *conn = nsnull; - - if (caps & NS_HTTP_ALLOW_KEEPALIVE) { - // search the idle connection list - PRInt32 i; - for (i=0; i> comparing against idle connection [conn=%x host=%s:%d]\n", - conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port())); - - // we check if the connection can be reused before even checking if it - // is a "matching" connection. this is how we keep the idle connection - // list fresh. we could alternatively use some sort of timer for this. - if (!conn->CanReuse()) { - LOG((" dropping stale connection: [conn=%x]\n", conn)); - mIdleConnections.RemoveElementAt(i); - i--; - NS_RELEASE(conn); - } - else if (conn->ConnectionInfo()->Equals(ci)) { - LOG((" reusing connection [conn=%x]\n", conn)); - mIdleConnections.RemoveElementAt(i); - i--; - break; - } - conn = nsnull; - } - } - - if (!conn) { - LOG((">> creating new connection...\n")); - NS_NEWXPCOM(conn, nsHttpConnection); - if (!conn) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(conn); - - rv = conn->Init(ci, mMaxRequestDelay); - if (NS_FAILED(rv)) { - NS_RELEASE(conn); - return rv; - } - - // We created a new connection - // If idle + active connections > max connections, then purge the oldest idle one. - if (mIdleConnections.Count() + mActiveConnections.Count() > mMaxConnections) { - LOG(("Created a new connection and popping oldest one [idlecount=%d activecount=%d maxConn=%d]\n", - mIdleConnections.Count(), mActiveConnections.Count(), mMaxConnections)); - NS_ASSERTION(mIdleConnections.Count() > 0, "idle connection list is empty"); - if (mIdleConnections.Count() > 0) { - nsHttpConnection *conn = (nsHttpConnection *) mIdleConnections[0]; - NS_ASSERTION(conn, "mIdleConnections[0] is null but count > 0"); - if (conn) { - LOG(("deleting connection [conn=%x host=%s:%d]\n", - conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port())); - mIdleConnections.RemoveElementAt(0); - NS_RELEASE(conn); - } - } - } - } - else { - // Update the connectionInfo (bug 94038) - conn->ConnectionInfo()->SetOriginServer(ci->Host(), ci->Port()); - } - - *result = conn; - return NS_OK; -} - -nsresult -nsHttpHandler::EnqueueTransaction_Locked(nsHttpTransaction *trans, - nsHttpConnectionInfo *ci) -{ - LOG(("nsHttpHandler::EnqueueTransaction_Locked [trans=%x]\n", trans)); - - nsPendingTransaction *pt = new nsPendingTransaction(trans, ci); - if (!pt) - return NS_ERROR_OUT_OF_MEMORY; - - mTransactionQ.AppendElement(pt); - - LOG((">> transaction queue contains %u elements\n", mTransactionQ.Count())); - return NS_OK; -} - -// dispatch this transaction, return unlocked -nsresult -nsHttpHandler::DispatchTransaction_Locked(nsAHttpTransaction *trans, - PRUint8 transCaps, - nsHttpConnection *conn) -{ - nsresult rv; - - LOG(("nsHttpHandler::DispatchTransaction_Locked [trans=%x conn=%x]\n", - trans, conn)); - - // assign the connection to the transaction. - trans->SetConnection(conn); - - // consider this connection active, even though it may fail. - mActiveConnections.AppendElement(conn); - - // handler now owns a reference to this connection - NS_ADDREF(conn); - - // we must not hold the connection lock while making the call to - // SetTransaction, as it could lead to deadlocks. - PR_Unlock(mConnectionLock); - rv = conn->SetTransaction(trans, transCaps); - - if (NS_FAILED(rv)) { - LOG(("nsHttpConnection::SetTransaction failed [rv=%x]\n", rv)); - nsAutoLock lock(mConnectionLock); - // the connection may already have been removed from the - // active connection list. - if (mActiveConnections.RemoveElement(conn)) - NS_RELEASE(conn); - } - return rv; -} - -// try to dispatch a pending transaction, return unlocked -void -nsHttpHandler::ProcessTransactionQ_Locked() -{ - LOG(("nsHttpHandler::ProcessTransactionQ_Locked\n")); - - nsPendingTransaction *pt = nsnull; - nsHttpConnection *conn = nsnull; - - // - // step 1: locate a pending transaction that can be processed - // - PRInt32 i; - for (i=0; iConnectionInfo(), - pt->Transaction()->Capabilities(), - &conn); - if (conn) - break; - } - if (!conn) { - LOG((">> unable to process transaction queue at this time\n")); - // the caller expects us to unlock before returning... - PR_Unlock(mConnectionLock); - return; - } - - // - // step 2: remove i'th pending transaction from the pending transaction - // queue. we'll put it back if there is a problem dispatching it. - // - // the call to DispatchTransaction_Locked will temporarily leave - // mConnectionLock, so this step is crucial as it ensures that our - // state is completely defined on the stack (not in member variables). - // - mTransactionQ.RemoveElementAt(i); - - // - // step 3: determine if we can pipeline any other transactions along with - // this transaction. if pipelining is disabled or there are no other - // transactions that can be sent with this transaction, then simply send - // this transaction. - // - nsAHttpTransaction *trans = pt->Transaction(); - PRUint8 caps = pt->Transaction()->Capabilities(); - nsPipelineEnqueueState pipelineState; - if (conn->SupportsPipelining() && - caps & NS_HTTP_ALLOW_PIPELINING && - BuildPipeline_Locked(pipelineState, - pt->Transaction(), - pt->ConnectionInfo())) { - // ok... let's rock! - trans = pipelineState.Transaction(); - caps = pipelineState.TransactionCaps(); - NS_ASSERTION(trans, "no transaction"); - } -#if defined(PR_LOGGING) - else - LOG(("no pipelining [because-of-server=%d because-of-caps=%d]\n", - conn->SupportsPipelining() == PR_FALSE, - caps & NS_HTTP_ALLOW_PIPELINING == PR_FALSE)); -#endif - - // - // step 4: dispatch this transaction - // - nsresult rv = DispatchTransaction_Locked(trans, caps, conn); - - // we're no longer inside mConnectionLock - - // - // step 5: handle errors / cleanup - // - if (NS_FAILED(rv)) { - LOG((">> DispatchTransaction_Locked failed [rv=%x]\n", rv)); - nsAutoLock lock(mConnectionLock); - // there must have been something wrong with the connection, - // requeue... we'll try again later. - if (caps & NS_HTTP_ALLOW_PIPELINING) - PipelineFailed_Locked(pipelineState); - mTransactionQ.AppendElement(pt); - } - else - delete pt; - pipelineState.Cleanup(); - NS_RELEASE(conn); -} - -// we're at the active connection limit if any one of the following conditions is true: -// (1) at max-connections -// (2) keep-alive enabled and at max-persistent-connections-per-server/proxy -// (3) keep-alive disabled and at max-connections-per-server -PRBool -nsHttpHandler::AtActiveConnectionLimit_Locked(nsHttpConnectionInfo *ci, PRUint8 caps) -{ - LOG(("nsHttpHandler::AtActiveConnectionLimit_Locked [host=%s:%d caps=%x]\n", - ci->Host(), ci->Port(), caps)); - - // use >= just to be safe - if (mActiveConnections.Count() >= mMaxConnections) - return PR_TRUE; - - nsHttpConnection *conn; - PRUint8 totalCount = 0, persistentCount = 0; - PRInt32 i; - for (i=0; i> comparing against active connection [conn=%x host=%s:%d]\n", - conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port())); - if (conn->ConnectionInfo()->Equals(ci)) { - totalCount++; - if (conn->IsKeepAlive()) - persistentCount++; - } - } - - LOG((" total-count=%u, persistent-count=%u\n", - PRUint32(totalCount), PRUint32(persistentCount))); - - PRUint8 maxPersistentConnections = - ci->UsingHttpProxy() ? mMaxPersistentConnectionsPerProxy - : mMaxPersistentConnectionsPerServer; - - // use >= just to be safe - return (totalCount >= mMaxConnectionsPerServer) || - ((caps & NS_HTTP_ALLOW_KEEPALIVE) && - (persistentCount >= maxPersistentConnections)); -} - -nsresult -nsHttpHandler::RemovePendingTransaction_Locked(nsHttpTransaction *trans) -{ - LOG(("nsHttpHandler::RemovePendingTransaction_Locked [trans=%x]\n", trans)); - - NS_ENSURE_ARG_POINTER(trans); - - nsPendingTransaction *pt = nsnull; - PRInt32 i; - for (i=0; iTransaction() == trans) { - mTransactionQ.RemoveElementAt(i); - delete pt; - return NS_OK; - } - } - - NS_WARNING("transaction not in pending queue"); - return NS_ERROR_NOT_AVAILABLE; -} - -void -nsHttpHandler::DeadConnectionCleanupCB(nsITimer *timer, void *closure) -{ - nsHttpHandler *self = NS_STATIC_CAST(nsHttpHandler*, closure); - if (self) - self->PurgeDeadConnections(); -} - -void -nsHttpHandler::DropConnections(nsVoidArray &connections) -{ - nsHttpConnection *conn; - PRInt32 i; - for (i=0; iDropTransport(); - NS_RELEASE(conn); - } - connections.Clear(); -} - -PRBool -nsHttpHandler::BuildPipeline_Locked(nsPipelineEnqueueState &state, - nsHttpTransaction *firstTrans, - nsHttpConnectionInfo *ci) -{ - if (mMaxPipelinedRequests < 2) - return PR_FALSE; - - LOG(("BuildPipeline_Locked [trans=%x]\n", firstTrans)); - - // - // need to search the pending transaction list for other transactions - // that can be pipelined along with |firstTrans|. - // - nsresult rv = NS_ERROR_FAILURE; // by default, nothing to pipeline - PRUint8 numAppended = 0; - PRInt32 i = 0; - while (i < mTransactionQ.Count()) { - nsPendingTransaction *pt = (nsPendingTransaction *) mTransactionQ[i]; - if (pt->Transaction()->Capabilities() & (NS_HTTP_ALLOW_KEEPALIVE | - NS_HTTP_ALLOW_PIPELINING) && - pt->ConnectionInfo()->Equals(ci)) { - - // - // ok, we can add this transaction to our pipeline - // - if (numAppended == 0) { - rv = state.Init(firstTrans); - if (NS_FAILED(rv)) break; - } - rv = state.AppendTransaction(pt); - if (NS_FAILED(rv)) break; - - // - // ok, remove the transaction from the pending queue; next time - // around the loop we'll still check the i-th element :-) - // - mTransactionQ.RemoveElementAt(i); - - // - // we may have reached the pipelined requests limit... - // - if (++numAppended == (mMaxPipelinedRequests - 1)) - break; - } - else - i++; // advance to next pending transaction - } - if (NS_FAILED(rv)) { - LOG((" unable to pipeline any transactions with this one\n")); - state.Cleanup(); - return PR_FALSE; - } - LOG((" pipelined %u transactions\n", numAppended + 1)); - return PR_TRUE; -} - -void -nsHttpHandler::PipelineFailed_Locked(nsPipelineEnqueueState &state) -{ - if ((mMaxPipelinedRequests < 2) || !state.HasPipeline()) - return; - - LOG(("PipelineFailed_Locked\n")); - - // need to put any "appended" transactions back on the queue - PRInt32 i = 0; - while (i < state.NumAppendedTrans()) { - mTransactionQ.AppendElement(state.GetAppendedTrans(i)); - i++; - } - state.DropAppendedTrans(); -} - void nsHttpHandler::BuildUserAgent() { @@ -1905,15 +1422,26 @@ nsHttpHandler::NewProxiedChannel(nsIURI *uri, nsresult rv; - // select proxy caps if using a non-transparent proxy - PRInt8 caps = mCapabilities; - if (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http")) { - // SSL tunneling should not use proxy settings - PRBool isHTTPS; - rv = uri->SchemeIs("https", &isHTTPS); - if (NS_FAILED(rv)) return rv; - if (!isHTTPS) - caps = mProxyCapabilities; + PRBool https; + rv = uri->SchemeIs("https", &https); + if (NS_FAILED(rv)) return rv; + + // select proxy caps if using a non-transparent proxy. SSL tunneling + // should not use proxy settings. + PRInt8 caps; + if (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http") && !https) + caps = mProxyCapabilities; + else + caps = mCapabilities; + + if (https) { + // HACK: make sure PSM gets initialized on the main thread. + nsCOMPtr spserv = + do_GetService(kSocketProviderServiceCID); + if (spserv) { + nsCOMPtr provider; + spserv->GetSocketProvider("ssl", getter_AddRefs(provider)); + } } rv = httpChannel->Init(uri, caps, proxyInfo); @@ -2089,140 +1617,51 @@ nsHttpHandler::Observe(nsISupports *subject, { LOG(("nsHttpHandler::Observe [topic=\"%s\")]\n", topic)); - if (!nsCRT::strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { + if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) { nsCOMPtr prefBranch = do_QueryInterface(subject); if (prefBranch) PrefsChanged(prefBranch, NS_ConvertUCS2toUTF8(data).get()); + + // XXX should probably shutdown and init the conn mgr. } - else if (!nsCRT::strcmp(topic, "profile-change-net-teardown") || - !nsCRT::strcmp(topic, "session-logout") || - !nsCRT::strcmp(topic, "network:offline-status-changed")) { + else if (strcmp(topic, "profile-change-net-teardown") == 0 || + strcmp(topic, "session-logout") == 0 || + strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - // ignore online notification - if (!nsCRT::strcmp(topic, "network:offline-status-changed") && - NS_LITERAL_STRING("online").Equals(data)) - return NS_OK; + // kill off the "prune dead connections" timer + StopPruneDeadConnectionsTimer(); // clear cache of all authentication credentials. - if (mAuthCache) - mAuthCache->ClearAll(); + mAuthCache.ClearAll(); - { - nsAutoLock lock(mConnectionLock); - - LOG((" http logout [idle-count=%u active-count=%u]\n", - mIdleConnections.Count(), - mActiveConnections.Count())); - - // kill idle connections; these sockets could be holding onto other - // resources that need to be freed (e.g., NSS file descriptors). - DropConnections(mIdleConnections); - - // mark all active connections as not reusable. this prevents any - // active connections from finding their way onto the idle - // connection list. - nsHttpConnection *conn; - for (PRInt32 i=0; iDontReuse(); - } - } + // ensure connection manager is shutdown + if (mConnMgr) + mConnMgr->Shutdown(); // need to reset the session start time since cache validation may // depend on this value. mSessionStartTime = NowInSeconds(); } - else if (!nsCRT::strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - if (mTimer) { - mTimer->Cancel(); - mTimer = 0; - } + else if (strcmp(topic, "profile-change-net-restore") == 0) { + // initialize connection manager + InitConnectionMgr(); - // If we don't call DropConnections here, we'll never get - // destroyed, since we own a reference to the connections in - // these arrays and they own a reference back to us. - { - nsAutoLock lock(mConnectionLock); - - LOG(("dropping active connections...\n")); - DropConnections(mActiveConnections); - - LOG(("dropping idle connections...\n")); - DropConnections(mIdleConnections); - } + // restart the "prune dead connections" timer + StartPruneDeadConnectionsTimer(); + } + else if (strcmp(topic, "timer-callback") == 0) { + // prune dead connections +#ifdef DEBUG + nsCOMPtr timer = do_QueryInterface(subject); + NS_ASSERTION(timer == mTimer, "unexpected timer-callback"); +#endif + if (mConnMgr) + mConnMgr->PruneDeadConnections(); } return NS_OK; } -//----------------------------------------------------------------------------- -// nsHttpHandler::nsPendingTransaction -//----------------------------------------------------------------------------- - -nsHttpHandler:: -nsPendingTransaction::nsPendingTransaction(nsHttpTransaction *trans, - nsHttpConnectionInfo *ci) - : mTransaction(trans) - , mConnectionInfo(ci) - , mBusy(0) -{ - LOG(("Creating nsPendingTransaction @%x\n", this)); - - NS_PRECONDITION(mTransaction, "null transaction"); - NS_PRECONDITION(mConnectionInfo, "null connection info"); - - NS_ADDREF(mTransaction); - NS_ADDREF(mConnectionInfo); -} - -nsHttpHandler:: -nsPendingTransaction::~nsPendingTransaction() -{ - LOG(("Destroying nsPendingTransaction @%x\n", this)); - - NS_RELEASE(mTransaction); - NS_RELEASE(mConnectionInfo); -} - -//----------------------------------------------------------------------------- -// nsHttpHandler::nsPipelineEnqueueState -//----------------------------------------------------------------------------- - -nsresult nsHttpHandler:: -nsPipelineEnqueueState::Init(nsHttpTransaction *firstTrans) -{ - NS_ASSERTION(mPipeline == nsnull, "already initialized"); - - mPipeline = new nsHttpPipeline; - if (!mPipeline) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(mPipeline); - - return mPipeline->Init(firstTrans); -} - -nsresult nsHttpHandler:: -nsPipelineEnqueueState::AppendTransaction(nsPendingTransaction *pt) -{ - nsresult rv = mPipeline->AppendTransaction(pt->Transaction()); - if (NS_FAILED(rv)) return rv; - - // remember this pending transaction object - mAppendedTrans.AppendElement(pt); - return NS_OK; -} - -void nsHttpHandler:: -nsPipelineEnqueueState::Cleanup() -{ - NS_IF_RELEASE(mPipeline); - - // free any appended pending transaction objects - for (PRInt32 i=0; i < mAppendedTrans.Count(); i++) - delete GetAppendedTrans(i); - mAppendedTrans.Clear(); -} - //----------------------------------------------------------------------------- // nsHttpsHandler implementation //----------------------------------------------------------------------------- @@ -2259,7 +1698,7 @@ nsHttpsHandler::GetDefaultPort(PRInt32 *aPort) NS_IMETHODIMP nsHttpsHandler::GetProtocolFlags(PRUint32 *aProtocolFlags) { - return nsHttpHandler::get()->GetProtocolFlags(aProtocolFlags); + return gHttpHandler->GetProtocolFlags(aProtocolFlags); } NS_IMETHODIMP @@ -2268,13 +1707,13 @@ nsHttpsHandler::NewURI(const nsACString &aSpec, nsIURI *aBaseURI, nsIURI **_retval) { - return nsHttpHandler::get()->NewURI(aSpec, aOriginCharset, aBaseURI, _retval); + return gHttpHandler->NewURI(aSpec, aOriginCharset, aBaseURI, _retval); } NS_IMETHODIMP nsHttpsHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval) { - return nsHttpHandler::get()->NewChannel(aURI, _retval); + return gHttpHandler->NewChannel(aURI, _retval); } NS_IMETHODIMP diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHandler.h b/mozilla/netwerk/protocol/http/src/nsHttpHandler.h index 0097ace5a33..7de3a43b99b 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHandler.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpHandler.h @@ -25,7 +25,16 @@ #define nsHttpHandler_h__ #include "nsHttp.h" -#include "nsHttpPipeline.h" +#include "nsHttpAuthCache.h" +#include "nsHttpConnection.h" +#include "nsHttpConnectionMgr.h" + +#include "nsXPIDLString.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsVoidArray.h" + #include "nsIHttpProtocolHandler.h" #include "nsIProtocolProxyService.h" #include "nsIIOService.h" @@ -37,19 +46,12 @@ #include "nsICacheSession.h" #include "nsIEventQueueService.h" #include "nsIMIMEService.h" -#include "nsXPIDLString.h" -#include "nsString.h" -#include "nsCOMPtr.h" -#include "nsWeakReference.h" -#include "nsVoidArray.h" #include "nsIIDNService.h" #include "nsITimer.h" -class nsHttpConnection; class nsHttpConnectionInfo; class nsHttpHeaderArray; class nsHttpTransaction; -class nsHttpAuthCache; class nsAHttpTransaction; class nsIHttpChannel; class nsIPrefBranch; @@ -72,9 +74,6 @@ public: nsHttpHandler(); virtual ~nsHttpHandler(); - // Returns a pointer to the one and only HTTP handler - static nsHttpHandler *get() { return mGlobalInstance; } - nsresult Init(); nsresult AddStandardRequestHeaders(nsHttpHeaderArray *, PRUint8 capabilities, @@ -93,7 +92,8 @@ public: const char *DefaultSocketType() { return mDefaultSocketType.get(); /* ok to return null */ } nsIIDNService *IDNConverter() { return mIDNConverter; } - nsHttpAuthCache *AuthCache() { return mAuthCache; } + nsHttpAuthCache *AuthCache() { return &mAuthCache; } + nsHttpConnectionMgr *ConnMgr() { return mConnMgr; } // cache support nsresult GetCacheSession(nsCacheStoragePolicy, nsICacheSession **); @@ -113,21 +113,29 @@ public: // Called to kick-off a new transaction, by default the transaction // will be put on the pending transaction queue if it cannot be // initiated at this time. Callable from any thread. - nsresult InitiateTransaction(nsHttpTransaction *, nsHttpConnectionInfo *); + nsresult InitiateTransaction(nsHttpTransaction *trans) + { + return mConnMgr->AddTransaction(trans); + } // Called to cancel a transaction, which may or may not be assigned to // a connection. Callable from any thread. - nsresult CancelTransaction(nsHttpTransaction *, nsresult status); + nsresult CancelTransaction(nsHttpTransaction *trans, nsresult reason) + { + return mConnMgr->CancelTransaction(trans, reason); + } // Called when a connection is done processing a transaction. Callable // from any thread. - nsresult ReclaimConnection(nsHttpConnection *); + nsresult ReclaimConnection(nsHttpConnection *conn) + { + return mConnMgr->ReclaimConnection(conn); + } - // Called when a connection has been busy with a single transaction for - // longer than mMaxRequestDelay. - nsresult ProcessTransactionQ(); - - nsresult PurgeDeadConnections(); + nsresult ProcessPendingQ(nsHttpConnectionInfo *cinfo) + { + return mConnMgr->ProcessPendingQ(cinfo); + } // // The HTTP handler caches pointers to specific XPCOM services, and @@ -146,84 +154,14 @@ public: // Called by the channel once headers are available nsresult OnExamineResponse(nsIHttpChannel *); -public: /* internal */ - // - // Transactions that have not yet been assigned to a connection are kept - // in a queue of nsPendingTransaction objects. nsPendingTransaction - // implements nsAHttpTransactionSink to handle transaction Cancellation. - // - class nsPendingTransaction - { - public: - nsPendingTransaction(nsHttpTransaction *, nsHttpConnectionInfo *); - ~nsPendingTransaction(); - - nsHttpTransaction *Transaction() { return mTransaction; } - nsHttpConnectionInfo *ConnectionInfo() { return mConnectionInfo; } - - PRBool IsBusy() { return mBusy; } - void SetBusy(PRBool value) { mBusy = value; } - - private: - nsHttpTransaction *mTransaction; - nsHttpConnectionInfo *mConnectionInfo; - PRPackedBool mBusy; - }; - - // - // Data structure used to hold information used during the construction of - // a transaction pipeline. - // - class nsPipelineEnqueueState - { - public: - nsPipelineEnqueueState() : mPipeline(nsnull) {} - ~nsPipelineEnqueueState() { Cleanup(); } - - nsresult Init(nsHttpTransaction *); - nsresult AppendTransaction(nsPendingTransaction *); - void Cleanup(); - - nsAHttpTransaction *Transaction() { return mPipeline; } - PRUint8 TransactionCaps() { return NS_HTTP_ALLOW_KEEPALIVE | NS_HTTP_ALLOW_PIPELINING; } - PRBool HasPipeline() { return (mPipeline != nsnull); } - nsPendingTransaction *GetAppendedTrans(PRInt32 i) { return (nsPendingTransaction *) mAppendedTrans[i]; } - PRInt32 NumAppendedTrans() { return mAppendedTrans.Count(); } - void DropAppendedTrans() { mAppendedTrans.Clear(); } - - private: - nsHttpPipeline *mPipeline; - nsAutoVoidArray mAppendedTrans; - }; - private: - // - // Connection management methods - // - nsresult GetConnection_Locked(nsHttpConnectionInfo *, PRUint8 caps, nsHttpConnection **); - nsresult EnqueueTransaction_Locked(nsHttpTransaction *, nsHttpConnectionInfo *); - nsresult DispatchTransaction_Locked(nsAHttpTransaction *, PRUint8 caps, nsHttpConnection *); // unlocked on return - void ProcessTransactionQ_Locked(); // unlocked on return - PRBool AtActiveConnectionLimit_Locked(nsHttpConnectionInfo *, PRUint8 caps); - nsresult RemovePendingTransaction_Locked(nsHttpTransaction *); - - void DropConnections(nsVoidArray &); - - // - // Pipelining methods - these may fail silently, and that's ok! - // - PRBool BuildPipeline_Locked(nsPipelineEnqueueState &, - nsHttpTransaction *, - nsHttpConnectionInfo *); - void PipelineFailed_Locked(nsPipelineEnqueueState &); - // // Useragent/prefs helper methods // void BuildUserAgent(); void InitUserAgentComponents(); - void PrefsChanged(nsIPrefBranch *prefs, const char *pref = nsnull); + void PrefsChanged(nsIPrefBranch *prefs, const char *pref); void GetPrefBranch(nsIPrefBranch **); nsresult SetAccept(const char *); @@ -232,10 +170,13 @@ private: nsresult SetAcceptCharsets(const char *); // timer callback for cleansing the idle connection list - static void DeadConnectionCleanupCB(nsITimer *, void *); + //static void DeadConnectionCleanupCB(nsITimer *, void *); + + nsresult InitConnectionMgr(); + void StartPruneDeadConnectionsTimer(); + void StopPruneDeadConnectionsTimer(); private: - static nsHttpHandler *mGlobalInstance; // cached services nsCOMPtr mIOService; @@ -248,7 +189,10 @@ private: nsCOMPtr mTimer; // the authentication credentials cache - nsHttpAuthCache *mAuthCache; + nsHttpAuthCache mAuthCache; + + // the connection manager + nsHttpConnectionMgr *mConnMgr; // // prefs @@ -284,12 +228,6 @@ private: nsCOMPtr mCacheSession_MEM; PRUint32 mLastUniqueID; PRUint32 mSessionStartTime; - - // connection management - nsVoidArray mActiveConnections; // list of nsHttpConnection objects - nsVoidArray mIdleConnections; // list of nsHttpConnection objects - nsVoidArray mTransactionQ; // list of nsPendingTransaction objects - PRLock *mConnectionLock; // protect connection lists // useragent components nsXPIDLCString mAppName; @@ -316,6 +254,10 @@ private: PRPackedBool mSendSecureXSiteReferrer; }; +//----------------------------------------------------------------------------- + +extern nsHttpHandler *gHttpHandler; + //----------------------------------------------------------------------------- // nsHttpsHandler - thin wrapper to distinguish the HTTP handler from the // HTTPS handler (even though they share the same impl). @@ -330,8 +272,8 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIPROTOCOLHANDLER - NS_FORWARD_NSIPROXIEDPROTOCOLHANDLER (nsHttpHandler::get()->) - NS_FORWARD_NSIHTTPPROTOCOLHANDLER (nsHttpHandler::get()->) + NS_FORWARD_NSIPROXIEDPROTOCOLHANDLER (gHttpHandler->) + NS_FORWARD_NSIHTTPPROTOCOLHANDLER (gHttpHandler->) nsHttpsHandler() { } virtual ~nsHttpsHandler() { } diff --git a/mozilla/netwerk/protocol/http/src/nsHttpPipeline.cpp b/mozilla/netwerk/protocol/http/src/nsHttpPipeline.cpp index 56cee884192..5bb5652dbda 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpPipeline.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpPipeline.cpp @@ -21,10 +21,12 @@ * Darin Fisher (original author) */ +#include #include "nsHttp.h" #include "nsHttpPipeline.h" +#include "nsHttpHandler.h" #include "nsIRequest.h" -#include "nsISocketTransportService.h" +#include "nsISocketTransport.h" #include "nsIStringStream.h" #include "nsIPipe.h" #include "nsCOMPtr.h" @@ -34,109 +36,42 @@ #ifdef DEBUG #include "prthread.h" // defined by the socket transport service while active -extern PRThread *NS_SOCKET_THREAD; +extern PRThread *gSocketThread; #endif //----------------------------------------------------------------------------- -// nsHttpPipeline::nsInputStreamWrapper +// nsHttpPushBackWriter //----------------------------------------------------------------------------- -nsHttpPipeline:: -nsInputStreamWrapper::nsInputStreamWrapper(const char *data, PRUint32 dataLen) - : mData(data) - , mDataLen(dataLen) - , mDataPos(0) +class nsHttpPushBackWriter : public nsAHttpSegmentWriter { -} +public: + nsHttpPushBackWriter(const char *buf, PRUint32 bufLen) + : mBuf(buf) + , mBufLen(bufLen) + { } + virtual ~nsHttpPushBackWriter() {} -nsHttpPipeline:: -nsInputStreamWrapper::~nsInputStreamWrapper() -{ -} + nsresult OnWriteSegment(char *buf, PRUint32 count, PRUint32 *countWritten) + { + if (mBufLen == 0) + return NS_BASE_STREAM_CLOSED; -// this thing is going to be allocated on the stack -NS_IMETHODIMP_(nsrefcnt) nsHttpPipeline:: -nsInputStreamWrapper::AddRef() -{ - return 1; -} + if (count > mBufLen) + count = mBufLen; -NS_IMETHODIMP_(nsrefcnt) nsHttpPipeline:: -nsInputStreamWrapper::Release() -{ - return 1; -} + memcpy(buf, mBuf, count); -NS_IMPL_THREADSAFE_QUERY_INTERFACE1(nsHttpPipeline::nsInputStreamWrapper, nsIInputStream) - -NS_IMETHODIMP nsHttpPipeline:: -nsInputStreamWrapper::Close() -{ - return NS_OK; -} - -NS_IMETHODIMP nsHttpPipeline:: -nsInputStreamWrapper::Available(PRUint32 *result) -{ - *result = (mDataLen - mDataPos); - return NS_OK; -} - -static NS_METHOD -nsWriteToRawBuffer(nsIInputStream *inStr, - void *closure, - const char *fromRawSegment, - PRUint32 offset, - PRUint32 count, - PRUint32 *writeCount) -{ - char *toBuf = (char *) closure; - memcpy(toBuf + offset, fromRawSegment, count); - *writeCount = count; - return NS_OK; -} - -NS_IMETHODIMP nsHttpPipeline:: -nsInputStreamWrapper::Read(char *buf, PRUint32 count, PRUint32 *countRead) -{ - return ReadSegments(nsWriteToRawBuffer, buf, count, countRead); -} - -NS_IMETHODIMP nsHttpPipeline:: -nsInputStreamWrapper::ReadSegments(nsWriteSegmentFun writer, - void *closure, - PRUint32 count, - PRUint32 *countRead) -{ - nsresult rv; - PRUint32 maxCount = mDataLen - mDataPos; - if (count > maxCount) - count = maxCount; - - // here's the code that distinguishes this implementation from other - // string stream implementations. normally, we'd return NS_OK to - // signify EOF, but we need to return NS_BASE_STREAM_WOULD_BLOCK to - // keep the nsStreamListenerProxy code happy. - if (count == 0) { - *countRead = 0; + mBuf += count; + mBufLen -= count; + *countWritten = count; return NS_OK; } - //if (count == 0) - // return NS_BASE_STREAM_WOULD_BLOCK; - - rv = writer(this, closure, mData + mDataPos, 0, count, countRead); - if (NS_SUCCEEDED(rv)) - mDataPos += *countRead; - return rv; -} - -NS_IMETHODIMP nsHttpPipeline:: -nsInputStreamWrapper::IsNonBlocking(PRBool *result) -{ - *result = PR_TRUE; - return NS_OK; -} +private: + const char *mBuf; + PRUint32 mBufLen; +}; //----------------------------------------------------------------------------- // nsHttpPipeline @@ -144,64 +79,42 @@ nsInputStreamWrapper::IsNonBlocking(PRBool *result) nsHttpPipeline::nsHttpPipeline() : mConnection(nsnull) - , mNumTrans(0) - , mCurrentReader(-1) - , mLock(nsnull) , mStatus(NS_OK) + , mRequestIsPartial(PR_FALSE) + , mResponseIsPartial(PR_FALSE) + , mPushBackBuf(nsnull) + , mPushBackLen(0) + , mPushBackMax(0) { - memset(mTransactionQ, 0, sizeof(PRUint32) * NS_HTTP_MAX_PIPELINED_REQUESTS); - memset(mTransactionFlags, 0, sizeof(PRUint32) * NS_HTTP_MAX_PIPELINED_REQUESTS); } nsHttpPipeline::~nsHttpPipeline() { - NS_IF_RELEASE(mConnection); + // make sure we aren't still holding onto any transactions! + Close(NS_ERROR_ABORT); - for (PRInt8 i=0; iSetConnection(this); + + if (mRequestQ.Count() == 1) + mConnection->ResumeSend(); + } + return NS_OK; } - //----------------------------------------------------------------------------- // nsHttpPipeline::nsISupports //----------------------------------------------------------------------------- @@ -219,7 +132,6 @@ NS_INTERFACE_MAP_END // nsHttpPipeline::nsAHttpConnection //----------------------------------------------------------------------------- -// called on the socket thread nsresult nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans, nsHttpRequestHead *requestHead, @@ -228,131 +140,129 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans, { LOG(("nsHttpPipeline::OnHeadersAvailable [this=%x]\n", this)); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ASSERTION(mConnection, "no connection"); + // trans has now received its response headers; forward to the real connection return mConnection->OnHeadersAvailable(trans, requestHead, responseHead, reset); } -// called on any thread nsresult -nsHttpPipeline::OnTransactionComplete(nsAHttpTransaction *trans, nsresult status) +nsHttpPipeline::ResumeSend() { - LOG(("nsHttpPipeline::OnTransactionComplete [this=%x trans=%x status=%x]\n", - this, trans, status)); + NS_NOTREACHED("nsHttpPipeline::ResumeSend"); + return NS_ERROR_UNEXPECTED; +} - // called either from nsHttpTransaction::HandleContent (socket thread) - // or from nsHttpHandler::CancelTransaction (any thread) +nsresult +nsHttpPipeline::ResumeRecv() +{ + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + NS_ASSERTION(mConnection, "no connection"); + return mConnection->ResumeRecv(); +} - PRBool mustCancel = PR_FALSE, stopTrans = PR_FALSE; - { - nsAutoLock lock(mLock); +void +nsHttpPipeline::CloseTransaction(nsAHttpTransaction *trans, nsresult reason) +{ + LOG(("nsHttpPipeline::CloseTransaction [this=%x trans=%x reason=%x]\n", + this, trans, reason)); - PRInt8 transIndex = LocateTransaction_Locked(trans); - NS_ASSERTION(transIndex != -1, "unknown transaction"); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + NS_ASSERTION(NS_FAILED(reason), "expecting failure code"); - mTransactionFlags[transIndex] = eTransactionComplete; + // the specified transaction is to be closed with the given "reason" + + PRInt32 index; + PRBool killPipeline = PR_FALSE; - if (NS_FAILED(status)) { - mStatus = status; - - // don't bother waiting for a connection to be established if the - // first transaction has been canceled. - if (transIndex == 0) - mustCancel = PR_TRUE; - // go ahead and kill off the transaction if it hasn't started - // reading yet. - if (transIndex > mCurrentReader) { - stopTrans = PR_TRUE; - DropTransaction_Locked(transIndex); - } + index = mRequestQ.IndexOf(trans); + if (index >= 0) { + if (index == 0 && mRequestIsPartial) { + // the transaction is in the request queue. check to see if any of + // its data has been written out yet. + killPipeline = PR_TRUE; } + mRequestQ.RemoveElementAt(index); + } + else { + index = mResponseQ.IndexOf(trans); + if (index >= 0) + mResponseQ.RemoveElementAt(index); + // while we could avoid killing the pipeline if this transaction is the + // last transaction in the pipeline, there doesn't seem to be that much + // value in doing so. most likely if this transaction is going away, + // the others will be shortly as well. + killPipeline = PR_TRUE; } - if (stopTrans) - trans->OnStopTransaction(status); + trans->Close(reason); + NS_RELEASE(trans); - if (mustCancel) { - NS_ASSERTION(mConnection, "no connection"); - mConnection->OnTransactionComplete(this, status); - } - - return NS_OK; + if (killPipeline) + Close(reason); } -// not called on the socket thread -nsresult -nsHttpPipeline::OnSuspend() -{ - LOG(("nsHttpPipeline::OnSuspend [this=%x]\n", this)); - - NS_ASSERTION(mConnection, "no connection"); - return mConnection->OnSuspend(); -} - -// not called on the socket thread -nsresult -nsHttpPipeline::OnResume() -{ - LOG(("nsHttpPipeline::OnResume [this=%x]\n", this)); - - NS_ASSERTION(mConnection, "no connection"); - return mConnection->OnResume(); -} - -// called on any thread void nsHttpPipeline::GetConnectionInfo(nsHttpConnectionInfo **result) { - LOG(("nsHttpPipeline::GetConnectionInfo [this=%x]\n", this)); - NS_ASSERTION(mConnection, "no connection"); mConnection->GetConnectionInfo(result); } -// called on the socket thread void -nsHttpPipeline::DropTransaction(nsAHttpTransaction *trans) +nsHttpPipeline::GetSecurityInfo(nsISupports **result) { - LOG(("nsHttpPipeline::DropTransaction [this=%x trans=%x]\n", this, trans)); - NS_ASSERTION(mConnection, "no connection"); - - // clear the transaction from our queue - { - nsAutoLock lock(mLock); - - PRInt8 transIndex = LocateTransaction_Locked(trans); - if (transIndex == -1) - return; - - DropTransaction_Locked(transIndex); - - mStatus = NS_ERROR_NET_RESET; - } - - // Assuming DropTransaction is called in response to a dead socket connection... - mConnection->OnTransactionComplete(this, NS_ERROR_NET_RESET); + mConnection->GetSecurityInfo(result); } -// called on any thread PRBool nsHttpPipeline::IsPersistent() { - return PR_TRUE; + return PR_TRUE; // pipelining requires this to be true! } -// called on the socket thread nsresult nsHttpPipeline::PushBack(const char *data, PRUint32 length) { LOG(("nsHttpPipeline::PushBack [this=%x len=%u]\n", this, length)); + + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + NS_ASSERTION(mPushBackLen == 0, "push back buffer already has data!"); - nsInputStreamWrapper readable(data, length); + // PushBack is called recursively from WriteSegments - return OnDataReadable(&readable); + // XXX we have a design decision to make here. either we buffer the data + // and process it when we return to WriteSegments, or we attempt to move + // onto the next transaction from here. doing so adds complexity with the + // benefit of eliminating the extra buffer copy. the buffer is at most + // 4096 bytes, so it is really unclear if there is any value in the added + // complexity. besides simplicity, buffering this data has the advantage + // that we'll call close on the transaction sooner, which will wake up + // the HTTP channel sooner to continue with its work. + + if (!mPushBackBuf) { + mPushBackMax = length; + mPushBackBuf = (char *) malloc(mPushBackMax); + if (!mPushBackBuf) + return NS_ERROR_OUT_OF_MEMORY; + } + else if (length > mPushBackMax) { + // grow push back buffer as necessary. + NS_ASSERTION(length <= NS_HTTP_SEGMENT_SIZE, "too big"); + mPushBackMax = length; + mPushBackBuf = (char *) realloc(mPushBackBuf, mPushBackMax); + if (!mPushBackBuf) + return NS_ERROR_OUT_OF_MEMORY; + } + + memcpy(mPushBackBuf, data, length); + mPushBackLen = length; + + return NS_OK; } - //----------------------------------------------------------------------------- // nsHttpPipeline::nsAHttpConnection //----------------------------------------------------------------------------- @@ -362,275 +272,52 @@ nsHttpPipeline::SetConnection(nsAHttpConnection *conn) { LOG(("nsHttpPipeline::SetConnection [this=%x conn=%x]\n", this, conn)); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ASSERTION(!mConnection, "already have a connection"); + NS_IF_ADDREF(mConnection = conn); - // no need to be inside the lock - for (PRInt8 i=0; iSetConnection(this); - } + PRInt32 i, count = mRequestQ.Count(); + for (i=0; iSetConnection(this); } void -nsHttpPipeline::SetSecurityInfo(nsISupports *securityInfo) +nsHttpPipeline::GetSecurityCallbacks(nsIInterfaceRequestor **result) { - LOG(("nsHttpPipeline::SetSecurityInfo [this=%x]\n", this)); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); - // set security info on each transaction - nsAutoLock lock(mLock); - for (PRInt8 i=0; iSetSecurityInfo(securityInfo); - } -} - -void -nsHttpPipeline::GetNotificationCallbacks(nsIInterfaceRequestor **result) -{ - LOG(("nsHttpPipeline::GetNotificationCallbacks [this=%x]\n", this)); - - // return notification callbacks from first transaction - nsAutoLock lock(mLock); - if (mTransactionQ[0]) - mTransactionQ[0]->GetNotificationCallbacks(result); + // return security callbacks from first request + nsAHttpTransaction *trans = Request(0); + if (trans) + trans->GetSecurityCallbacks(result); else *result = nsnull; } -PRUint32 -nsHttpPipeline::GetRequestSize() -{ - LOG(("nsHttpPipeline::GetRequestSize [this=%x]\n", this)); - - nsAutoLock lock(mLock); - return GetRequestSize_Locked(); -} - -// called on the socket thread -nsresult -nsHttpPipeline::OnDataWritable(nsIOutputStream *stream) -{ - LOG(("nsHttpPipeline::OnDataWritable [this=%x]\n", this)); - - NS_ASSERTION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); - - nsresult rv; - if (!mRequestData) { - nsAutoLock lock(mLock); - - // check for early cancelation - if (NS_FAILED(mStatus)) - return mStatus; - - // allocate a pipe for the request data - PRUint32 size = GetRequestSize_Locked(); - nsCOMPtr outputStream; - rv = NS_NewPipe(getter_AddRefs(mRequestData), - getter_AddRefs(outputStream), - size, size, PR_TRUE, PR_TRUE); - if (NS_FAILED(rv)) return rv; - - // fill the pipe - for (PRInt32 i=0; iAvailable(&before); - // append the transaction's request data to our buffer... - rv = mTransactionQ[i]->OnDataWritable(outputStream); - if (rv == NS_BASE_STREAM_CLOSED) - break; // advance to next transaction - if (NS_FAILED(rv)) - return rv; // something bad happened!! - // else, there's more to write (the transaction may be - // writing in small chunks). verify that the transaction - // actually wrote something to the pipe, and if it didn't, - // then advance to the next transaction to avoid an - // infinite loop (see bug 146884). - mRequestData->Available(&after); - if (before == after) - break; - } - } - } - } - else { - nsAutoLock lock(mLock); - - // check for early cancelation... (important for slow connections) - // only abort if we haven't started reading - if (NS_FAILED(mStatus) && (mCurrentReader == -1)) - return mStatus; - } - - // find out how much data still needs to be written, and write it - PRUint32 n = 0; - rv = mRequestData->Available(&n); - if (NS_FAILED(rv)) return rv; - - if (n > 0) - return stream->WriteFrom(mRequestData, NS_HTTP_BUFFER_SIZE, &n); - - // if nothing to write, then signal EOF - return NS_BASE_STREAM_CLOSED; -} - -// called on the socket thread (may be called recursively) -nsresult -nsHttpPipeline::OnDataReadable(nsIInputStream *stream) -{ - LOG(("nsHttpPipeline::OnDataReadable [this=%x]\n", this)); - - NS_ASSERTION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); - - { - nsresult rv = NS_OK; - nsAutoLock lock(mLock); - - if (mCurrentReader == -1) - mCurrentReader = 0; - - while (1) { - nsAHttpTransaction *reader = mTransactionQ[mCurrentReader]; - // the reader may be NULL if it has already completed. - if (!reader || (mTransactionFlags[mCurrentReader] & eTransactionComplete)) { - // advance to next reader - if (++mCurrentReader == mNumTrans) { - mCurrentReader = -1; - return NS_OK; - } - continue; - } - - // remember the index of this reader - PRUint32 readerIndex = mCurrentReader; - PRUint32 bytesRemaining = 0; - - mTransactionFlags[readerIndex] |= eTransactionReading; - - // cannot hold lock while calling OnDataReadable... must also ensure - // that |reader| doesn't dissappear on us. - nsCOMPtr readerDeathGrip(reader); - PR_Unlock(mLock); - - rv = reader->OnDataReadable(stream); - - if (NS_SUCCEEDED(rv)) - rv = stream->Available(&bytesRemaining); - - PR_Lock(mLock); - - if (NS_FAILED(rv)) - return rv; - - // the reader may have completed... - if (mTransactionFlags[readerIndex] & eTransactionComplete) { - reader->OnStopTransaction(reader->Status()); - DropTransaction_Locked(readerIndex); - } - - // the pipeline may have completed... - if (NS_FAILED(mStatus) || IsDone_Locked()) - break; // exit lock - - // otherwise, if there is nothing left in the stream, then unwind... - if (bytesRemaining == 0) - return NS_OK; - - // PushBack may have been called during the call to OnDataReadable, so - // we cannot depend on |reader| pointing to |mCurrentReader| anymore. - // loop around, and re-acquire |reader|. - } - } - - NS_ASSERTION(mConnection, "no connection"); - mConnection->OnTransactionComplete(this, mStatus); - return NS_OK; -} - -// called on any thread -nsresult -nsHttpPipeline::OnStopTransaction(nsresult status) -{ - LOG(("nsHttpPipeline::OnStopTransaction [this=%x status=%x]\n", this, status)); - - // called either from nsHttpHandler::CancelTransaction (mConnection == nsnull) - // or from nsHttpConnection::OnStopRequest (on the socket thread) - - if (mConnection) { - NS_ASSERTION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); - nsAutoLock lock(mLock); - // XXX this assertion is wrong!! what about network errors?? - NS_ASSERTION(mStatus == status, "unexpected status"); - // reset any transactions that haven't already completed. - // - // normally, we'd expect the current reader to have completed already; - // however, if the server happens to switch to HTTP/1.0 and not send a - // Content-Length for one of the pipelined responses (yes, it does - // happen!!), then we'll need to be sure to not reset the corresponding - // transaction. - for (PRInt8 i=0; iOnStopTransaction(NS_ERROR_NET_RESET); - else - trans->OnStopTransaction(status); - PR_Lock(mLock); - - NS_RELEASE(trans); - } - } - mCurrentReader = -1; - mNumTrans = 0; - } - else { - NS_ASSERTION(NS_FAILED(status), "unexpected cancelation status"); - NS_ASSERTION(mCurrentReader == -1, "unexpected reader"); - for (PRInt8 i=0; iOnStopTransaction(status); - DropTransaction_Locked(i); - } - } - } - - return NS_OK; -} - -// called on the socket thread void -nsHttpPipeline::OnStatus(nsresult status, const PRUnichar *statusText) +nsHttpPipeline::OnTransportStatus(nsresult status, PRUint32 progress) { - LOG(("nsHttpPipeline::OnStatus [this=%x status=%x]\n", this, status)); + LOG(("nsHttpPipeline::OnStatus [this=%x status=%x progress=%u]\n", + this, status, progress)); - nsAutoLock lock(mLock); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + nsAHttpTransaction *trans; switch (status) { case NS_NET_STATUS_RECEIVING_FROM: // forward this only to the transaction currently recieving data - if (mCurrentReader != -1 && mTransactionQ[mCurrentReader]) - mTransactionQ[mCurrentReader]->OnStatus(status, statusText); + trans = Response(0); + if (trans) + trans->OnTransportStatus(status, progress); break; default: // forward other notifications to all transactions - for (PRInt8 i=0; iOnStatus(status, statusText); + PRInt32 i, count = mRequestQ.Count(); + for (i=0; iOnTransportStatus(status, progress); } break; } @@ -639,62 +326,215 @@ nsHttpPipeline::OnStatus(nsresult status, const PRUnichar *statusText) PRBool nsHttpPipeline::IsDone() { - LOG(("nsHttpPipeline::IsDone [this=%x]\n", this)); - - nsAutoLock lock(mLock); - return IsDone_Locked(); + return (mRequestQ.Count() == 0) && (mResponseQ.Count() == 0); } nsresult nsHttpPipeline::Status() { - LOG(("nsHttpPipeline::Status [this=%x status=%x]\n", this, mStatus)); - return mStatus; } - -//----------------------------------------------------------------------------- -// nsHttpPipeline -//----------------------------------------------------------------------------- - -PRBool -nsHttpPipeline::IsDone_Locked() +PRUint32 +nsHttpPipeline::Available() { - // done if all of the transactions are null - for (PRInt8 i=0; iAvailable(); + return result; } -PRInt8 -nsHttpPipeline::LocateTransaction_Locked(nsAHttpTransaction *trans) +NS_METHOD +nsHttpPipeline::ReadFromPipe(nsIInputStream *stream, + void *closure, + const char *buf, + PRUint32 offset, + PRUint32 count, + PRUint32 *countRead) { - for (PRInt8 i=0; imReader->OnReadSegment(buf, count, countRead); +} + +nsresult +nsHttpPipeline::ReadSegments(nsAHttpSegmentReader *reader, + PRUint32 count, + PRUint32 *countRead) +{ + LOG(("nsHttpPipeline::ReadSegments [this=%x count=%u]\n", this, count)); + + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + nsresult rv; + + PRUint32 avail = 0; + if (mSendBufIn) { + rv = mSendBufIn->Available(&avail); + if (NS_FAILED(rv)) return rv; } - return -1; + + if (avail == 0) { + rv = FillSendBuf(); + if (NS_FAILED(rv)) return rv; + + rv = mSendBufIn->Available(&avail); + if (NS_FAILED(rv)) return rv; + } + + // read no more than what was requested + if (avail > count) + avail = count; + + mReader = reader; + + rv = mSendBufIn->ReadSegments(ReadFromPipe, this, avail, countRead); + + mReader = nsnull; + return rv; +} + +nsresult +nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer, + PRUint32 count, + PRUint32 *countWritten) +{ + LOG(("nsHttpPipeline::WriteSegments [this=%x count=%u]\n", this, count)); + + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + nsAHttpTransaction *trans; + nsresult rv; + + trans = Response(0); + if (!trans) { + if (mRequestQ.Count() > 0) + rv = NS_BASE_STREAM_WOULD_BLOCK; + else + rv = NS_BASE_STREAM_CLOSED; + } + else { + // + // ask the transaction to consume data from the connection. + // PushBack may be called recursively. + // + rv = trans->WriteSegments(writer, count, countWritten); + + if (rv == NS_BASE_STREAM_CLOSED || trans->IsDone()) { + trans->Close(NS_OK); + NS_RELEASE(trans); + mResponseQ.RemoveElementAt(0); + mResponseIsPartial = PR_FALSE; + + // ask the connection manager to add additional transactions + // to our pipeline. + gHttpHandler->ConnMgr()->AddTransactionToPipeline(this); + } + else + mResponseIsPartial = PR_TRUE; + } + + if (mPushBackLen) { + nsHttpPushBackWriter writer(mPushBackBuf, mPushBackLen); + PRUint32 len = mPushBackLen, n; + mPushBackLen = 0; + // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE, + // so we are guaranteed that the next response will eat the entire + // push back buffer (even though it might again call PushBack). + rv = WriteSegments(&writer, len, &n); + } + + return rv; } void -nsHttpPipeline::DropTransaction_Locked(PRInt8 i) +nsHttpPipeline::Close(nsresult reason) { - mTransactionFlags[i] = 0; - NS_RELEASE(mTransactionQ[i]); + LOG(("nsHttpPipeline::Close [this=%x reason=%x]\n", this, reason)); + + // the connection is going away! + mStatus = reason; + + // we must no longer reference the connection! + NS_IF_RELEASE(mConnection); + + PRUint32 i, count; + nsAHttpTransaction *trans; + + // any pending requests can ignore this error and be restarted + count = mRequestQ.Count(); + for (i=0; iClose(NS_ERROR_NET_RESET); + NS_RELEASE(trans); + } + mRequestQ.Clear(); + + trans = Response(0); + if (trans) { + // if the current response is partially complete, then it cannot be + // restarted and will have to fail with the status of the connection. + if (mResponseIsPartial) + trans->Close(reason); + else + trans->Close(NS_ERROR_NET_RESET); + NS_RELEASE(trans); + + // any remaining pending responses can be restarted + count = mResponseQ.Count(); + for (i=1; iClose(NS_ERROR_NET_RESET); + NS_RELEASE(trans); + } + mResponseQ.Clear(); + } } -PRUint32 -nsHttpPipeline::GetRequestSize_Locked() +nsresult +nsHttpPipeline::OnReadSegment(const char *segment, + PRUint32 count, + PRUint32 *countRead) { - PRUint32 size = 0; - for (PRInt8 i=0; iGetRequestSize(); - } - LOG((" request-size=%u\n", size)); - return size; + return mSendBufOut->Write(segment, count, countRead); +} + +nsresult +nsHttpPipeline::FillSendBuf() +{ + // reads from request queue, moving transactions to response queue + // when they have been completely read. + + nsresult rv; + + if (!mSendBufIn) { + // allocate a single-segment pipe + rv = NS_NewPipe(getter_AddRefs(mSendBufIn), + getter_AddRefs(mSendBufOut), + NS_HTTP_SEGMENT_SIZE, + NS_HTTP_SEGMENT_SIZE); + if (NS_FAILED(rv)) return rv; + } + + PRUint32 n, avail; + nsAHttpTransaction *trans; + while ((trans = Request(0)) != nsnull) { + avail = trans->Available(); + if (avail) { + rv = trans->ReadSegments(this, avail, &n); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(n > 0, "pipe was full"); + } + avail = trans->Available(); + if (avail == 0) { + // move transaction from request queue to response queue + mRequestQ.RemoveElementAt(0); + mResponseQ.AppendElement(trans); + mRequestIsPartial = PR_FALSE; + } + else + mRequestIsPartial = PR_TRUE; + } + return NS_OK; } diff --git a/mozilla/netwerk/protocol/http/src/nsHttpPipeline.h b/mozilla/netwerk/protocol/http/src/nsHttpPipeline.h index 6f19d0aa484..62ef075888c 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpPipeline.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpPipeline.h @@ -28,10 +28,13 @@ #include "nsAHttpConnection.h" #include "nsAHttpTransaction.h" #include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsVoidArray.h" #include "nsCOMPtr.h" class nsHttpPipeline : public nsAHttpConnection , public nsAHttpTransaction + , public nsAHttpSegmentReader { public: NS_DECL_ISUPPORTS @@ -39,73 +42,82 @@ public: nsHttpPipeline(); virtual ~nsHttpPipeline(); - nsresult Init(nsAHttpTransaction *); - nsresult AppendTransaction(nsAHttpTransaction *); + nsresult AddTransaction(nsAHttpTransaction *); // nsAHttpConnection methods: nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpRequestHead *, nsHttpResponseHead *, PRBool *reset); - nsresult OnTransactionComplete(nsAHttpTransaction *, nsresult status); - nsresult OnSuspend(); - nsresult OnResume(); + nsresult ResumeSend(); + nsresult ResumeRecv(); + void CloseTransaction(nsAHttpTransaction *, nsresult); void GetConnectionInfo(nsHttpConnectionInfo **); - void DropTransaction(nsAHttpTransaction *); + void GetSecurityInfo(nsISupports **); PRBool IsPersistent(); nsresult PushBack(const char *, PRUint32); // nsAHttpTransaction methods: void SetConnection(nsAHttpConnection *); - void SetSecurityInfo(nsISupports *); - void GetNotificationCallbacks(nsIInterfaceRequestor **); - PRUint32 GetRequestSize(); - nsresult OnDataWritable(nsIOutputStream *); - nsresult OnDataReadable(nsIInputStream *); - nsresult OnStopTransaction(nsresult status); - void OnStatus(nsresult status, const PRUnichar *statusText); + void GetSecurityCallbacks(nsIInterfaceRequestor **); + void OnTransportStatus(nsresult status, PRUint32 progress); PRBool IsDone(); nsresult Status(); + PRUint32 Available(); + nsresult ReadSegments(nsAHttpSegmentReader *, PRUint32, PRUint32 *); + nsresult WriteSegments(nsAHttpSegmentWriter *, PRUint32, PRUint32 *); + void Close(nsresult reason); + + // nsAHttpSegmentReader methods: + nsresult OnReadSegment(const char *, PRUint32, PRUint32 *); + + // nsAHttpSegmentWriter methods: + nsresult OnWriteSegment(char *, PRUint32, PRUint32 *); private: - // - // simple nsIInputStream implementation that wraps the push-back data - // and returns NS_BASE_STREAM_WOULD_BLOCK when empty. unfortunately, none - // of the string stream classes behave this way. - // - class nsInputStreamWrapper : public nsIInputStream + + nsresult FillSendBuf(); + + static NS_METHOD ReadFromPipe(nsIInputStream *, void *, const char *, + PRUint32, PRUint32, PRUint32 *); + + // convenience functions + nsAHttpTransaction *Request(PRInt32 i) { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSIINPUTSTREAM + if (mRequestQ.Count() == 0) + return nsnull; - nsInputStreamWrapper(const char *data, PRUint32 dataLen); - virtual ~nsInputStreamWrapper(); + return (nsAHttpTransaction *) mRequestQ[i]; + } + nsAHttpTransaction *Response(PRInt32 i) + { + if (mResponseQ.Count() == 0) + return nsnull; - private: - const char *mData; - PRUint32 mDataLen; - PRUint32 mDataPos; - }; + return (nsAHttpTransaction *) mResponseQ[i]; + } - // - // helpers - // - PRBool IsDone_Locked(); - PRInt8 LocateTransaction_Locked(nsAHttpTransaction *); - void DropTransaction_Locked(PRInt8); - PRUint32 GetRequestSize_Locked(); + nsAHttpConnection *mConnection; + nsVoidArray mRequestQ; // array of transactions + nsVoidArray mResponseQ; // array of transactions + nsresult mStatus; -private: - enum { - eTransactionReading = PR_BIT(1), - eTransactionComplete = PR_BIT(2) - }; - nsAHttpConnection *mConnection; // hard ref - nsAHttpTransaction *mTransactionQ [NS_HTTP_MAX_PIPELINED_REQUESTS]; // hard refs - PRUint32 mTransactionFlags[NS_HTTP_MAX_PIPELINED_REQUESTS]; - PRInt8 mNumTrans; // between 2 and NS_HTTP_MAX_PIPELINED_REQUESTS - PRInt8 mCurrentReader; // index of transaction currently reading - PRLock *mLock; - nsresult mStatus; - nsCOMPtr mRequestData; + // these flags indicate whether or not the first request or response + // is partial. a partial request means that Request(0) has been + // partially written out to the socket. a partial response means + // that Response(0) has been partially read in from the socket. + PRBool mRequestIsPartial; + PRBool mResponseIsPartial; + + // used when calling ReadSegments/WriteSegments on a transaction. + nsAHttpSegmentReader *mReader; + nsAHttpSegmentWriter *mWriter; + + // send buffer + nsCOMPtr mSendBufIn; + nsCOMPtr mSendBufOut; + + // the push back buffer. not exceeding NS_HTTP_SEGMENT_SIZE bytes. + char *mPushBackBuf; + PRUint32 mPushBackLen; + PRUint32 mPushBackMax; }; #endif // nsHttpPipeline_h__ diff --git a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp index 189a0d75460..6573dafe8de 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp @@ -28,12 +28,27 @@ #include "nsHttpRequestHead.h" #include "nsHttpResponseHead.h" #include "nsHttpChunkedDecoder.h" -#include "nsIStringStream.h" -#include "nsISeekableStream.h" -#include "nsISocketTransportService.h" +#include "nsIOService.h" +#include "nsAutoLock.h" #include "pratom.h" #include "plevent.h" +#include "nsIStringStream.h" +#include "nsISeekableStream.h" +#include "nsISocketTransport.h" +#include "nsMultiplexInputStream.h" + +//----------------------------------------------------------------------------- + +#ifdef DEBUG +// defined by the socket transport service while active +extern PRThread *gSocketThread; +#endif + +//----------------------------------------------------------------------------- + +static NS_DEFINE_CID(kMultiplexInputStream, NS_MULTIPLEXINPUTSTREAM_CID); + // mLineBuf is limited to this number of bytes. #define MAX_LINEBUF_LENGTH (1024 * 10) @@ -82,32 +97,34 @@ LogHeaders(const char *lines) // nsHttpTransaction //----------------------------------------------------------------------------- -nsHttpTransaction::nsHttpTransaction(nsIStreamListener *listener, - nsIInterfaceRequestor *callbacks, - PRUint8 caps) - : mListener(listener) - , mCallbacks(callbacks) +nsHttpTransaction::nsHttpTransaction() + : mRequestSize(0) , mConnection(nsnull) - , mReqUploadStreamOffset(0) - , mReqUploadStreamLength(0) + , mConnInfo(nsnull) + , mRequestHead(nsnull) , mResponseHead(nsnull) , mContentLength(-1) , mContentRead(0) , mChunkedDecoder(nsnull) - , mTransactionDone(0) , mStatus(NS_OK) + , mLock(PR_NewLock()) + , mTransportStatus(0) + , mTransportProgress(0) + , mTransportProgressMax(0) + , mTransportStatusInProgress(PR_FALSE) , mRestartCount(0) - , mCapabilities(caps) + , mCaps(0) + , mConnected(PR_FALSE) , mHaveStatusLine(PR_FALSE) , mHaveAllHeaders(PR_FALSE) + , mTransactionDone(PR_FALSE) , mResponseIsComplete(PR_FALSE) - , mFiredOnStart(PR_FALSE) + , mDidContentStart(PR_FALSE) , mNoContent(PR_FALSE) , mPrematureEOF(PR_FALSE) + , mDestroying(PR_FALSE) { LOG(("Creating nsHttpTransaction @%x\n", this)); - - NS_PRECONDITION(listener, "null listener"); } nsHttpTransaction::~nsHttpTransaction() @@ -115,45 +132,37 @@ nsHttpTransaction::~nsHttpTransaction() LOG(("Destroying nsHttpTransaction @%x\n", this)); NS_IF_RELEASE(mConnection); + NS_IF_RELEASE(mConnInfo); - delete mChunkedDecoder; delete mResponseHead; + delete mChunkedDecoder; + + PR_DestroyLock(mLock); } nsresult -nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead, - nsIInputStream *requestBody, - PRBool requestBodyHasHeaders, - PRBool pruneProxyHeaders) +nsHttpTransaction::Init(PRUint8 caps, + nsHttpConnectionInfo *cinfo, + nsHttpRequestHead *requestHead, + nsIInputStream *requestBody, + PRBool requestBodyHasHeaders, + nsIEventQueue *queue, + nsIInterfaceRequestor *callbacks, + nsITransportEventSink *eventsink, + nsIAsyncInputStream **responseBody) { nsresult rv; - LOG(("nsHttpTransaction::SetupRequest [this=%x]\n", this)); + LOG(("nsHttpTransaction::Init [this=%x caps=%x]\n", this, caps)); - NS_ENSURE_ARG_POINTER(requestHead); + NS_ASSERTION(cinfo, "ouch"); + NS_ASSERTION(requestHead, "ouch"); - // grab a reference to the calling thread's event queue. - nsCOMPtr eqs; - nsHttpHandler::get()->GetEventQueueService(getter_AddRefs(eqs)); - if (eqs) - eqs->ResolveEventQueue(NS_CURRENT_EVENTQ, getter_AddRefs(mConsumerEventQ)); - - // build a proxy for the progress event sink - if (!(mCapabilities & NS_HTTP_DONT_REPORT_PROGRESS)) { - if (mCallbacks && mConsumerEventQ) { - nsCOMPtr temp = do_GetInterface(mCallbacks); - if (temp) { - nsCOMPtr mgr; - nsHttpHandler::get()->GetProxyObjectManager(getter_AddRefs(mgr)); - if (mgr) - mgr->GetProxyForObject(mConsumerEventQ, - NS_GET_IID(nsIProgressEventSink), - temp, - PROXY_ASYNC | PROXY_ALWAYS, - getter_AddRefs(mProgressSink)); - } - } - } + NS_ADDREF(mConnInfo = cinfo); + mCallbacks = callbacks; + mTransportSink = eventsink; + mConsumerEventQ = queue; + mCaps = caps; if (requestHead->Method() == nsHttp::Head) mNoContent = PR_TRUE; @@ -161,7 +170,11 @@ nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead, // grab a weak reference to the request head mRequestHead = requestHead; - mReqHeaderBuf.SetLength(0); + // make sure we eliminate any proxy specific headers from + // the request if we are talking HTTPS via a SSL tunnel. + PRBool pruneProxyHeaders = cinfo->UsingSSL() && + cinfo->UsingHttpProxy(); + mReqHeaderBuf.Truncate(); requestHead->Flatten(mReqHeaderBuf, pruneProxyHeaders); #if defined(PR_LOGGING) @@ -172,26 +185,52 @@ nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead, } #endif - mReqUploadStream = requestBody; - if (mReqUploadStream) { - mReqUploadStream->Available(&mReqUploadStreamLength); - mReqUploadStreamOffset = 0; - } - // If the request body does not include headers or if there is no request // body, then we must add the header/body separator manually. if (!requestBodyHasHeaders || !requestBody) mReqHeaderBuf.Append("\r\n"); - // Create a string stream for the request header buf + // Create a string stream for the request header buf (the stream holds + // a non-owning reference to the request header data, so we MUST keep + // mReqHeaderBuf around). nsCOMPtr sup; rv = NS_NewByteInputStream(getter_AddRefs(sup), mReqHeaderBuf.get(), mReqHeaderBuf.Length()); if (NS_FAILED(rv)) return rv; - mReqHeaderStream = do_QueryInterface(sup, &rv); + nsCOMPtr headers = do_QueryInterface(sup, &rv); - return rv; + if (requestBody) { + // wrap the headers and request body in a multiplexed input stream. + nsCOMPtr multi = + do_CreateInstance(kMultiplexInputStream, &rv); + if (NS_FAILED(rv)) return rv; + + rv = multi->AppendStream(headers); + if (NS_FAILED(rv)) return rv; + + rv = multi->AppendStream(requestBody); + if (NS_FAILED(rv)) return rv; + + mRequestStream = multi; + } + else + mRequestStream = headers; + + rv = mRequestStream->Available(&mRequestSize); + if (NS_FAILED(rv)) return rv; + + // create pipe for response stream + rv = NS_NewPipe2(getter_AddRefs(mPipeIn), + getter_AddRefs(mPipeOut), + PR_TRUE, PR_TRUE, + NS_HTTP_SEGMENT_SIZE, + NS_HTTP_SEGMENT_COUNT, + nsIOService::gBufferCache); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*responseBody = mPipeIn); + return NS_OK; } nsHttpResponseHead * @@ -209,128 +248,187 @@ nsHttpTransaction::TakeResponseHead() // nsHttpTransaction::nsAHttpTransaction //---------------------------------------------------------------------------- -PRUint32 -nsHttpTransaction::GetRequestSize() +void +nsHttpTransaction::OnTransportStatus(nsresult status, PRUint32 progress) { - PRUint32 n = 0; - if (mReqHeaderStream) - mReqHeaderStream->Available(&n); - return n; -} - -// called on the socket transport thread -nsresult -nsHttpTransaction::OnDataWritable(nsIOutputStream *os) -{ - PRUint32 n = 0; - - LOG(("nsHttpTransaction::OnDataWritable [this=%x]\n", this)); - - // check if we're done writing the headers - nsresult rv = mReqHeaderStream->Available(&n); - if (NS_FAILED(rv)) return rv; - - // let at most NS_HTTP_BUFFER_SIZE bytes be written at a time. + LOG(("nsHttpTransaction::OnSocketStatus [this=%x status=%x progress=%u]\n", + this, status, progress)); - if (n != 0) - return os->WriteFrom(mReqHeaderStream, NS_HTTP_BUFFER_SIZE, &n); + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); - if (mReqUploadStream) { - nsresult rv = os->WriteFrom(mReqUploadStream, NS_HTTP_BUFFER_SIZE, &n); - if (NS_SUCCEEDED(rv)) { - mReqUploadStreamOffset += n; - if (mProgressSink) - mProgressSink->OnProgress(nsnull, nsnull, - mReqUploadStreamOffset, - mReqUploadStreamLength); + PRBool postEvent; + { + nsAutoLock lock(mLock); + + // stamp latest socket status + mTransportStatus = status; + + if (status == nsISocketTransport::STATUS_RECEIVING_FROM) { + // ignore the progress argument and use our own. as a result, + // the progress reported will not include the size of the response + // headers. this is OK b/c we only want to report the progress + // downloading the body of the response. + mTransportProgress = mContentRead; + mTransportProgressMax = mContentLength; } - return rv; + else { + // when uploading, we include the request headers in the progress + // notifications. + mTransportProgress = progress; + mTransportProgressMax = mRequestSize; + } + + postEvent = !mTransportStatusInProgress; } - return NS_BASE_STREAM_CLOSED; + // only post an event if there is not already an event in progress. we + // do this as an optimization to avoid an excessive number of status events. + if (postEvent) { + PLEvent *ev = new PLEvent; + NS_ADDREF_THIS(); + PL_InitEvent(ev, this, TransportStatus_Handler, TransportStatus_Cleanup); + if (mConsumerEventQ->PostEvent(ev) != PR_SUCCESS) { + NS_RELEASE_THIS(); + delete ev; + } + } } -// called on the socket transport thread -nsresult -nsHttpTransaction::OnDataReadable(nsIInputStream *is) +PRUint32 +nsHttpTransaction::Available() { - nsresult rv; + PRUint32 size; + if (NS_FAILED(mRequestStream->Available(&size))) + size = 0; + return size; +} - LOG(("nsHttpTransaction::OnDataReadable [this=%x]\n", this)); +NS_METHOD +nsHttpTransaction::ReadRequestSegment(nsIInputStream *stream, + void *closure, + const char *buf, + PRUint32 offset, + PRUint32 count, + PRUint32 *countRead) +{ + nsHttpTransaction *trans = (nsHttpTransaction *) closure; + return trans->mReader->OnReadSegment(buf, count, countRead); +} - if (!mListener) { - LOG(("nsHttpTransaction: no listener! closing stream\n")); +nsresult +nsHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader, + PRUint32 count, PRUint32 *countRead) +{ + NS_ASSERTION(PR_CurrentThread() == gSocketThread, "wrong thread"); + + if (!mConnected) { + mConnected = PR_TRUE; + mConnection->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); + } + + mReader = reader; + + nsresult rv = mRequestStream->ReadSegments(ReadRequestSegment, this, count, countRead); + + mReader = nsnull; + return rv; +} + +NS_METHOD +nsHttpTransaction::WritePipeSegment(nsIOutputStream *stream, + void *closure, + char *buf, + PRUint32 offset, + PRUint32 count, + PRUint32 *countWritten) +{ + nsHttpTransaction *trans = (nsHttpTransaction *) closure; + + if (trans->mTransactionDone) return NS_BASE_STREAM_CLOSED; - } - mSource = is; + nsresult rv; + // + // OK, now let the caller fill this segment with data. + // + rv = trans->mWriter->OnWriteSegment(buf, count, countWritten); + if (NS_FAILED(rv)) return rv; // caller didn't want to write anything - // let our listener try to read up to NS_HTTP_BUFFER_SIZE from us. - rv = mListener->OnDataAvailable(this, nsnull, this, - mContentRead, NS_HTTP_BUFFER_SIZE); + NS_ASSERTION(*countWritten > 0, "bad writer"); - LOG(("nsHttpTransaction: listener returned [rv=%x]\n", rv)); + // now let the transaction "play" with the buffer. it is free to modify + // the contents of the buffer and/or modify countWritten. + rv = trans->ProcessData(buf, *countWritten, countWritten); + if (NS_FAILED(rv)) + trans->Close(rv); - mSource = 0; + return rv; // failure code only stops WriteSegments; it is not propogated. +} - // check if this transaction needs to be restarted - if (mPrematureEOF) { - mPrematureEOF = PR_FALSE; - rv = Restart(); - // if successfully restarted, then return an error to abort the - // socket transport. - if (NS_SUCCEEDED(rv)) - rv = NS_BINDING_ABORTED; - } +nsresult +nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer, + PRUint32 count, PRUint32 *countWritten) +{ + NS_ASSERTION(PR_CurrentThread() == gSocketThread, "wrong thread"); + + if (mTransactionDone) + return NS_BASE_STREAM_CLOSED; + + mWriter = writer; + + nsresult rv = mPipeOut->WriteSegments(WritePipeSegment, this, count, countWritten); + + mWriter = nsnull; + + // if pipe would block then we need to AsyncWait on it. + if (rv == NS_BASE_STREAM_WOULD_BLOCK) + mPipeOut->AsyncWait(this, 0, nsnull); return rv; } -// called on any thread -nsresult -nsHttpTransaction::OnStopTransaction(nsresult status) +void +nsHttpTransaction::Close(nsresult reason) { - LOG(("nsHttpTransaction::OnStopTransaction [this=%x status=%x]\n", - this, status)); + LOG(("nsHttpTransaction::Close [this=%x reason=%x]\n", this, reason)); + + NS_ASSERTION(PR_CurrentThread() == gSocketThread, "wrong thread"); + + if (NS_FAILED(mStatus)) { + LOG((" already closed\n")); + return; + } + + // we must no longer reference the connection! + NS_IF_RELEASE(mConnection); + mConnected = PR_FALSE; // if the connection was reset before we read any part of the response, // then we must try to restart the transaction. - if (status == NS_ERROR_NET_RESET) { + if (reason == NS_ERROR_NET_RESET) { // if some data was read, then mask the reset error, so our listener // will treat this as a normal failure. XXX we might want to map // this error to a special error code to indicate that the transfer // was abnormally interrupted. if (mContentRead > 0) - status = NS_ERROR_ABORT; + reason = NS_ERROR_ABORT; // XXX NS_ERROR_NET_INTERRUPT?? // if restarting fails, then we must notify our listener. else if (NS_SUCCEEDED(Restart())) - return NS_OK; + return; } - mTransactionDone = 1; // force this flag - mStatus = status; + if (NS_SUCCEEDED(reason) && !mHaveAllHeaders && !mLineBuf.IsEmpty()) { + // the server has not sent the final \r\n terminating the header section, + // and there is still a header line unparsed. let's make sure we parse + // the remaining header line, and then hopefully, the response will be + // usable (see bug 88792). + ParseLineSegment("\n", 1); + } - if (mListener) { - if (!mFiredOnStart) { - mFiredOnStart = PR_TRUE; - mListener->OnStartRequest(this, nsnull); - } - mListener->OnStopRequest(this, nsnull, status); - mListener = 0; + mTransactionDone = PR_TRUE; // force this flag + mStatus = reason; - // from this point forward we can't access the request head. - mRequestHead = nsnull; - } - return NS_OK; -} - -void -nsHttpTransaction::OnStatus(nsresult status, const PRUnichar *statusText) -{ - LOG(("nsHttpTransaction::OnStatus [this=%x status=%x]\n", this, status)); - - if (mProgressSink) - mProgressSink->OnStatus(nsnull, nsnull, status, statusText); + mPipeOut->CloseEx(reason); } //----------------------------------------------------------------------------- @@ -340,10 +438,10 @@ nsHttpTransaction::OnStatus(nsresult status, const PRUnichar *statusText) nsresult nsHttpTransaction::Restart() { - nsresult rv; + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); // limit the number of restart attempts - bug 92224 - if (++mRestartCount >= nsHttpHandler::get()->MaxRequestAttempts()) { + if (++mRestartCount >= gHttpHandler->MaxRequestAttempts()) { LOG(("reached max request attempts, failing transaction @%x\n", this)); return NS_ERROR_NET_RESET; } @@ -351,35 +449,14 @@ nsHttpTransaction::Restart() LOG(("restarting transaction @%x\n", this)); // rewind streams in case we already wrote out the request - nsCOMPtr seekable = do_QueryInterface(mReqHeaderStream); + nsCOMPtr seekable = do_QueryInterface(mRequestStream); if (seekable) seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); - seekable = do_QueryInterface(mReqUploadStream); - if (seekable) - seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); - mReqUploadStreamOffset = 0; - // just in case the connection is holding the last reference to us... - NS_ADDREF_THIS(); + // clear the old socket info + mSecurityInfo = 0; - // we don't want the connection to send anymore notifications to us. - mConnection->DropTransaction(this); - - nsHttpConnectionInfo *ci = nsnull; - mConnection->GetConnectionInfo(&ci); - NS_ASSERTION(ci, "connection info should be non-null"); - if (ci) { - // we must release the connection before re-initiating this transaction - // since we'll be getting a new connection. - NS_RELEASE(mConnection); - - rv = nsHttpHandler::get()->InitiateTransaction(this, ci); - NS_ASSERTION(NS_SUCCEEDED(rv), "InitiateTransaction failed"); - - NS_RELEASE(ci); - } - NS_RELEASE_THIS(); - return NS_OK; + return gHttpHandler->InitiateTransaction(this); } void @@ -518,10 +595,7 @@ nsHttpTransaction::ParseHead(char *buf, nsresult nsHttpTransaction::HandleContentStart() { - nsresult rv; - - LOG(("nsHttpTransaction::HandleContentStart [this=%x response-head=%x]\n", - this, mResponseHead)); + LOG(("nsHttpTransaction::HandleContentStart [this=%x]\n", this)); if (mResponseHead) { #if defined(PR_LOGGING) @@ -544,7 +618,7 @@ nsHttpTransaction::HandleContentStart() mHaveStatusLine = PR_FALSE; mResponseHead->Reset(); // wait to be called again... - return NS_BASE_STREAM_WOULD_BLOCK; + return NS_OK; } // check if this is a no-content response @@ -584,12 +658,8 @@ nsHttpTransaction::HandleContentStart() } } - LOG(("nsHttpTransaction [this=%x] sending OnStartRequest\n", this)); - mFiredOnStart = PR_TRUE; - - rv = mListener->OnStartRequest(this, nsnull); - LOG(("OnStartRequest returned rv=%x\n", rv)); - return rv; + mDidContentStart = PR_TRUE; + return NS_OK; } // called on the socket thread @@ -601,18 +671,14 @@ nsHttpTransaction::HandleContent(char *buf, { nsresult rv; - LOG(("nsHttpTransaction::HandleContent [this=%x count=%u]\n", - this, count)); + LOG(("nsHttpTransaction::HandleContent [this=%x count=%u]\n", this, count)); *contentRead = 0; *contentRemaining = 0; - if (mTransactionDone) - return NS_OK; - NS_ASSERTION(mConnection, "no connection"); - if (!mFiredOnStart) { + if (!mDidContentStart) { rv = HandleContentStart(); if (NS_FAILED(rv)) return rv; } @@ -650,8 +716,10 @@ nsHttpTransaction::HandleContent(char *buf, if (*contentRead) { // update count of content bytes read and report progress... mContentRead += *contentRead; + /* if (mProgressSink) mProgressSink->OnProgress(nsnull, nsnull, mContentRead, PR_MAX(0, mContentLength)); + */ } LOG(("nsHttpTransaction [this=%x count=%u read=%u mContentRead=%u mContentLength=%d]\n", @@ -660,23 +728,106 @@ nsHttpTransaction::HandleContent(char *buf, // check for end-of-file if ((mContentRead == PRUint32(mContentLength)) || (mChunkedDecoder && mChunkedDecoder->ReachedEOF())) { - // atomically mark the transaction as complete to ensure that - // OnTransactionComplete is fired only once! - PRInt32 priorVal = PR_AtomicSet(&mTransactionDone, 1); - if (priorVal == 0) { - mResponseIsComplete = PR_TRUE; - // let the connection know that we are done with it; this should - // result in OnStopTransaction being fired. - return mConnection->OnTransactionComplete(this, NS_OK); - } - return NS_OK; + // the transaction is done with a complete response. + mTransactionDone = PR_TRUE; + mResponseIsComplete = PR_TRUE; } - // if we didn't "read" anything and this is not a no-content response, - // then we must return NS_BASE_STREAM_WOULD_BLOCK so we'll be called again. - return (!mNoContent && !*contentRead) ? NS_BASE_STREAM_WOULD_BLOCK : NS_OK; + return NS_OK; } +nsresult +nsHttpTransaction::ProcessData(char *buf, PRUint32 count, PRUint32 *countRead) +{ + nsresult rv; + + LOG(("nsHttpTransaction::ProcessData [this=%x count=%u]\n", this, count)); + + *countRead = 0; + + // we may not have read all of the headers yet... + if (!mHaveAllHeaders) { + PRUint32 bytesConsumed = 0; + + rv = ParseHead(buf, count, &bytesConsumed); + if (NS_FAILED(rv)) return rv; + + count -= bytesConsumed; + + // if buf has some content in it, shift bytes to top of buf. + if (count && bytesConsumed) + memmove(buf, buf + bytesConsumed, count); + } + + // even though count may be 0, we still want to call HandleContent + // so it can complete the transaction if this is a "no-content" response. + if (mHaveAllHeaders) { + PRUint32 countRemaining = 0; + // + // buf layout: + // + // +--------------------------------------+----------------+-----+ + // | countRead | countRemaining | | + // +--------------------------------------+----------------+-----+ + // + // count : bytes read from the socket + // countRead : bytes corresponding to this transaction + // countRemaining : bytes corresponding to next pipelined transaction + // + // NOTE: + // count > countRead + countRemaining <==> chunked transfer encoding + // + rv = HandleContent(buf, count, countRead, &countRemaining); + if (NS_FAILED(rv)) return rv; + // we may have read more than our share, in which case we must give + // the excess bytes back to the connection + if (mResponseIsComplete && countRemaining) { + NS_ASSERTION(mConnection, "no connection"); + mConnection->PushBack(buf + *countRead, countRemaining); + } + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// nsHttpTransaction events +//----------------------------------------------------------------------------- + +void *PR_CALLBACK +nsHttpTransaction::TransportStatus_Handler(PLEvent *ev) +{ + nsHttpTransaction *trans = + NS_STATIC_CAST(nsHttpTransaction *, PL_GetEventOwner(ev)); + + LOG(("nsHttpTransaction::SocketStatus_Handler [trans=%x]\n", trans)); + + nsresult status; + PRUint32 progress, progressMax; + { + nsAutoLock lock(trans->mLock); + + status = trans->mTransportStatus; + progress = trans->mTransportProgress; + progressMax = trans->mTransportProgressMax; + + trans->mTransportStatusInProgress = PR_FALSE; + } + + trans->mTransportSink->OnTransportStatus(nsnull, status, progress, progressMax); + + NS_RELEASE(trans); + return nsnull; +} + +void PR_CALLBACK +nsHttpTransaction::TransportStatus_Cleanup(PLEvent *ev) +{ + delete ev; +} + +//----------------------------------------------------------------------------- + void nsHttpTransaction::DeleteSelfOnConsumerThread() { @@ -684,8 +835,11 @@ nsHttpTransaction::DeleteSelfOnConsumerThread() nsCOMPtr currentEventQ; LOG(("nsHttpTransaction::DeleteSelfOnConsumerThread [this=%x]\n", this)); + + NS_ASSERTION(!mDestroying, "deleting self again"); + mDestroying = PR_TRUE; - nsHttpHandler::get()->GetEventQueueService(getter_AddRefs(eqs)); + gHttpHandler->GetEventQueueService(getter_AddRefs(eqs)); if (eqs) eqs->ResolveEventQueue(NS_CURRENT_EVENTQ, getter_AddRefs(currentEventQ)); @@ -701,9 +855,7 @@ nsHttpTransaction::DeleteSelfOnConsumerThread() return; } - PL_InitEvent(event, this, - nsHttpTransaction::DeleteThis_EventHandlerFunc, - nsHttpTransaction::DeleteThis_EventCleanupFunc); + PL_InitEvent(event, this, DeleteThis_Handler, DeleteThis_Cleanup); PRStatus status = mConsumerEventQ->PostEvent(event); NS_ASSERTION(status == PR_SUCCESS, "PostEvent failed"); @@ -711,7 +863,7 @@ nsHttpTransaction::DeleteSelfOnConsumerThread() } void *PR_CALLBACK -nsHttpTransaction::DeleteThis_EventHandlerFunc(PLEvent *ev) +nsHttpTransaction::DeleteThis_Handler(PLEvent *ev) { nsHttpTransaction *trans = NS_STATIC_CAST(nsHttpTransaction *, PL_GetEventOwner(ev)); @@ -723,7 +875,7 @@ nsHttpTransaction::DeleteThis_EventHandlerFunc(PLEvent *ev) } void PR_CALLBACK -nsHttpTransaction::DeleteThis_EventCleanupFunc(PLEvent *ev) +nsHttpTransaction::DeleteThis_Cleanup(PLEvent *ev) { delete ev; } @@ -752,225 +904,36 @@ nsHttpTransaction::Release() } NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsHttpTransaction, - nsIRequest, - nsIInputStream) + nsIOutputStreamNotify, + nsISocketEventHandler) //----------------------------------------------------------------------------- -// nsHttpTransaction::nsIRequest +// nsHttpTransaction::nsIOutputStreamNotify //----------------------------------------------------------------------------- NS_IMETHODIMP -nsHttpTransaction::GetName(nsACString &aName) +nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out) { - return NS_ERROR_NOT_IMPLEMENTED; -} + // proxy this event to the socket thread -NS_IMETHODIMP -nsHttpTransaction::IsPending(PRBool *_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} + nsCOMPtr sts; + gHttpHandler->ConnMgr()->GetSTS(getter_AddRefs(sts)); + if (sts) + sts->PostEvent(this, 0, 0, nsnull); // only one type of event so far -NS_IMETHODIMP -nsHttpTransaction::GetStatus(nsresult *aStatus) -{ - *aStatus = mStatus; return NS_OK; } -// called from any thread -NS_IMETHODIMP -nsHttpTransaction::Cancel(nsresult status) -{ - LOG(("nsHttpTransaction::Cancel [this=%x status=%x]\n", this, status)); - - // ignore cancelation if the transaction already has an error status. - if (NS_FAILED(mStatus)) { - LOG(("ignoring cancel since transaction has already failed " - "[this=%x mStatus=%x]\n", this, mStatus)); - return NS_OK; - } - - // if the transaction is already "done" then there is nothing more to do. - // ie., our consumer _will_ eventually receive their OnStopRequest. - PRInt32 priorVal = PR_AtomicSet(&mTransactionDone, 1); - if (priorVal == 1) { - LOG(("ignoring cancel since transaction is already done [this=%x]\n", this)); - return NS_OK; - } - - // the status must be set immediately as the cancelation may only take - // action asynchronously. - mStatus = status; - - return nsHttpHandler::get()->CancelTransaction(this, status); -} - -NS_IMETHODIMP -nsHttpTransaction::Suspend() -{ - LOG(("nsHttpTransaction::Suspend [this=%x]\n", this)); - if (mConnection && !mTransactionDone) - mConnection->OnSuspend(); - return NS_OK; -} - -// called from the consumer thread, while nothing is happening on the socket thread. -NS_IMETHODIMP -nsHttpTransaction::Resume() -{ - LOG(("nsHttpTransaction::Resume [this=%x]\n", this)); - if (mConnection && !mTransactionDone) - mConnection->OnResume(); - return NS_OK; -} - -NS_IMETHODIMP -nsHttpTransaction::GetLoadGroup(nsILoadGroup **aLoadGroup) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} -NS_IMETHODIMP -nsHttpTransaction::SetLoadGroup(nsILoadGroup *aLoadGroup) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsHttpTransaction::GetLoadFlags(nsLoadFlags *aLoadFlags) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} -NS_IMETHODIMP -nsHttpTransaction::SetLoadFlags(nsLoadFlags aLoadFlags) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - //----------------------------------------------------------------------------- -// nsHttpTransaction::nsIInputStream +// nsHttpTransaction::nsISocketEventHandler //----------------------------------------------------------------------------- NS_IMETHODIMP -nsHttpTransaction::Close() +nsHttpTransaction::OnSocketEvent(PRUint32 type, PRUint32 param1, void *param2) { - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsHttpTransaction::Available(PRUint32 *result) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsHttpTransaction::Read(char *buf, PRUint32 count, PRUint32 *bytesWritten) -{ - nsresult rv; - - LOG(("nsHttpTransaction::Read [this=%x count=%u]\n", this, count)); - - NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); - - if (mTransactionDone) - return NS_BASE_STREAM_CLOSED; - - *bytesWritten = 0; - - // read some data from our source and put it in the given buf - rv = mSource->Read(buf, count, bytesWritten); - LOG(("mSource->Read [rv=%x count=%u countRead=%u]\n", rv, count, *bytesWritten)); - - // detect explicit socket RESET - if (rv == NS_ERROR_NET_RESET) { - LOG(("got NS_ERROR_NET_RESET\n")); - *bytesWritten = 0; + if (mConnection) { + nsresult rv = mConnection->ResumeRecv(); + NS_ASSERTION(NS_SUCCEEDED(rv), "ResumeSend failed"); } - else if (NS_FAILED(rv)) { - LOG(("nsHttpTransaction: mSource->Read() returned [rv=%x]\n", rv)); - return rv; - } - - if (*bytesWritten == 0) { - LOG(("nsHttpTransaction: reached EOF\n")); - if (!mHaveStatusLine) { - // we've read nothing from the socket... - mPrematureEOF = PR_TRUE; - // return would block to prevent being called again. - return NS_BASE_STREAM_WOULD_BLOCK; - } - if (!mHaveAllHeaders && !mLineBuf.IsEmpty()) { - // the server has not sent the final \r\n terminating the header section, - // and there is still a header line unparsed. let's make sure we parse - // the remaining header line, and then hopefully, the response will be - // usable (see bug 88792). - rv = ParseLineSegment("\n", 1); - } - return rv; - } - - // pretend that no bytes were written (since we're just borrowing the - // given buf anyways). - count = *bytesWritten; - *bytesWritten = 0; - - // we may not have read all of the headers yet... - if (!mHaveAllHeaders) { - PRUint32 bytesConsumed = 0; - - rv = ParseHead(buf, count, &bytesConsumed); - if (NS_FAILED(rv)) return rv; - - count -= bytesConsumed; - - if (count && bytesConsumed) { - // buf has some content in it; shift bytes to top of buf. - memmove(buf, buf + bytesConsumed, count); - } - } - - // even though count may be 0, we still want to call HandleContent - // so it can complete the transaction if this is a "no-content" response. - if (mHaveAllHeaders) { - PRUint32 bytesRemaining = 0; - // - // buf layout: - // - // +-----------------------------------------+----------------+-----+ - // | bytesWritten | bytesRemaining | | - // +-----------------------------------------+----------------+-----+ - // - // count : bytes read from the socket - // bytesWritten : bytes corresponding to this transaction - // bytesRemaining : bytes corresponding to next pipelined transaction - // - // NOTE: - // count > bytesWritten + bytesRemaining <==> chunked transfer encoding - // - rv = HandleContent(buf, count, bytesWritten, &bytesRemaining); - if (NS_FAILED(rv)) return rv; - // we may have read more than our share, in which case we must give - // the excess bytes back to the connection - if (mResponseIsComplete && bytesRemaining) { - NS_ASSERTION(mConnection, "no connection"); - mConnection->PushBack(buf + *bytesWritten, bytesRemaining); - } - return rv; - } - - // wait for more data - return NS_BASE_STREAM_WOULD_BLOCK; -} - -NS_IMETHODIMP -nsHttpTransaction::ReadSegments(nsWriteSegmentFun writer, void *closure, - PRUint32 count, PRUint32 *countRead) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsHttpTransaction::IsNonBlocking(PRBool *result) -{ - return NS_ERROR_NOT_IMPLEMENTED; + return NS_OK; } diff --git a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h index 2b4366bee8c..6a78ca6fecf 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h @@ -28,15 +28,19 @@ #include "nsHttpHeaderArray.h" #include "nsAHttpTransaction.h" #include "nsAHttpConnection.h" -#include "nsIStreamListener.h" -#include "nsIInputStream.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIProgressEventSink.h" -#include "nsIEventQueue.h" -#include "nsXPIDLString.h" #include "nsCOMPtr.h" +#include "nsIPipe.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsIInterfaceRequestor.h" +#include "nsISocketTransportService.h" +#include "nsITransport.h" +#include "nsIEventQueue.h" + +//----------------------------------------------------------------------------- + +class nsHttpTransaction; class nsHttpRequestHead; class nsHttpResponseHead; class nsHttpChunkedDecoder; @@ -47,32 +51,60 @@ class nsHttpChunkedDecoder; //----------------------------------------------------------------------------- class nsHttpTransaction : public nsAHttpTransaction - , public nsIRequest - , public nsIInputStream + , public nsIOutputStreamNotify + , public nsISocketEventHandler { public: NS_DECL_ISUPPORTS - NS_DECL_NSIREQUEST - NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIOUTPUTSTREAMNOTIFY + NS_DECL_NSISOCKETEVENTHANDLER - // A transaction is constructed from request headers. - nsHttpTransaction(nsIStreamListener *, nsIInterfaceRequestor *, PRUint8 caps); + nsHttpTransaction(); virtual ~nsHttpTransaction(); - // Called to initialize the transaction - nsresult SetupRequest(nsHttpRequestHead *requestHeaders, - nsIInputStream *requestBody, - PRBool requestBodyIncludesHeaders, - PRBool pruneProxyHeaders); + // + // called to initialize the transaction + // + // @param caps + // the transaction capabilities (see nsHttp.h) + // @param connInfo + // the connection type for this transaction. + // @param reqHeaders + // the request header struct + // @param reqBody + // the request body (POST or PUT data stream) + // @param reqBodyIncludesHeaders + // fun stuff to support NPAPI plugins. + // @param eventQ + // the event queue were notifications should be sent. + // @param callbacks + // the notification callbacks to be given to PSM. + // @param responseBody + // the input stream that will contain the response data. async + // wait on this input stream for data. on first notification, + // headers should be available (check transaction status). + // + nsresult Init(PRUint8 caps, + nsHttpConnectionInfo *connInfo, + nsHttpRequestHead *reqHeaders, + nsIInputStream *reqBody, + PRBool reqBodyIncludesHeaders, + nsIEventQueue *eventQ, + nsIInterfaceRequestor *callbacks, + nsITransportEventSink *eventsink, + nsIAsyncInputStream **responseBody); - nsIStreamListener *Listener() { return mListener; } - nsAHttpConnection *Connection() { return mConnection; } + // attributes + PRUint8 Caps() { return mCaps; } + nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } nsHttpRequestHead *RequestHead() { return mRequestHead; } nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; } + nsISupports *SecurityInfo() { return mSecurityInfo; } + nsresult TransportStatus(){ return mTransportStatus; } + nsIInterfaceRequestor *Callbacks() { return mCallbacks; } nsIEventQueue *ConsumerEventQ() { return mConsumerEventQ; } - nsISupports *SecurityInfo() { return mSecurityInfo; } - PRUint8 Capabilities() { return mCapabilities; } + nsAHttpConnection *Connection() { return mConnection; } // Called to take ownership of the response headers; the transaction // will drop any reference to the response headers after this call. @@ -81,18 +113,26 @@ public: // Called to find out if the transaction generated a complete response. PRBool ResponseIsComplete() { return mResponseIsComplete; } + //------------------------------------------------------------------------- // nsAHttpTransaction methods: - void SetConnection(nsAHttpConnection *conn) { NS_IF_ADDREF(mConnection = conn); } - void SetSecurityInfo(nsISupports *info) { mSecurityInfo = info; } - void GetNotificationCallbacks(nsIInterfaceRequestor **cb) { NS_IF_ADDREF(*cb = mCallbacks); } - PRUint32 GetRequestSize(); - PRUint32 GetContentRead() { return mContentRead; } - nsresult OnDataWritable(nsIOutputStream *); - nsresult OnDataReadable(nsIInputStream *); - nsresult OnStopTransaction(nsresult); - void OnStatus(nsresult status, const PRUnichar *statusText); + //------------------------------------------------------------------------- + + void SetConnection(nsAHttpConnection *conn) + { + NS_IF_RELEASE(mConnection); + NS_IF_ADDREF(mConnection = conn); + } + void GetSecurityCallbacks(nsIInterfaceRequestor **cb) + { + NS_IF_ADDREF(*cb = mCallbacks); + } + void OnTransportStatus(nsresult status, PRUint32 progress); PRBool IsDone() { return mTransactionDone; } nsresult Status() { return mStatus; } + PRUint32 Available(); + nsresult ReadSegments(nsAHttpSegmentReader *, PRUint32, PRUint32 *); + nsresult WriteSegments(nsAHttpSegmentWriter *, PRUint32, PRUint32 *); + void Close(nsresult); private: nsresult Restart(); @@ -101,30 +141,39 @@ private: nsresult ParseHead(char *, PRUint32 count, PRUint32 *countRead); nsresult HandleContentStart(); nsresult HandleContent(char *, PRUint32 count, PRUint32 *contentRead, PRUint32 *contentRemaining); + nsresult ProcessData(char *, PRUint32, PRUint32 *); void DeleteSelfOnConsumerThread(); - static void *PR_CALLBACK DeleteThis_EventHandlerFunc(PLEvent *); - static void PR_CALLBACK DeleteThis_EventCleanupFunc(PLEvent *); + static void *PR_CALLBACK TransportStatus_Handler(PLEvent *); + static void PR_CALLBACK TransportStatus_Cleanup(PLEvent *); + static void *PR_CALLBACK DeleteThis_Handler(PLEvent *); + static void PR_CALLBACK DeleteThis_Cleanup(PLEvent *); + + static NS_METHOD ReadRequestSegment(nsIInputStream *, void *, const char *, + PRUint32, PRUint32, PRUint32 *); + static NS_METHOD WritePipeSegment(nsIOutputStream *, void *, char *, + PRUint32, PRUint32, PRUint32 *); private: - nsCOMPtr mListener; nsCOMPtr mCallbacks; - nsCOMPtr mProgressSink; + nsCOMPtr mTransportSink; nsCOMPtr mConsumerEventQ; nsCOMPtr mSecurityInfo; - - nsAHttpConnection *mConnection; // hard ref + nsCOMPtr mPipeIn; + nsCOMPtr mPipeOut; nsCString mReqHeaderBuf; // flattened request headers - nsCOMPtr mReqHeaderStream; // header data stream - nsCOMPtr mReqUploadStream; // upload data stream - PRUint32 mReqUploadStreamOffset; - PRUint32 mReqUploadStreamLength; + nsCOMPtr mRequestStream; + PRUint32 mRequestSize; - nsCOMPtr mSource; + nsAHttpConnection *mConnection; // hard ref + nsHttpConnectionInfo *mConnInfo; // hard ref nsHttpRequestHead *mRequestHead; // weak ref nsHttpResponseHead *mResponseHead; // hard ref + nsAHttpSegmentReader *mReader; + nsAHttpSegmentWriter *mWriter; + nsCString mLineBuf; // may contain a partial line PRInt32 mContentLength; // equals -1 if unknown @@ -132,18 +181,30 @@ private: nsHttpChunkedDecoder *mChunkedDecoder; - PRInt32 mTransactionDone; // set atomically nsresult mStatus; - PRUint16 mRestartCount; // the number of times this transaction has been restarted - PRUint8 mCapabilities; + // this lock is used to protect access to members which may be accessed + // from both the main thread as well as the socket thread. + PRLock *mLock; + // these transport status fields are protected by mLock + nsresult mTransportStatus; + PRUint32 mTransportProgress; + PRUint32 mTransportProgressMax; + PRPackedBool mTransportStatusInProgress; + + PRUint16 mRestartCount; // the number of times this transaction has been restarted + PRUint8 mCaps; + + PRPackedBool mConnected; PRPackedBool mHaveStatusLine; PRPackedBool mHaveAllHeaders; - PRPackedBool mResponseIsComplete; - PRPackedBool mFiredOnStart; - PRPackedBool mNoContent; // expecting an empty entity body? + PRPackedBool mTransactionDone; + PRPackedBool mResponseIsComplete; // == mTransactionDone && NS_SUCCEEDED(mStatus) ? + PRPackedBool mDidContentStart; + PRPackedBool mNoContent; // expecting an empty entity body? PRPackedBool mPrematureEOF; + PRPackedBool mDestroying; }; #endif // nsHttpTransaction_h__ diff --git a/mozilla/netwerk/protocol/jar/public/Makefile.in b/mozilla/netwerk/protocol/jar/public/Makefile.in index ccf6ea4c4d2..6cf61831559 100644 --- a/mozilla/netwerk/protocol/jar/public/Makefile.in +++ b/mozilla/netwerk/protocol/jar/public/Makefile.in @@ -30,9 +30,9 @@ MODULE = necko XPIDL_MODULE = necko_jar GRE_MODULE = 1 -XPIDLSRCS = nsIJARChannel.idl \ - nsIJARURI.idl \ - nsIJARProtocolHandler.idl +XPIDLSRCS = nsIJARURI.idl \ + nsIJARChannel.idl \ + nsIJARProtocolHandler.idl include $(topsrcdir)/config/rules.mk diff --git a/mozilla/netwerk/protocol/jar/public/nsIJARChannel.idl b/mozilla/netwerk/protocol/jar/public/nsIJARChannel.idl index 56ad867e1a4..85832c259a4 100644 --- a/mozilla/netwerk/protocol/jar/public/nsIJARChannel.idl +++ b/mozilla/netwerk/protocol/jar/public/nsIJARChannel.idl @@ -37,16 +37,7 @@ #include "nsIChannel.idl" -interface nsISimpleEnumerator; - [scriptable, uuid(c7e410d1-85f2-11d3-9f63-006008a6efe9)] interface nsIJARChannel : nsIChannel { - /** - * Enumerates all the entries in the JAR (the root URI). - * ARGUMENTS: - * aRoot - a string representing the root dir to enumerate from - * or null to enumerate the whole thing. - */ - nsISimpleEnumerator EnumerateEntries(in string aRoot); }; diff --git a/mozilla/netwerk/protocol/jar/src/nsJARChannel.cpp b/mozilla/netwerk/protocol/jar/src/nsJARChannel.cpp index 814e42ba47a..630a903120c 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARChannel.cpp +++ b/mozilla/netwerk/protocol/jar/src/nsJARChannel.cpp @@ -17,409 +17,476 @@ * */ -#include "nsNetUtil.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" #include "nsJARChannel.h" -#include "nsCRT.h" -#include "nsIFileTransportService.h" -#include "nsIURI.h" -#include "nsIFileURL.h" -#include "nsCExternalHandlerService.h" -#include "nsIMIMEService.h" -#include "nsAutoLock.h" -#include "nsIFileStreams.h" +#include "nsJARProtocolHandler.h" #include "nsMimeTypes.h" +#include "nsNetUtil.h" + #include "nsScriptSecurityManager.h" #include "nsIAggregatePrincipal.h" -#include "nsIProgressEventSink.h" -#include "nsXPIDLString.h" -#include "nsReadableUtils.h" +#include "nsIFileURL.h" #include "nsIJAR.h" -#include "prthread.h" -static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); static NS_DEFINE_CID(kScriptSecurityManagerCID, NS_SCRIPTSECURITYMANAGER_CID); +static NS_DEFINE_CID(kInputStreamChannelCID, NS_INPUTSTREAMCHANNEL_CID); + +//----------------------------------------------------------------------------- #if defined(PR_LOGGING) // -// Log module for JarChannel logging... +// set NSPR_LOG_MODULES=nsJarProtocol:5 // -// To enable logging (see prlog.h for full details): -// -// set NSPR_LOG_MODULES=nsJarProtocol:5 -// set NSPR_LOG_FILE=nspr.log -// -// this enables PR_LOG_DEBUG level information and places all output in -// the file nspr.log -// -PRLogModuleInfo* gJarProtocolLog = nsnull; +static PRLogModuleInfo *gJarProtocolLog = nsnull; +#endif -#endif /* PR_LOGGING */ +#define LOG(args) PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, args) +#define LOG_ENABLED() PR_LOG_TEST(gJarProtocolLog, 4) -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// nsJARInputThunk +// +// this class allows us to do some extra work on the stream transport thread. +//----------------------------------------------------------------------------- -#define NS_DEFAULT_JAR_BUFFER_SEGMENT_SIZE (16*1024) -#define NS_DEFAULT_JAR_BUFFER_MAX_SIZE (256*1024) +class nsJARInputThunk : public nsIInputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + + nsJARInputThunk(nsIFile *jarFile, const nsACString &jarEntry, + nsIZipReaderCache *jarCache) + : mJarCache(jarCache) + , mJarFile(jarFile) + , mJarEntry(jarEntry) + { + NS_ASSERTION(mJarFile, "no jar file"); + } + virtual ~nsJARInputThunk() {} + + void GetJarReader(nsIZipReader **result) + { + NS_ADDREF(*result = mJarReader); + } + +private: + nsresult EnsureJarStream(); + + nsCOMPtr mJarCache; + nsCOMPtr mJarReader; + nsCOMPtr mJarFile; + nsCOMPtr mJarStream; + nsCString mJarEntry; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputThunk, nsIInputStream) + +nsresult +nsJARInputThunk::EnsureJarStream() +{ + if (mJarStream) + return NS_OK; + + nsresult rv = mJarCache->GetZip(mJarFile, getter_AddRefs(mJarReader)); + if (NS_FAILED(rv)) return rv; + + return mJarReader->GetInputStream(mJarEntry.get(), + getter_AddRefs(mJarStream)); +} + +NS_IMETHODIMP +nsJARInputThunk::Close() +{ + if (mJarStream) + return mJarStream->Close(); + + return NS_OK; +} + +NS_IMETHODIMP +nsJARInputThunk::Available(PRUint32 *avail) +{ + nsresult rv = EnsureJarStream(); + if (NS_FAILED(rv)) return rv; + + return mJarStream->Available(avail); +} + +NS_IMETHODIMP +nsJARInputThunk::Read(char *buf, PRUint32 count, PRUint32 *countRead) +{ + nsresult rv = EnsureJarStream(); + if (NS_FAILED(rv)) return rv; + + return mJarStream->Read(buf, count, countRead); +} + +NS_IMETHODIMP +nsJARInputThunk::ReadSegments(nsWriteSegmentFun writer, void *closure, + PRUint32 count, PRUint32 *countRead) +{ + // stream transport does only calls Read() + NS_NOTREACHED("nsJarInputThunk::ReadSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsJARInputThunk::IsNonBlocking(PRBool *nonBlocking) +{ + *nonBlocking = PR_FALSE; + return NS_OK; +} + +//----------------------------------------------------------------------------- nsJARChannel::nsJARChannel() - : mLoadFlags(LOAD_NORMAL) - , mContentLength(-1) + : mContentLength(-1) + , mLoadFlags(LOAD_NORMAL) , mStatus(NS_OK) -#ifdef DEBUG - , mInitiator(nsnull) -#endif + , mIsPending(PR_FALSE) + , mJarInput(nsnull) { #if defined(PR_LOGGING) - // - // Initialize the global PRLogModule for socket transport logging - // if necessary... - // - if (nsnull == gJarProtocolLog) { + if (!gJarProtocolLog) gJarProtocolLog = PR_NewLogModule("nsJarProtocol"); - } -#endif /* PR_LOGGING */ +#endif + + // hold an owning reference to the jar handler + NS_ADDREF(gJarHandler); } nsJARChannel::~nsJARChannel() { - NS_IF_RELEASE(mJARProtocolHandler); + // release owning reference to the jar handler + nsJARProtocolHandler *handler = gJarHandler; + NS_RELEASE(handler); // NULL parameter } -NS_IMPL_THREADSAFE_ISUPPORTS7(nsJARChannel, - nsIJARChannel, - nsIChannel, - nsIRequest, - nsIRequestObserver, - nsIStreamListener, - nsIStreamIO, - nsIDownloadObserver) +NS_IMPL_ISUPPORTS6(nsJARChannel, + nsIRequest, + nsIChannel, + nsIStreamListener, + nsIRequestObserver, + nsIDownloadObserver, + nsIJARChannel) -NS_METHOD -nsJARChannel::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +nsresult +nsJARChannel::Init(nsIURI *uri) { nsresult rv; + mJarURI = do_QueryInterface(uri, &rv); - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - - nsJARChannel* jarChannel = new nsJARChannel(); - if (jarChannel == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(jarChannel); - rv = jarChannel->QueryInterface(aIID, aResult); - NS_RELEASE(jarChannel); +#if defined(PR_LOGGING) + mJarURI->GetSpec(mSpec); +#endif return rv; } - -nsresult -nsJARChannel::Init(nsJARProtocolHandler* aHandler, nsIURI* uri) + +nsresult +nsJARChannel::CreateJarInput() { - nsresult rv; - mURI = do_QueryInterface(uri, &rv); + // important to pass a clone of the file since the nsIFile impl is not + // necessarily MT-safe + nsCOMPtr clonedFile; + nsresult rv = mJarFile->Clone(getter_AddRefs(clonedFile)); if (NS_FAILED(rv)) return rv; - NS_ADDREF(mJARProtocolHandler = aHandler); + mJarInput = new nsJARInputThunk(clonedFile, mJarEntry, gJarHandler->JarCache()); + if (!mJarInput) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mJarInput); return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIRequest methods +nsresult +nsJARChannel::EnsureJarInput(PRBool blocking) +{ + LOG(("nsJARChannel::EnsureJarInput [this=%x %s]\n", this, mSpec.get())); + + nsresult rv; + nsCOMPtr uri; + + rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI)); + if (NS_FAILED(rv)) return rv; + + rv = mJarURI->GetJAREntry(mJarEntry); + if (NS_FAILED(rv)) return rv; + + // try to get a nsIFile directly from the url, which will often succeed. + { + nsCOMPtr fileURL = do_QueryInterface(mJarBaseURI); + if (fileURL) + fileURL->GetFile(getter_AddRefs(mJarFile)); + } + + if (mJarFile) { + rv = CreateJarInput(); + } + 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), + mJarBaseURI, this, nsnull, PR_FALSE, + mLoadGroup, mCallbacks, mLoadFlags); + } + return rv; + +} + +//----------------------------------------------------------------------------- +// nsIRequest +//----------------------------------------------------------------------------- NS_IMETHODIMP nsJARChannel::GetName(nsACString &result) { - return mURI->GetSpec(result); + return mJarURI->GetSpec(result); } NS_IMETHODIMP -nsJARChannel::IsPending(PRBool* result) +nsJARChannel::IsPending(PRBool *result) { - NS_NOTREACHED("nsJARChannel::IsPending"); - return NS_ERROR_NOT_IMPLEMENTED; + *result = mIsPending; + return NS_OK; } NS_IMETHODIMP nsJARChannel::GetStatus(nsresult *status) { - *status = mStatus; + if (mPump && NS_SUCCEEDED(mStatus)) + mPump->GetStatus(status); + else + *status = mStatus; return NS_OK; } NS_IMETHODIMP nsJARChannel::Cancel(nsresult status) { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); - nsresult rv = NS_OK; - - if (mJarExtractionTransport) { - rv = mJarExtractionTransport->Cancel(status); - mJarExtractionTransport = nsnull; - } - mStatus = status; - return rv; + if (mPump) + return mPump->Cancel(status); + + NS_ASSERTION(!mIsPending, "need to implement cancel when downloading"); + return NS_OK; } NS_IMETHODIMP nsJARChannel::Suspend() { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - nsresult rv = NS_OK; + if (mPump) + return mPump->Suspend(); - if (mJarExtractionTransport) { - rv = mJarExtractionTransport->Suspend(); - } - - return rv; + NS_ASSERTION(!mIsPending, "need to implement suspend when downloading"); + return NS_OK; } NS_IMETHODIMP nsJARChannel::Resume() { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - nsresult rv = NS_OK; + if (mPump) + return mPump->Resume(); - if (mJarExtractionTransport) { - rv = mJarExtractionTransport->Resume(); - } - - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIChannel methods - -NS_IMETHODIMP -nsJARChannel::GetOriginalURI(nsIURI* *aOriginalURI) -{ - if (mOriginalURI) - *aOriginalURI = mOriginalURI; - else - *aOriginalURI = NS_STATIC_CAST(nsIURI*, mURI); - - NS_IF_ADDREF(*aOriginalURI); + NS_ASSERTION(!mIsPending, "need to implement resume when downloading"); return NS_OK; } NS_IMETHODIMP -nsJARChannel::SetOriginalURI(nsIURI* aOriginalURI) -{ - mOriginalURI = aOriginalURI; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetURI(nsIURI* *aURI) -{ - *aURI = mURI; - NS_ADDREF(*aURI); - return NS_OK; -} - -nsresult -nsJARChannel::OpenJARElement() -{ - nsresult rv; - nsAutoCMonitor mon(this); - rv = Open(); - if (NS_SUCCEEDED(rv)) - rv = GetInputStream(getter_AddRefs(mSynchronousInputStream)); - mon.Notify(); // wake up nsIChannel::Open - return rv; -} - -NS_IMETHODIMP -nsJARChannel::Open(nsIInputStream* *result) -{ - nsAutoCMonitor mon(this); - nsresult rv; - mSynchronousRead = PR_TRUE; - rv = EnsureJARFileAvailable(); - if (NS_FAILED(rv)) return rv; - if (mSynchronousInputStream == nsnull) - mon.Wait(); - if (!mSynchronousInputStream) - return NS_ERROR_FAILURE; - - *result = mSynchronousInputStream; // Result of GetInputStream called on transport thread - NS_ADDREF(*result); - mSynchronousInputStream = 0; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::AsyncOpen(nsIStreamListener* listener, nsISupports* ctxt) -{ - nsresult rv; - -#ifdef DEBUG - mInitiator = PR_GetCurrentThread(); -#endif - - mUserContext = ctxt; - mUserListener = listener; - mSynchronousRead = PR_FALSE; - - if (mLoadGroup) { - rv = mLoadGroup->AddRequest(this, nsnull); - if (NS_FAILED(rv)) return rv; - } - - rv = EnsureJARFileAvailable(); - if (NS_FAILED(rv) && mLoadGroup) - mLoadGroup->RemoveRequest(this, nsnull, rv); - return rv; -} - -nsresult -nsJARChannel::EnsureJARFileAvailable() -{ - nsresult rv; - -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCAutoString jarURLStr; - mURI->GetSpec(jarURLStr); - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: EnsureJARFileAvailable %s", jarURLStr.get())); - } -#endif - - rv = mURI->GetJARFile(getter_AddRefs(mJARBaseURI)); - if (NS_FAILED(rv)) return rv; - - rv = mURI->GetJAREntry(mJAREntry); - if (NS_FAILED(rv)) return rv; - - // try to get a nsIFile directly from the url, which will often succeed. - { - nsCOMPtr fileURL = do_QueryInterface(mJARBaseURI); - if (fileURL) - fileURL->GetFile(getter_AddRefs(mDownloadedJARFile)); - } - - if (mDownloadedJARFile) { - // after successfully downloading the jar file to the cache, - // start the extraction process: - if (mSynchronousRead) - rv = OpenJARElement(); - else - rv = AsyncReadJARElement(); - } - else { - rv = NS_NewDownloader(getter_AddRefs(mDownloader), - mJARBaseURI, this, nsnull, mSynchronousRead, - mLoadGroup, mCallbacks, mLoadFlags); - - // if DownloadComplete() was called early, need to release the reference. - if (mSynchronousRead && mSynchronousInputStream) - mDownloader = 0; - } - return rv; -} - -nsresult -nsJARChannel::AsyncReadJARElement() -{ - nsresult rv; - - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr jarTransport; - rv = fts->CreateTransportFromStreamIO(this, PR_TRUE, getter_AddRefs(jarTransport)); - if (NS_FAILED(rv)) return rv; - - if (mCallbacks) { - nsCOMPtr sink = do_GetInterface(mCallbacks); - if (sink) { - // XXX don't think that this is needed anymore - // jarTransport->SetProgressEventSink(sink); - } - } - -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCAutoString jarURLStr; - mURI->GetSpec(jarURLStr); - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: AsyncRead jar entry %s", jarURLStr.get())); - } -#endif - - rv = jarTransport->AsyncRead(this, nsnull, 0, PRUint32(-1), 0, - getter_AddRefs(mJarExtractionTransport)); - jarTransport = 0; - return rv; -} - -NS_IMETHODIMP -nsJARChannel::GetLoadFlags(PRUint32* aLoadFlags) +nsJARChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) { *aLoadFlags = mLoadFlags; return NS_OK; } NS_IMETHODIMP -nsJARChannel::SetLoadFlags(PRUint32 aLoadFlags) +nsJARChannel::SetLoadFlags(nsLoadFlags aLoadFlags) { mLoadFlags = aLoadFlags; return NS_OK; } NS_IMETHODIMP -nsJARChannel::GetContentType(nsACString &aContentType) +nsJARChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) { - nsresult rv = NS_OK; - if (mContentType.IsEmpty()) { - if (mJAREntry.IsEmpty()) - return NS_ERROR_NOT_AVAILABLE; - const char *ext = nsnull, *fileName = mJAREntry.get(); - PRInt32 len = mJAREntry.Length(); - for (PRInt32 i = len-1; i >= 0; i--) { - if (fileName[i] == '.') { - ext = &fileName[i + 1]; - break; - } - } - if (ext) { - nsIMIMEService* mimeServ = mJARProtocolHandler->GetCachedMimeService(); - if (mimeServ) { - nsXPIDLCString mimeType; - rv = mimeServ->GetTypeFromExtension(ext, getter_Copies(mimeType)); - if (NS_SUCCEEDED(rv)) - mContentType = mimeType; - } - } - else - rv = NS_ERROR_NOT_AVAILABLE; + NS_IF_ADDREF(*aLoadGroup = mLoadGroup); + return NS_OK; +} - if (NS_FAILED(rv)) { - mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); - rv = NS_OK; +NS_IMETHODIMP +nsJARChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) +{ + mLoadGroup = aLoadGroup; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// nsIChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsJARChannel::GetOriginalURI(nsIURI **aURI) +{ + if (mOriginalURI) + *aURI = mOriginalURI; + else + *aURI = mJarURI; + NS_IF_ADDREF(*aURI); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::SetOriginalURI(nsIURI *aURI) +{ + mOriginalURI = aURI; + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetURI(nsIURI **aURI) +{ + NS_IF_ADDREF(*aURI = mJarURI); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetOwner(nsISupports **result) +{ + nsresult rv; + + if (mOwner) { + NS_ADDREF(*result = mOwner); + return NS_OK; + } + + if (!mJarInput) { + *result = nsnull; + return NS_OK; + } + + //-- Verify signature, if one is present, and set owner accordingly + nsCOMPtr jarReader; + mJarInput->GetJarReader(getter_AddRefs(jarReader)); + if (!jarReader) + return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr jar = do_QueryInterface(jarReader, &rv); + if (NS_FAILED(rv)) { + NS_ERROR("nsIJAR not supported"); + return rv; + } + + nsCOMPtr cert; + rv = jar->GetCertificatePrincipal(mJarEntry.get(), getter_AddRefs(cert)); + if (NS_FAILED(rv)) return rv; + + if (cert) { + // Get the codebase principal + nsCOMPtr secMan = + do_GetService(kScriptSecurityManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr codebase; + rv = secMan->GetCodebasePrincipal(mJarBaseURI, + getter_AddRefs(codebase)); + if (NS_FAILED(rv)) return rv; + + // Join the certificate and the codebase + nsCOMPtr agg = do_QueryInterface(cert, &rv); + if (NS_FAILED(rv)) return rv; + + rv = agg->SetCodebase(codebase); + if (NS_FAILED(rv)) return rv; + + mOwner = do_QueryInterface(agg, &rv); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = mOwner); + } + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::SetOwner(nsISupports *aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) +{ + NS_IF_ADDREF(*aCallbacks = mCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) +{ + mCallbacks = aCallbacks; + mProgressSink = do_GetInterface(mCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo) +{ + *aSecurityInfo = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsJARChannel::GetContentType(nsACString &result) +{ + nsresult rv; + + if (!mContentType.IsEmpty()) { + result = mContentType; + return NS_OK; + } + + // + // generate content type and set it + // + if (mJarEntry.IsEmpty()) { + LOG(("mJarEntry is empty!\n")); + return NS_ERROR_NOT_AVAILABLE; + } + + const char *ext = nsnull, *fileName = mJarEntry.get(); + PRInt32 len = mJarEntry.Length(); + for (PRInt32 i = len-1; i >= 0; i--) { + if (fileName[i] == '.') { + ext = &fileName[i + 1]; + break; + } + } + if (ext) { + nsIMIMEService *mimeServ = gJarHandler->MimeService(); + if (mimeServ) { + nsXPIDLCString mimeType; + rv = mimeServ->GetTypeFromExtension(ext, getter_Copies(mimeType)); + if (NS_SUCCEEDED(rv)) + mContentType = mimeType; } } - if (NS_SUCCEEDED(rv)) - aContentType = mContentType; else - aContentType.Truncate(); - return rv; + rv = NS_ERROR_NOT_AVAILABLE; + + if (NS_FAILED(rv) || mContentType.IsEmpty()) + mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE); + + result = mContentType; + return NS_OK; } NS_IMETHODIMP nsJARChannel::SetContentType(const nsACString &aContentType) { - mContentType = aContentType; + // mContentCharset is unchanged if not parsed + NS_ParseContentType(aContentType, mContentType, mContentCharset); return NS_OK; } @@ -438,274 +505,163 @@ nsJARChannel::SetContentCharset(const nsACString &aContentCharset) } NS_IMETHODIMP -nsJARChannel::GetContentLength(PRInt32* aContentLength) +nsJARChannel::GetContentLength(PRInt32 *result) { - NS_ENSURE_ARG_POINTER(aContentLength); - if (mContentLength == -1 && mJAR) { + if (mContentLength < 0 && mJarInput) { // ask the zip entry for the content length - nsresult rv; - nsCOMPtr entry; - rv = mJAR->GetEntry(mJAREntry.get(), getter_AddRefs(entry)); - if (NS_FAILED(rv)) return rv; - - rv = entry->GetRealSize((PRUint32*)&mContentLength); - if (NS_FAILED(rv)) return rv; + nsCOMPtr jarReader; + mJarInput->GetJarReader(getter_AddRefs(jarReader)); + if (jarReader) { + nsCOMPtr entry; + jarReader->GetEntry(mJarEntry.get(), getter_AddRefs(entry)); + if (entry) + entry->GetRealSize((PRUint32 *) &mContentLength); + } } - *aContentLength = mContentLength; + + *result = mContentLength; return NS_OK; } NS_IMETHODIMP nsJARChannel::SetContentLength(PRInt32 aContentLength) { - NS_NOTREACHED("nsJARChannel::SetContentLength"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsJARChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) -{ - *aLoadGroup = mLoadGroup; - NS_IF_ADDREF(*aLoadGroup); + // XXX does this really make any sense at all? + mContentLength = aContentLength; return NS_OK; } NS_IMETHODIMP -nsJARChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) +nsJARChannel::Open(nsIInputStream **stream) { - mLoadGroup = aLoadGroup; + LOG(("nsJARChannel::Open [this=%x]\n", this)); + + NS_ENSURE_TRUE(!mJarInput, NS_ERROR_IN_PROGRESS); + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + + nsresult rv = EnsureJarInput(PR_TRUE); + if (NS_FAILED(rv)) return rv; + + if (!mJarInput) + return NS_ERROR_UNEXPECTED; + + NS_ADDREF(*stream = mJarInput); return NS_OK; } NS_IMETHODIMP -nsJARChannel::GetOwner(nsISupports* *aOwner) +nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) { - nsresult rv; - if (mOwner == nsnull) { - //-- Verify signature, if one is present, and set owner accordingly - rv = EnsureZipReader(); + LOG(("nsJARChannel::AsyncOpen [this=%x]\n", this)); + + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + + nsresult rv = EnsureJarInput(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + if (mJarInput) { + // create input stream pump + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput); if (NS_FAILED(rv)) return rv; - nsCOMPtr jar = do_QueryInterface(mJAR, &rv); - NS_ASSERTION(NS_SUCCEEDED(rv), "Zip reader is not an nsIJAR"); - nsCOMPtr certificate; - rv = jar->GetCertificatePrincipal(mJAREntry.get(), - getter_AddRefs(certificate)); + rv = mPump->AsyncRead(this, nsnull); if (NS_FAILED(rv)) return rv; - if (certificate) - { // Get the codebase principal - nsCOMPtr secMan = - do_GetService(kScriptSecurityManagerCID, &rv); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - nsCOMPtr codebase; - rv = secMan->GetCodebasePrincipal(mJARBaseURI, - getter_AddRefs(codebase)); - if (NS_FAILED(rv)) return rv; - - // Join the certificate and the codebase - nsCOMPtr agg; - agg = do_QueryInterface(certificate, &rv); - rv = agg->SetCodebase(codebase); - if (NS_FAILED(rv)) return rv; - mOwner = do_QueryInterface(agg, &rv); - if (NS_FAILED(rv)) return rv; - } } - *aOwner = mOwner; - NS_IF_ADDREF(*aOwner); - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::SetOwner(nsISupports* aOwner) -{ - mOwner = aOwner; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) -{ - *aNotificationCallbacks = mCallbacks.get(); - NS_IF_ADDREF(*aNotificationCallbacks); - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) -{ - mCallbacks = aNotificationCallbacks; - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) -{ - *aSecurityInfo = nsnull; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIDownloadObserver methods: - -NS_IMETHODIMP -nsJARChannel::OnDownloadComplete(nsIDownloader* aDownloader, nsISupports* aClosure, - nsresult aStatus, nsIFile* aFile) -{ - nsresult rv=aStatus; - if(NS_SUCCEEDED(aStatus)) { - NS_ASSERTION(!mDownloader ||(aDownloader == mDownloader.get()), "wrong downloader"); - mDownloadedJARFile = aFile; - // after successfully downloading the jar file to the cache, - // start the extraction process: - if (mSynchronousRead) - rv = OpenJARElement(); - else - rv = AsyncReadJARElement(); - } - mDownloader = 0; - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsIRequestObserver methods: - -NS_IMETHODIMP -nsJARChannel::OnStartRequest(nsIRequest* jarExtractionTransport, - nsISupports* context) -{ -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - return mUserListener->OnStartRequest(this, mUserContext); -} - -NS_IMETHODIMP -nsJARChannel::OnStopRequest(nsIRequest* jarExtractionTransport, nsISupports* context, - nsresult aStatus) -{ - nsresult rv; -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCOMPtr jarURI; - nsCAutoString jarURLStr; - rv = mURI->GetSpec(jarURLStr); - if (NS_SUCCEEDED(rv)) { - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: jar extraction complete %s status=%x", - jarURLStr.get(), aStatus)); - } - } -#endif - - rv = mUserListener->OnStopRequest(this, mUserContext, aStatus); - NS_ASSERTION(NS_SUCCEEDED(rv), "OnStopRequest failed"); if (mLoadGroup) - mLoadGroup->RemoveRequest(this, context, aStatus); + mLoadGroup->AddRequest(this, nsnull); - mUserListener = nsnull; - mUserContext = nsnull; - mJarExtractionTransport = nsnull; - return rv; + mListener = listener; + mListenerContext = ctx; + mIsPending = PR_TRUE; + return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamListener methods: +//----------------------------------------------------------------------------- +// nsIDownloadObserver +//----------------------------------------------------------------------------- NS_IMETHODIMP -nsJARChannel::OnDataAvailable(nsIRequest* jarCacheTransport, - nsISupports* context, - nsIInputStream *inStr, - PRUint32 sourceOffset, - PRUint32 count) +nsJARChannel::OnDownloadComplete(nsIDownloader *downloader, + nsISupports *closure, + nsresult status, + nsIFile *file) { -#ifdef DEBUG - NS_ASSERTION(mInitiator == PR_GetCurrentThread(), "wrong thread"); -#endif - return mUserListener->OnDataAvailable(this, mUserContext, - inStr, sourceOffset, count); + if (NS_SUCCEEDED(status)) { + mJarFile = file; + + nsresult rv = CreateJarInput(); + if (NS_SUCCEEDED(rv)) { + // create input stream pump + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput); + if (NS_SUCCEEDED(rv)) + rv = mPump->AsyncRead(this, nsnull); + } + status = rv; + } + + if (NS_FAILED(status)) { + OnStartRequest(nsnull, nsnull); + OnStopRequest(nsnull, nsnull, status); + } + + mDownloader = 0; + return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIStreamIO methods: +//----------------------------------------------------------------------------- +// nsIStreamListener +//----------------------------------------------------------------------------- -nsresult -nsJARChannel::EnsureZipReader() +NS_IMETHODIMP +nsJARChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx) { - if (mJAR == nsnull) { - nsresult rv; - if (mDownloadedJARFile == nsnull) - return NS_ERROR_FAILURE; + LOG(("nsJARChannel::OnStartRequest [this=%x %s]\n", this, mSpec.get())); - nsCOMPtr jarCache; - rv = mJARProtocolHandler->GetJARCache(getter_AddRefs(jarCache)); - if (NS_FAILED(rv)) return rv; + return mListener->OnStartRequest(this, mListenerContext); +} - rv = jarCache->GetZip(mDownloadedJARFile, getter_AddRefs(mJAR)); - if (NS_FAILED(rv)) return rv; +NS_IMETHODIMP +nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) +{ + LOG(("nsJARChannel::OnStopRequest [this=%x %s status=%x]\n", + this, mSpec.get(), status)); + + if (NS_SUCCEEDED(mStatus)) + mStatus = status; + + if (mListener) { + mListener->OnStopRequest(this, mListenerContext, status); + mListener = 0; + mListenerContext = 0; } + + if (mLoadGroup) + mLoadGroup->RemoveRequest(this, nsnull, status); + + mPump = 0; + NS_IF_RELEASE(mJarInput); + mIsPending = PR_FALSE; return NS_OK; } NS_IMETHODIMP -nsJARChannel::Open() +nsJARChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, + nsIInputStream *stream, + PRUint32 offset, PRUint32 count) { - return EnsureZipReader(); -} - -NS_IMETHODIMP -nsJARChannel::Close(nsresult status) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsJARChannel::GetInputStream(nsIInputStream* *aInputStream) -{ -#ifdef PR_LOGGING - if (PR_LOG_TEST(gJarProtocolLog, PR_LOG_DEBUG)) { - nsCAutoString jarURLStr; - mURI->GetSpec(jarURLStr); - PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, - ("nsJarProtocol: GetInputStream jar entry %s", jarURLStr.get())); - } +#if defined(PR_LOGGING) + LOG(("nsJARChannel::OnDataAvailable [this=%x %s]\n", this, mSpec.get())); #endif - NS_ENSURE_TRUE(mJAR, NS_ERROR_NULL_POINTER); - nsresult rv = mJAR->GetInputStream(mJAREntry.get(), aInputStream); - if (NS_SUCCEEDED(rv)) - (*aInputStream)->Available((PRUint32 *) &mContentLength); - return rv; -} - -NS_IMETHODIMP -nsJARChannel::GetOutputStream(nsIOutputStream* *aOutputStream) -{ - NS_NOTREACHED("nsJARChannel::GetOutputStream"); - return NS_ERROR_NOT_IMPLEMENTED; -} -NS_IMETHODIMP -nsJARChannel::GetName(char* *aName) -{ - nsCAutoString spec; - nsresult rv = mURI->GetSpec(spec); - if (NS_FAILED(rv)) return rv; - *aName = ToNewCString(spec); - return *aName ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + nsresult rv; + + rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); + + // simply report progress here instead of hooking ourselves up as a + // nsITransportEventSink implementation. + if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND)) + mProgressSink->OnProgress(this, nsnull, offset + count, mContentLength); + + return rv; // let the pump cancel on failure } - -//////////////////////////////////////////////////////////////////////////////// -// nsIJARChannel methods: - -NS_IMETHODIMP -nsJARChannel::EnumerateEntries(const char *aRoot, nsISimpleEnumerator **_retval) -{ - NS_NOTREACHED("nsJARChannel::EnumerateEntries"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/netwerk/protocol/jar/src/nsJARChannel.h b/mozilla/netwerk/protocol/jar/src/nsJARChannel.h index 89045eb094a..4d4d361962f 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARChannel.h +++ b/mozilla/netwerk/protocol/jar/src/nsJARChannel.h @@ -39,104 +39,70 @@ #define nsJARChannel_h__ #include "nsIJARChannel.h" -#include "nsIStreamListener.h" -#include "nsIJARProtocolHandler.h" #include "nsIJARURI.h" -#include "nsIStreamIO.h" -#include "nsIChannel.h" -#include "nsIZipReader.h" -#include "nsIChannel.h" -#include "nsILoadGroup.h" +#include "nsIInputStreamPump.h" #include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsCOMPtr.h" -#include "nsIFile.h" -#include "prmon.h" +#include "nsIProgressEventSink.h" +#include "nsIStreamListener.h" #include "nsIDownloader.h" -#include "nsIInputStream.h" -#include "nsJARProtocolHandler.h" +#include "nsILoadGroup.h" +#include "nsIFile.h" +#include "nsIURI.h" +#include "nsCOMPtr.h" #include "nsString.h" +#include "prlog.h" -#ifdef DEBUG -#include "prthread.h" -#endif +class nsJARInputThunk; -class nsIFileChannel; -class nsJARChannel; +//----------------------------------------------------------------------------- -#define NS_JARCHANNEL_CID \ -{ /* 0xc7e410d5-0x85f2-11d3-9f63-006008a6efe9 */ \ - 0xc7e410d5, \ - 0x85f2, \ - 0x11d3, \ - {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ -} - -class nsJARChannel : public nsIJARChannel, - public nsIStreamListener, - public nsIStreamIO, - public nsIDownloadObserver +class nsJARChannel : public nsIJARChannel + , public nsIDownloadObserver + , public nsIStreamListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL NS_DECL_NSIJARCHANNEL + NS_DECL_NSIDOWNLOADOBSERVER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIDOWNLOADOBSERVER - - // NS_DECL_NSISTREAMIO and nsIChannel both define (attribute string contentType) - - NS_IMETHOD Open(); - NS_IMETHOD Close(nsresult status); - NS_IMETHOD GetInputStream(nsIInputStream * *aInputStream); - NS_IMETHOD GetOutputStream(nsIOutputStream * *aOutputStream); - NS_IMETHOD GetName(char * *aName); nsJARChannel(); virtual ~nsJARChannel(); - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, REFNSIID aIID, void **aResult); + nsresult Init(nsIURI *uri); - nsresult Init(nsJARProtocolHandler* aHandler, nsIURI* uri); - nsresult EnsureJARFileAvailable(); - nsresult OpenJARElement(); - nsresult AsyncReadJARElement(); - nsresult EnsureZipReader(); +private: + nsresult CreateJarInput(); + nsresult EnsureJarInput(PRBool blocking); - friend class nsJARDownloadObserver; - -protected: - nsJARProtocolHandler* mJARProtocolHandler; - nsCOMPtr mURI; - nsCOMPtr mLoadGroup; - nsCOMPtr mCallbacks; - nsCOMPtr mOriginalURI; - nsLoadFlags mLoadFlags; - nsCOMPtr mOwner; - - nsCOMPtr mUserContext; - nsCOMPtr mUserListener; - - nsCString mContentType; - nsCString mContentCharset; - PRInt32 mContentLength; - nsCOMPtr mJARBaseURI; - nsCString mJAREntry; - nsCOMPtr mJAR; - nsCOMPtr mDownloadedJARFile; - nsresult mStatus; - PRBool mSynchronousRead; - nsCOMPtr mSynchronousInputStream; - - nsCOMPtr mDownloader; - nsCOMPtr mJarExtractionTransport; -#ifdef DEBUG - PRThread* mInitiator; +#if defined(PR_LOGGING) + nsCString mSpec; #endif + + nsCOMPtr mJarURI; + nsCOMPtr mOriginalURI; + nsCOMPtr mOwner; + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; + nsCOMPtr mLoadGroup; + nsCOMPtr mListener; + nsCOMPtr mListenerContext; + nsCString mContentType; + nsCString mContentCharset; + PRInt32 mContentLength; + PRUint32 mLoadFlags; + nsresult mStatus; + PRBool mIsPending; + + nsJARInputThunk *mJarInput; + nsCOMPtr mPump; + nsCOMPtr mDownloader; + nsCOMPtr mJarFile; + nsCOMPtr mJarBaseURI; + nsCString mJarEntry; }; #endif // nsJARChannel_h__ diff --git a/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.cpp b/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.cpp index 141a55ab015..24f18bd1eb5 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.cpp +++ b/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.cpp @@ -52,12 +52,20 @@ static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID); -#define NS_JAR_CACHE_SIZE 32 +#define NS_JAR_CACHE_SIZE 32 -//////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- + +nsJARProtocolHandler *gJarHandler = nsnull; nsJARProtocolHandler::nsJARProtocolHandler() { + gJarHandler = this; +} + +nsJARProtocolHandler::~nsJARProtocolHandler() +{ + gJarHandler = nsnull; } nsresult @@ -74,17 +82,13 @@ nsJARProtocolHandler::Init() return rv; } -nsIMIMEService* -nsJARProtocolHandler::GetCachedMimeService() +nsIMIMEService * +nsJARProtocolHandler::MimeService() { - if (!mMimeService) { + if (!mMimeService) mMimeService = do_GetService(NS_MIMESERVICE_CONTRACTID); - } - return mMimeService.get(); -} -nsJARProtocolHandler::~nsJARProtocolHandler() -{ + return mMimeService.get(); } NS_IMPL_THREADSAFE_ISUPPORTS3(nsJARProtocolHandler, @@ -124,7 +128,7 @@ nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result) NS_IMETHODIMP nsJARProtocolHandler::GetScheme(nsACString &result) { - result = "jar"; + result = NS_LITERAL_CSTRING("jar"); return NS_OK; } @@ -185,21 +189,20 @@ nsJARProtocolHandler::NewURI(const nsACString &aSpec, } NS_IMETHODIMP -nsJARProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) +nsJARProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result) { - nsresult rv; + nsJARChannel *chan = new nsJARChannel(); + if (!chan) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(chan); - nsJARChannel* channel; - rv = nsJARChannel::Create(nsnull, NS_GET_IID(nsIJARChannel), (void**)&channel); - if (NS_FAILED(rv)) return rv; - - rv = channel->Init(this, uri); + nsresult rv = chan->Init(uri); if (NS_FAILED(rv)) { - NS_RELEASE(channel); + NS_RELEASE(chan); return rv; } - *result = channel; + *result = chan; return NS_OK; } diff --git a/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.h b/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.h index debfd0c4034..dfe008b07a7 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.h +++ b/mozilla/netwerk/protocol/jar/src/nsJARProtocolHandler.h @@ -35,8 +35,8 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsJARProtocolHandler_h___ -#define nsJARProtocolHandler_h___ +#ifndef nsJARProtocolHandler_h__ +#define nsJARProtocolHandler_h__ #include "nsIJARProtocolHandler.h" #include "nsIProtocolHandler.h" @@ -46,15 +46,6 @@ #include "nsWeakReference.h" #include "nsCOMPtr.h" -#define NS_JARPROTOCOLHANDLER_CID \ -{ /* 0xc7e410d4-0x85f2-11d3-9f63-006008a6efe9 */ \ - 0xc7e410d4, \ - 0x85f2, \ - 0x11d3, \ - {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ -} - - class nsJARProtocolHandler : public nsIJARProtocolHandler , public nsSupportsWeakReference { @@ -73,11 +64,14 @@ public: nsresult Init(); // returns non addref'ed pointer. - nsIMIMEService* GetCachedMimeService(); + nsIMIMEService *MimeService(); + nsIZipReaderCache *JarCache() { return mJARCache; } protected: nsCOMPtr mJARCache; nsCOMPtr mMimeService; }; -#endif /* nsJARProtocolHandler_h___ */ +extern nsJARProtocolHandler *gJarHandler; + +#endif // !nsJARProtocolHandler_h__ diff --git a/mozilla/netwerk/protocol/jar/src/nsJARURI.h b/mozilla/netwerk/protocol/jar/src/nsJARURI.h index 695c7ed1e9e..903944a573c 100644 --- a/mozilla/netwerk/protocol/jar/src/nsJARURI.h +++ b/mozilla/netwerk/protocol/jar/src/nsJARURI.h @@ -24,14 +24,6 @@ #include "nsCOMPtr.h" #include "nsString.h" -#define NS_JARURI_CID \ -{ /* 0xc7e410d7-0x85f2-11d3-9f63-006008a6efe9 */ \ - 0xc7e410d7, \ - 0x85f2, \ - 0x11d3, \ - {0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \ -} - class nsJARURI : public nsIJARURI, nsISerializable { public: diff --git a/mozilla/netwerk/resources/locale/en-US/necko.properties b/mozilla/netwerk/resources/locale/en-US/necko.properties index 0c43e95da42..cefbb406b03 100644 --- a/mozilla/netwerk/resources/locale/en-US/necko.properties +++ b/mozilla/netwerk/resources/locale/en-US/necko.properties @@ -40,6 +40,7 @@ ReceivingFrom=Transferring data from %1$S... ConnectingTo=Connecting to %1$S... ReadFrom=Read %1$S WroteTo=Wrote %1$S +WaitingFor=Waiting for %1$S... BeginFTPTransaction=Beginning FTP transaction... EndFTPTransaction=Finished FTP transaction EnterUserPasswordForRealm=Enter username and password for %1$S at %2$S diff --git a/mozilla/netwerk/streamconv/converters/Makefile.in b/mozilla/netwerk/streamconv/converters/Makefile.in index 01b70298ff5..0937de13f45 100644 --- a/mozilla/netwerk/streamconv/converters/Makefile.in +++ b/mozilla/netwerk/streamconv/converters/Makefile.in @@ -37,7 +37,6 @@ REQUIRES = xpcom \ util \ pref \ uconv \ - exthandler \ imglib2 \ necko2 \ $(ZLIB_REQUIRES) \ @@ -45,7 +44,6 @@ REQUIRES = xpcom \ CPPSRCS = \ ParseFTPList.cpp \ - nsMultiMixedConv.cpp \ nsFTPDirListingConv.cpp \ nsGopherDirListingConv.cpp \ mozTXTToHTMLConv.cpp \ @@ -55,8 +53,10 @@ CPPSRCS = \ nsDirIndex.cpp \ nsDirIndexParser.cpp \ nsIndexedToHTML.cpp \ + nsMultiMixedConv.cpp \ $(NULL) + ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) CPPSRCS += \ nsBinHexDecoder.cpp \ diff --git a/mozilla/netwerk/streamconv/converters/nsBinHexDecoder.cpp b/mozilla/netwerk/streamconv/converters/nsBinHexDecoder.cpp index a3b392116d6..759f65899ca 100644 --- a/mozilla/netwerk/streamconv/converters/nsBinHexDecoder.cpp +++ b/mozilla/netwerk/streamconv/converters/nsBinHexDecoder.cpp @@ -50,7 +50,6 @@ #include "nsIMIMEService.h" #include "nsMimeTypes.h" -#include "nsCExternalHandlerService.h" static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); @@ -515,7 +514,7 @@ nsresult nsBinHexDecoder::SetContentType(nsIRequest * aRequest, const char * fil return NS_ERROR_FAILURE; } - nsCOMPtr mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv)); + nsCOMPtr mimeService (do_GetService("@mozilla.org/mime;1", &rv)); NS_ENSURE_SUCCESS(rv, rv); nsXPIDLCString contentType; diff --git a/mozilla/netwerk/streamconv/converters/nsFTPDirListingConv.cpp b/mozilla/netwerk/streamconv/converters/nsFTPDirListingConv.cpp index c5f2df230ad..713e9f0ebeb 100644 --- a/mozilla/netwerk/streamconv/converters/nsFTPDirListingConv.cpp +++ b/mozilla/netwerk/streamconv/converters/nsFTPDirListingConv.cpp @@ -109,12 +109,12 @@ nsFTPDirListingConv::AsyncConvertData(const PRUnichar *aFromType, const PRUnicha rv = aCtxt->QueryInterface(NS_GET_IID(nsIURI), (void**)&uri); if (NS_FAILED(rv)) return rv; + // XXX this seems really wrong!! rv = NS_NewInputStreamChannel(&mPartChannel, uri, nsnull, NS_LITERAL_CSTRING(APPLICATION_HTTP_INDEX_FORMAT), - NS_LITERAL_CSTRING(""), - -1); // XXX fix contentLength + NS_LITERAL_CSTRING("")); NS_RELEASE(uri); if (NS_FAILED(rv)) return rv; diff --git a/mozilla/netwerk/streamconv/converters/nsGopherDirListingConv.cpp b/mozilla/netwerk/streamconv/converters/nsGopherDirListingConv.cpp index f99c456520b..fcf45c2ca40 100644 --- a/mozilla/netwerk/streamconv/converters/nsGopherDirListingConv.cpp +++ b/mozilla/netwerk/streamconv/converters/nsGopherDirListingConv.cpp @@ -134,12 +134,12 @@ nsGopherDirListingConv::AsyncConvertData(const PRUnichar *aFromType, mUri = do_QueryInterface(aCtxt,&rv); if (NS_FAILED(rv)) return rv; + // XXX this seems really wrong!! rv = NS_NewInputStreamChannel(&mPartChannel, mUri, nsnull, NS_LITERAL_CSTRING(APPLICATION_HTTP_INDEX_FORMAT), - NS_LITERAL_CSTRING(""), - -1); + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; return NS_OK; diff --git a/mozilla/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp b/mozilla/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp index ab85a55dcbf..cf78478df11 100644 --- a/mozilla/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp +++ b/mozilla/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp @@ -82,8 +82,9 @@ nsTXTToHTMLConv::OnStartRequest(nsIRequest* request, nsISupports *aContext) { // be parsed in OnDataAvailable(). nsCOMPtr channel = do_QueryInterface(request); - NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED); - channel->SetContentType(NS_LITERAL_CSTRING("text/html")); + if (channel) + channel->SetContentType(NS_LITERAL_CSTRING("text/html")); + // else, assume there is a channel somewhere that knows what it is doing! nsresult rv = mListener->OnStartRequest(request, aContext); if (NS_FAILED(rv)) return rv; diff --git a/mozilla/netwerk/test/Makefile.in b/mozilla/netwerk/test/Makefile.in index 16acaeb3e0f..e233d351be9 100644 --- a/mozilla/netwerk/test/Makefile.in +++ b/mozilla/netwerk/test/Makefile.in @@ -36,25 +36,31 @@ REQUIRES = xpcom \ CPPSRCS = \ PropertiesTest.cpp \ - TestSocketIO.cpp \ - TestSocketInput.cpp \ - TestSocketTransport.cpp \ - TestFileInput.cpp \ - TestFileTransport.cpp \ - TestProtocols.cpp \ - TestHttp.cpp \ urltest.cpp \ - TestFileInput2.cpp \ TestCallbacks.cpp \ - TestMCTransport.cpp \ TestPageLoad.cpp \ TestPerf.cpp \ TestIDN.cpp \ TestURLParser.cpp \ TestStandardURL.cpp \ + TestSocketTransport.cpp \ TestUpload.cpp \ + TestStreamTransport.cpp \ + TestStreamChannel.cpp \ + TestStreamPump.cpp \ + TestProtocols.cpp \ + TestBlockingSocket.cpp \ $(NULL) +# TestHttp.cpp \ +# TestFileInput.cpp \ +# TestFileInput2.cpp \ +# TestMCTransport.cpp \ +# TestSocketIO.cpp \ +# TestSocketInput.cpp \ +# TestSocketTransport.cpp \ +# TestFileTransport.cpp + SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) include $(topsrcdir)/config/config.mk diff --git a/mozilla/netwerk/test/TestPerf.cpp b/mozilla/netwerk/test/TestPerf.cpp index 70cd909bfd1..401941c14f3 100644 --- a/mozilla/netwerk/test/TestPerf.cpp +++ b/mozilla/netwerk/test/TestPerf.cpp @@ -15,11 +15,11 @@ load_sync_1(nsISupports *element, void *data) { nsCOMPtr stream; nsCOMPtr uri( do_QueryInterface(element) ); + nsCAutoString spec; nsresult rv; rv = NS_OpenURI(getter_AddRefs(stream), uri, gIOService); if (NS_FAILED(rv)) { - nsCAutoString spec; uri->GetAsciiSpec(spec); fprintf(stderr, "*** failed opening %s [rv=%x]\n", spec.get(), rv); return PR_TRUE; @@ -30,8 +30,13 @@ load_sync_1(nsISupports *element, void *data) while (1) { rv = stream->Read(buf, sizeof(buf), &bytesRead); - if (NS_FAILED(rv) || bytesRead == 0) + if (NS_FAILED(rv) || bytesRead == 0) { + if (NS_FAILED(rv)) { + uri->GetAsciiSpec(spec); + fprintf(stderr, "*** failed reading %s [rv=%x]\n", spec.get(), rv); + } break; + } } return PR_TRUE; @@ -107,7 +112,7 @@ MyListener::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) if (NS_FAILED(status)) { nsCAutoString spec; req->GetName(spec); - fprintf(stderr, "*** failed loading %s\n", spec.get()); + fprintf(stderr, "*** failed loading %s [reason=%x]\n", spec.get(), status); } if (--gRequestCount == 0) { // post shutdown event diff --git a/mozilla/netwerk/test/TestProtocols.cpp b/mozilla/netwerk/test/TestProtocols.cpp index cbaf24a335e..0484b05a591 100644 --- a/mozilla/netwerk/test/TestProtocols.cpp +++ b/mozilla/netwerk/test/TestProtocols.cpp @@ -71,6 +71,15 @@ #include "nsISimpleEnumerator.h" #include "nsXPIDLString.h" #include "nsNetUtil.h" +#include "prlog.h" + +#if defined(PR_LOGGING) +// +// set NSPR_LOG_MODULES=Test:5 +// +static PRLogModuleInfo *gTestLog = nsnull; +#endif +#define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); @@ -101,9 +110,9 @@ NS_IMPL_ISUPPORTS1(HeaderVisitor, nsIHttpHeaderVisitor) NS_IMETHODIMP HeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value) { - printf("%s: %s\n", + LOG((" %s: %s\n", PromiseFlatCString(header).get(), - PromiseFlatCString(value).get()); + PromiseFlatCString(value).get())); return NS_OK; } @@ -166,18 +175,10 @@ TestHttpEventSink::~TestHttpEventSink() NS_IMPL_ISUPPORTS1(TestHttpEventSink, nsIHttpEventSink); -#if 0 -NS_IMETHODIMP -TestHTTPEventSink::OnHeadersAvailable(nsISupports* context) -{ - return NS_OK; -} -#endif - NS_IMETHODIMP TestHttpEventSink::OnRedirect(nsIHttpChannel *channel, nsIChannel *newChannel) { - printf("\n+++ TestHTTPEventSink::OnRedirect +++\n"); + LOG(("\n+++ TestHTTPEventSink::OnRedirect +++\n")); return NS_OK; } @@ -210,12 +211,14 @@ NS_IMPL_ISUPPORTS2(InputTestConsumer, nsIStreamListener, nsIRequestObserver) NS_IMETHODIMP InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) { + LOG(("InputTestConsumer::OnStartRequest\n")); + URLLoadInfo* info = (URLLoadInfo*)context; if (info) info->mConnectTime = PR_Now() - info->mConnectTime; if (gVerbose) - printf("\nStarted loading: %s\n", info ? info->Name() : "UNKNOWN URL"); + LOG(("\nStarted loading: %s\n", info ? info->Name() : "UNKNOWN URL")); nsCAutoString value; @@ -224,20 +227,27 @@ InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) nsresult status; channel->GetStatus(&status); if (NS_SUCCEEDED(status)) { - printf("Channel Info:\n"); + LOG(("Channel Info:\n")); + + channel->GetName(value); + LOG(("\tName: %s\n", value.get())); channel->GetContentType(value); - printf("\tContent-Type: %s\n", value.get()); + LOG(("\tContent-Type: %s\n", value.get())); channel->GetContentCharset(value); - printf("\tContent-Charset: %s\n", value.get()); + LOG(("\tContent-Charset: %s\n", value.get())); PRInt32 length = -1; if (NS_SUCCEEDED(channel->GetContentLength(&length))) - printf("\tContent-Length: %d\n", length); + LOG(("\tContent-Length: %d\n", length)); else - printf("\tContent-Length: Unknown\n"); + LOG(("\tContent-Length: Unknown\n")); } + + nsCOMPtr owner; + channel->GetOwner(getter_AddRefs(owner)); + LOG(("\tChannel Owner: %x\n", owner.get())); } nsCOMPtr httpChannel(do_QueryInterface(request)); @@ -247,10 +257,10 @@ InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(visitor); - printf("\nHTTP request headers:\n"); + LOG(("HTTP request headers:\n")); httpChannel->VisitRequestHeaders(visitor); - printf("\nHTTP response headers:\n"); + LOG(("HTTP response headers:\n")); httpChannel->VisitResponseHeaders(visitor); NS_RELEASE(visitor); @@ -258,16 +268,16 @@ InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) nsCOMPtr resChannel = do_QueryInterface(request); if (resChannel) { - printf("Resumable entity identification:\n"); + LOG(("Resumable entity identification:\n")); nsCOMPtr entityID; nsresult rv = resChannel->GetEntityID(getter_AddRefs(entityID)); if (NS_SUCCEEDED(rv) && entityID) { PRUint32 size; if (NS_SUCCEEDED(entityID->GetSize(&size)) && size != PRUint32(-1)) - printf("\tSize: %d\n", size); + LOG(("\tSize: %d\n", size)); else - printf("\tSize: Unknown\n"); + LOG(("\tSize: Unknown\n")); PRTime lastModified; if (NS_SUCCEEDED(entityID->GetLastModified(&lastModified)) && lastModified != -1) { @@ -277,9 +287,9 @@ InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) char buf[100]; PR_FormatTime(buf, 100, "%c", &exploded); - printf("\tLast Modified: %s\n", buf); + LOG(("\tLast Modified: %s\n", buf)); } else - printf("\tLast Modified: Unknown\n"); + LOG(("\tLast Modified: Unknown\n")); } } @@ -293,7 +303,6 @@ InputTestConsumer::OnDataAvailable(nsIRequest *request, PRUint32 aSourceOffset, PRUint32 aLength) { - char buf[1025]; PRUint32 amt, size; nsresult rv; @@ -348,6 +357,8 @@ NS_IMETHODIMP InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context, nsresult aStatus) { + LOG(("InputTestConsumer::OnStopRequest [status=%x]\n", aStatus)); + URLLoadInfo* info = (URLLoadInfo*)context; if (info) { @@ -367,24 +378,24 @@ InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context, bHTTPURL = PR_TRUE; } - printf("\nFinished loading: %s Status Code: %x\n", info->Name(), aStatus); + LOG(("\nFinished loading: %s Status Code: %x\n", info->Name(), aStatus)); if (bHTTPURL) - printf("\tHTTP Status: %u\n", httpStatus); + LOG(("\tHTTP Status: %u\n", httpStatus)); if (NS_ERROR_UNKNOWN_HOST == aStatus || NS_ERROR_UNKNOWN_PROXY_HOST == aStatus) { - printf("\tDNS lookup failed.\n"); + LOG(("\tDNS lookup failed.\n")); } - printf("\tTime to connect: %.3f seconds\n", connectTime); - printf("\tTime to read: %.3f seconds.\n", readTime); - printf("\tRead: %d bytes.\n", info->mBytesRead); + LOG(("\tTime to connect: %.3f seconds\n", connectTime)); + LOG(("\tTime to read: %.3f seconds.\n", readTime)); + LOG(("\tRead: %d bytes.\n", info->mBytesRead)); if (!info->mBytesRead) { } else if (readTime > 0.0) { - printf("\tThroughput: %.0f bps.\n", (info->mBytesRead*8)/readTime); + LOG(("\tThroughput: %.0f bps.\n", (info->mBytesRead*8)/readTime)); } else { - printf("\tThroughput: REAL FAST!!\n"); + LOG(("\tThroughput: REAL FAST!!\n")); } } else { - printf("\nFinished loading: UNKNOWN URL. Status Code: %x\n", aStatus); + LOG(("\nFinished loading: UNKNOWN URL. Status Code: %x\n", aStatus)); } FireDecrement(); @@ -435,14 +446,14 @@ nsresult StartLoadingURL(const char* aUrlString) rv = pService->NewURI(nsDependentCString(aUrlString), nsnull, nsnull, getter_AddRefs(pURL)); if (NS_FAILED(rv)) { - printf("ERROR: NewURI failed for %s\n", aUrlString); + LOG(("ERROR: NewURI failed for %s [rv=%x]\n", aUrlString)); return rv; } nsCOMPtr pChannel; NotificationCallbacks* callbacks = new NotificationCallbacks(); if (!callbacks) { - NS_ERROR("Failed to create a new consumer!"); + LOG(("Failed to create a new consumer!")); return NS_ERROR_OUT_OF_MEMORY;; } NS_ADDREF(callbacks); @@ -453,7 +464,7 @@ nsresult StartLoadingURL(const char* aUrlString) callbacks); // notificationCallbacks NS_RELEASE(callbacks); if (NS_FAILED(rv)) { - printf("ERROR: NS_OpenURI failed for %s\n", aUrlString); + LOG(("ERROR: NS_OpenURI failed for %s [rv=%x]\n", aUrlString, rv)); return rv; } @@ -506,6 +517,9 @@ nsresult StartLoadingURL(const char* aUrlString) if (NS_SUCCEEDED(rv)) { gKeepRunning += 1; } + else { + LOG(("ERROR: AsyncOpen failed [rv=%x]\n", rv)); + } NS_RELEASE(listener); NS_RELEASE(info); } @@ -540,7 +554,7 @@ nsresult LoadURLsFromFile(char *aFileName) urlString.StripChars("\r"); if (urlString.Length()) { - printf("\t%s\n", urlString.get()); + LOG(("\t%s\n", urlString.get())); rv = StartLoadingURL(urlString.get()); } } @@ -550,7 +564,7 @@ nsresult LoadURLsFromFile(char *aFileName) // If anything is left in the fileBuffer, treat it as a URL... fileBuffer.StripChars("\r"); if (fileBuffer.Length()) { - printf("\t%s\n", fileBuffer.get()); + LOG(("\t%s\n", fileBuffer.get())); StartLoadingURL(fileBuffer.get()); } @@ -580,6 +594,10 @@ main(int argc, char* argv[]) return -1; } +#if defined(PR_LOGGING) + gTestLog = PR_NewLogModule("Test"); +#endif + /* The following code only deals with XPCOM registration stuff. and setting up the event queues. Copied from TestSocketIO.cpp @@ -597,7 +615,7 @@ main(int argc, char* argv[]) eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); int i; - printf("\nTrying to load:\n"); + LOG(("Trying to load:\n")); for (i=1; i * * 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 -#ifdef WIN32 -//#define USE_TIMERS // Only use nsITimer on Windows (for now...) -#include -#endif -#ifdef XP_OS2 -#include -#endif - -#include "nspr.h" -#ifdef XP_MAC -#include "pprio.h" // PR_Init_Log -#endif - -#include "nsITransport.h" -#include "nsIRequest.h" -#include "nsISocketTransportService.h" -#include "nsIEventQueueService.h" -#include "nsIServiceManager.h" #include "nsIComponentRegistrar.h" -#include "nsIRequestObserver.h" -#include "nsIStreamListener.h" -#include "nsIPipe.h" -#include "nsIInputStream.h" -#include "nsIOutputStream.h" -#include "nsIRunnable.h" -#include "nsIThread.h" -#include "nsITimer.h" +#include "nsISocketTransportService.h" +#include "nsISocketTransport.h" +#include "nsIAsyncInputStream.h" +#include "nsIAsyncOutputStream.h" +#include "nsIProgressEventSink.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIProgressEventSink.h" -#include "nsCRT.h" +#include "nsIProxyObjectManager.h" +#include "nsIRequest.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsString.h" +#include "nsIFileStreams.h" +#include "nsIStreamListener.h" +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" +#include "nsILocalFile.h" #include "nsNetUtil.h" +#include "nsAutoLock.h" +#include "prlog.h" -#if defined(XP_MAC) -#include "macstdlibextras.h" - // Set up the toolbox and (if DEBUG) the console. Do this in a static initializer, - // to make it as unlikely as possible that somebody calls printf() before we get initialized. -static struct MacInitializer { MacInitializer() { InitializeMacToolbox(); InitializeSIOUX(true); } } gInitializer; -#endif // XP_MAC +//////////////////////////////////////////////////////////////////////////////// -// forward declarations... -class TestConnection; +#if defined(PR_LOGGING) +// +// set NSPR_LOG_MODULES=Test:5 +// +static PRLogModuleInfo *gTestLog = nsnull; +#endif +#define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) + +//////////////////////////////////////////////////////////////////////////////// static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); -static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID); -//static PRTime gElapsedTime; -static int gKeepRunning = 1; - -#define NUM_TEST_THREADS 15 -#define TRANSFER_AMOUNT 64 - -static TestConnection* gConnections[NUM_TEST_THREADS]; -static nsIThread* gThreads[NUM_TEST_THREADS]; -//static nsITimer* gPeriodicTimer; -static PRBool gVerbose = PR_TRUE; - - -void Pump_PLEvents(nsIEventQueueService * eventQService); -void Pump_PLEvents(nsIEventQueueService * eventQService) -{ - nsIEventQueue* eventQ = nsnull; - eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); - - while ( gKeepRunning ) { -#ifdef WIN32 - MSG msg; - - if (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - gKeepRunning = FALSE; - } -#elif defined(XP_OS2) - QMSG qmsg; - - if (WinGetMsg(0, &qmsg, 0, 0, 0)) - WinDispatchMsg(0, &qmsg); - else - gKeepRunning = FALSE; -#else - nsresult rv; - PLEvent *gEvent; - rv = eventQ->GetEvent(&gEvent); - rv = eventQ->HandleEvent(gEvent); -#endif /* !WIN32 */ - } - -} - -// ----- -// -// TestConnection class... -// -// ----- - -class TestConnection : public nsIRunnable, - public nsIStreamListener, - public nsIInterfaceRequestor, - public nsIProgressEventSink -{ -public: - TestConnection(const char* aHostName, PRInt32 aPort, - PRBool aAsyncFlag); - virtual ~TestConnection(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIRUNNABLE - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - - // TestConnection methods... - nsresult WriteBuffer(void); - nsresult ReadBuffer(void); - - nsresult Process(void); - - nsresult Suspend(void); - nsresult Resume(void); - - NS_IMETHOD GetInterface(const nsIID & uuid, void * *result) { - if (uuid.Equals(NS_GET_IID(nsIProgressEventSink))) { - *result = (nsIProgressEventSink*)this; - NS_ADDREF_THIS(); - return NS_OK; - } - return NS_NOINTERFACE; - } - - NS_IMETHOD OnProgress(nsIRequest *request, nsISupports *ctxt, - PRUint32 aProgress, PRUint32 aProgressMax) { - putc('+', stderr); - return NS_OK; - } - - NS_IMETHOD OnStatus(nsIRequest *request, nsISupports *ctxt, - nsresult aStatus, const PRUnichar* aStatusArg) { - putc('?', stderr); - return NS_OK; - } - -protected: - nsIOutputStream* mOut; - nsIInputStream* mStream; - - nsIInputStream* mInStream; - nsIOutputStream* mOutStream; - - nsITransport* mTransport; - nsCOMPtr mReadRequest; - nsCOMPtr mWriteRequest; - - PRBool mIsAsync; - PRInt32 mBufferLength; - char mBufferChar; - - PRInt32 mBytesRead; - -}; +PRBool gDone = PR_FALSE; +nsIEventQueue* gEventQ = nsnull; //////////////////////////////////////////////////////////////////////////////// -class TestConnectionOpenObserver : public nsIRequestObserver +static void *PR_CALLBACK +DoneEvent_Handler(PLEvent *ev) { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - - TestConnectionOpenObserver(TestConnection* test) - : mTestConnection(test) { - } - virtual ~TestConnectionOpenObserver() {} - -protected: - TestConnection* mTestConnection; - -}; - -NS_IMPL_ISUPPORTS1(TestConnectionOpenObserver, nsIRequestObserver); - -NS_IMETHODIMP -TestConnectionOpenObserver::OnStartRequest(nsIRequest *request, nsISupports* context) -{ - if (gVerbose) - printf("\n+++ TestConnectionOpenObserver::OnStartRequest +++. Context = %p\n", (void*)context); - - return NS_OK; + gDone = PR_TRUE; + return nsnull; } -NS_IMETHODIMP -TestConnectionOpenObserver::OnStopRequest(nsIRequest *request, nsISupports* context, - nsresult aStatus) +static void PR_CALLBACK +DoneEvent_Cleanup(PLEvent *ev) { - if (gVerbose || NS_FAILED(aStatus)) - printf("\n+++ TestConnectionOpenObserver::OnStopRequest (status = %x) +++." - "\tContext = %p\n", - aStatus, (void*)context); - return NS_OK; + delete ev; +} + +static void +PostDoneEvent() +{ + LOG(("PostDoneEvent\n")); + + PLEvent *ev = new PLEvent(); + + PL_InitEvent(ev, nsnull, + DoneEvent_Handler, + DoneEvent_Cleanup); + + gEventQ->PostEvent(ev); } //////////////////////////////////////////////////////////////////////////////// -NS_IMETHODIMP -TestConnection::OnStartRequest(nsIRequest *request, nsISupports* context) +class MyHandler : public nsIOutputStreamNotify + , public nsIInputStreamNotify { - if (gVerbose) - printf("\n+++ TestConnection::OnStartRequest +++. Context = %p\n", (void*)context); - return NS_OK; -} +public: + NS_DECL_ISUPPORTS - -NS_IMETHODIMP -TestConnection::OnDataAvailable(nsIRequest *request, nsISupports* context, - nsIInputStream *aIStream, - PRUint32 aSourceOffset, - PRUint32 aLength) -{ - nsresult rv; - - char buf[TRANSFER_AMOUNT]; - PRUint32 amt; - - if (gVerbose) - printf("\n+++ TestConnection::OnDavaAvailable +++." - "\tContext = %p length = %d\n", - (void*)context, aLength); - - while (aLength > 0) { - PRInt32 cnt = PR_MIN(TRANSFER_AMOUNT, aLength); - rv = aIStream->Read(buf, cnt, &amt); - NS_ASSERTION(NS_SUCCEEDED(rv), "Read failed"); - mBytesRead += amt; - aLength -= amt; - buf[amt] = '\0'; - if (gVerbose) - puts(buf); - } - - if (mBufferLength == mBytesRead) { - mBytesRead = 0; - WriteBuffer(); - } - - return NS_OK; -} - - -NS_IMETHODIMP -TestConnection::OnStopRequest(nsIRequest *request, nsISupports* context, - nsresult aStatus) -{ - if (gVerbose || NS_FAILED(aStatus)) - printf("\n+++ TestConnection::OnStopRequest (status = %x) +++." - "\tContext = %p\n", - aStatus, (void*)context); - return NS_OK; -} - - -TestConnection::TestConnection(const char* aHostName, PRInt32 aPort, - PRBool aAsyncFlag) -{ - nsresult rv; - - mIsAsync = aAsyncFlag; - - mBufferLength = TRANSFER_AMOUNT; - mBufferChar = 'a'; - mBytesRead = 0; - - mTransport = nsnull; - mOut = nsnull; - mStream = nsnull; - - mInStream = nsnull; - mOutStream = nsnull; - - // Create a socket transport... - nsCOMPtr sts = - do_GetService(kSocketTransportServiceCID, &rv); - if (NS_SUCCEEDED(rv)) { - rv = sts->CreateTransport(aHostName, aPort, nsnull, 0, 0, &mTransport); - if (NS_SUCCEEDED(rv)) { - // Set up the notification callbacks to provide a progress event sink. - // That way we exercise the progress notification proxy code. - mTransport->SetNotificationCallbacks((nsIInterfaceRequestor*)this, PR_FALSE); - } - } - - - if (NS_SUCCEEDED(rv)) { - if (mIsAsync) { - // Create a stream for the data being written to the server... - if (NS_SUCCEEDED(rv)) { - rv = NS_NewPipe(&mStream, &mOut, 1024, 4096); - } - } - // Synchronous transport... - else { - rv = mTransport->OpenInputStream(0, -1, 0, &mInStream); - rv = mTransport->OpenOutputStream(0, -1, 0, &mOutStream); - } - } -} - - -TestConnection::~TestConnection() -{ - NS_IF_RELEASE(mTransport); - // Async resources... - NS_IF_RELEASE(mStream); - NS_IF_RELEASE(mOut); - - // Sync resources... - NS_IF_RELEASE(mInStream); - NS_IF_RELEASE(mOutStream); -} - -NS_IMPL_THREADSAFE_ISUPPORTS5(TestConnection, - nsIRunnable, - nsIStreamListener, - nsIRequestObserver, - nsIInterfaceRequestor, - nsIProgressEventSink); - -NS_IMETHODIMP -TestConnection::Run(void) -{ - nsresult rv = NS_OK; - - // Create the Event Queue for this thread... - nsCOMPtr eventQService = - do_GetService(kEventQueueServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = eventQService->CreateMonitoredThreadEventQueue(); - if (NS_FAILED(rv)) return rv; - - // - // Make sure that all resources were allocated in the constructor... - // - if (!mTransport) { - rv = NS_ERROR_FAILURE; - } - - if (NS_SUCCEEDED(rv)) { - if (mIsAsync) { - - // - // Initiate an async read... - // - rv = mTransport->AsyncRead(this, mTransport, 0, -1, 0, getter_AddRefs(mReadRequest)); - - if (NS_FAILED(rv)) { - printf("Error: AsyncRead failed..."); - } else { - rv = WriteBuffer(); - } - Pump_PLEvents(eventQService); - } - else { - while (NS_SUCCEEDED(rv)) { - rv = WriteBuffer(); - - if (NS_SUCCEEDED(rv)) { - rv = ReadBuffer(); + MyHandler(const char *path, + nsIAsyncInputStream *in, + nsIAsyncOutputStream *out) + : mInput(in) + , mOutput(out) + , mWriteOffset(0) + { + mBuf = NS_LITERAL_CSTRING("GET ") + + nsDependentCString(path) + + NS_LITERAL_CSTRING(" HTTP/1.0\r\n\r\n"); } - } + virtual ~MyHandler() {} + + // called on any thread + NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *out) + { + LOG(("OnOutputStreamReady\n")); + + nsresult rv; + PRUint32 n, count = mBuf.Length() - mWriteOffset; + + rv = out->Write(mBuf.get() + mWriteOffset, count, &n); + + LOG((" write returned [rv=%x count=%u]\n", rv, n)); + + if (NS_FAILED(rv) || (n == 0)) { + if (rv != NS_BASE_STREAM_WOULD_BLOCK) { + LOG((" done writing; starting to read\n")); + mInput->AsyncWait(this, 0, nsnull); + return NS_OK; + } + } + + mWriteOffset += n; + + return out->AsyncWait(this, 0, nsnull); } - } - if (gVerbose) - printf("Transport thread exiting...\n"); - return rv; -} + // called on any thread + NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *in) + { + LOG(("OnInputStreamReady\n")); + nsresult rv; + PRUint32 n; + char buf[500]; -nsresult TestConnection::WriteBuffer(void) -{ - nsresult rv = NS_ERROR_FAILURE; - char *buffer; - PRInt32 size; - PRUint32 bytesWritten; + rv = in->Read(buf, sizeof(buf), &n); - if (mBufferChar == 'z') { - mBufferChar = 'a'; - } else { - mBufferChar++; - } + LOG((" read returned [rv=%x count=%u]\n", rv, n)); - if (gVerbose) - printf("\n+++ Request is: %c. Context = %p\n", mBufferChar, (void*)mTransport); + if (NS_FAILED(rv) || (n == 0)) { + if (rv != NS_BASE_STREAM_WOULD_BLOCK) { + PostDoneEvent(); + return NS_OK; + } + } - // Create and fill a test buffer of data... - buffer = (char*)PR_Malloc(mBufferLength + 4); - - if (buffer) { - for (size=0; sizeAsyncWait(this, 0, nsnull); } - buffer[size++] = '\r'; - buffer[size++] = '\n'; - buffer[size] = 0; - // - // Async case... - // - if (mStream) { - rv = mOut->Write(buffer, size, &bytesWritten); +private: + nsCOMPtr mInput; + nsCOMPtr mOutput; + nsCString mBuf; + PRUint32 mWriteOffset; +}; - // Write the buffer to the server... - if (NS_SUCCEEDED(rv)) { - rv = NS_AsyncWriteFromStream( - getter_AddRefs(mWriteRequest), - mTransport, mStream, 0, bytesWritten, 0, - nsnull, mTransport); - } - // Wait for the write to complete... - if (NS_FAILED(rv)) { - printf("Error: AsyncWrite failed..."); - } - } - // - // Synchronous case... - // - else if (mOutStream) { - rv = mOutStream->Write(buffer, size, &bytesWritten); - NS_ASSERTION((PRUint32)size == bytesWritten, "Not enough was written..."); +NS_IMPL_THREADSAFE_ISUPPORTS2(MyHandler, + nsIOutputStreamNotify, + nsIInputStreamNotify) + +//////////////////////////////////////////////////////////////////////////////// + +/** + * create transport, open streams, and close + */ +static nsresult +RunCloseTest(nsISocketTransportService *sts, + const char *host, int port, + PRUint32 inFlags, PRUint32 outFlags) +{ + nsresult rv; + + LOG(("RunCloseTest\n")); + + nsCOMPtr transport; + rv = sts->CreateTransport(nsnull, 0, + nsDependentCString(host), port, nsnull, + getter_AddRefs(transport)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr in; + rv = transport->OpenInputStream(inFlags, 0, 0, getter_AddRefs(in)); + nsCOMPtr asyncIn = do_QueryInterface(in, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr out; + rv = transport->OpenOutputStream(outFlags, 0, 0, getter_AddRefs(out)); + nsCOMPtr asyncOut = do_QueryInterface(out, &rv); + if (NS_FAILED(rv)) return rv; + + LOG(("waiting 1 second before closing transport and streams...\n")); + PR_Sleep(PR_SecondsToInterval(1)); + + // let nsCOMPtr destructors close everything... + return NS_OK; +} + + +/** + * asynchronously read socket stream + */ +static nsresult +RunTest(nsISocketTransportService *sts, + const char *host, int port, const char *path, + PRUint32 inFlags, PRUint32 outFlags) +{ + nsresult rv; + + LOG(("RunTest\n")); + + nsCOMPtr transport; + rv = sts->CreateTransport(nsnull, 0, + nsDependentCString(host), port, nsnull, + getter_AddRefs(transport)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr in; + rv = transport->OpenInputStream(inFlags, 0, 0, getter_AddRefs(in)); + nsCOMPtr asyncIn = do_QueryInterface(in, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr out; + rv = transport->OpenOutputStream(outFlags, 0, 0, getter_AddRefs(out)); + nsCOMPtr asyncOut = do_QueryInterface(out, &rv); + if (NS_FAILED(rv)) return rv; + + MyHandler *handler = new MyHandler(path, asyncIn, asyncOut); + if (handler == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(handler); + + rv = asyncOut->AsyncWait(handler, 0, nsnull); + + if (NS_SUCCEEDED(rv)) { + PLEvent* event; + gDone = PR_FALSE; + while (!gDone) { + rv = gEventQ->WaitForEvent(&event); + if (NS_FAILED(rv)) return rv; + rv = gEventQ->HandleEvent(event); + if (NS_FAILED(rv)) return rv; + } } - PR_Free(buffer); - } else { - rv = NS_ERROR_OUT_OF_MEMORY; - } - return rv; + NS_RELEASE(handler); + + return NS_OK; } - -nsresult TestConnection::ReadBuffer(void) -{ - nsresult rv = NS_OK; - - // - // Synchronous case... - // - if (mInStream) { - char *buffer; - PRUint32 bytesRead; - - buffer = (char*)PR_Malloc(mBufferLength + 4); - - if (buffer) { - rv = mInStream->Read(buffer, mBufferLength, &bytesRead); - - if (NS_SUCCEEDED(rv) && bytesRead > 0) { - buffer[bytesRead] = '\0'; - if (gVerbose) - printf("TestConnection::ReadBuffer. Read %d bytes\n", bytesRead); - puts(buffer); - } - PR_Free(buffer); - } - } - - return rv; -} - -nsresult TestConnection::Process(void) -{ - return NS_OK; -} - - -nsresult TestConnection::Suspend(void) -{ - nsresult rv; - - if (mReadRequest) { - rv = mReadRequest->Suspend(); - } else { - rv = NS_ERROR_FAILURE; - } - - return rv; -} - -nsresult TestConnection::Resume(void) -{ - nsresult rv; - - if (mReadRequest) { - rv = mReadRequest->Resume(); - } else { - rv = NS_ERROR_FAILURE; - } - - return rv; -} - - - - - - -#if defined(USE_TIMERS) - -void TimerCallback(nsITimer* aTimer, void* aClosure) -{ - static PRBool flag = PR_FALSE; - int i; - - if (flag) { - printf("Resuming connections...\n"); - } else { - printf("Suspending connections...\n"); - } - - - for (i=0; iResume(); - } else { - connection->Suspend(); - } - } - } - flag = !flag; - - gPeriodicTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); - if (NS_SUCCEEDED(rv)) { - gPeriodicTimer->Init(TimerCallback, nsnull, 1000*5); - } -} - -#endif /* USE_TIMERS */ +//////////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { - nsresult rv; + nsresult rv; - // ----- - // - // Parse the command line args... - // - // ----- -#if 0 - if (argc < 3) { - printf("usage: %s [-sync|-silent] \n", argv[0]); - return -1; - } -#endif - PRBool bIsAsync = PR_TRUE; - const char* hostName = nsnull; - int i; - - - for (i=1; i \n"); + return -1; } - hostName = argv[i]; - } - if (!hostName) { - hostName = "chainsaw"; - } - printf("Using %s as echo server...\n", hostName); + { + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); -#ifdef XP_MAC - (void) PR_SetEnv("NSPR_LOG_MODULES=nsSocketTransport:5"); - (void) PR_SetEnv("NSPR_LOG_FILE=nspr.log"); - PR_Init_Log(); +#if defined(PR_LOGGING) + gTestLog = PR_NewLogModule("Test"); #endif - // ----- - // - // Initialize XPCom... - // - // ----- - { - nsCOMPtr servMan; - NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); - nsCOMPtr registrar = do_QueryInterface(servMan); - NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); - if (registrar) - registrar->AutoRegister(nsnull); + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_FAILED(rv)) return rv; - // Create the Event Queue for this thread... - nsCOMPtr eventQService = - do_GetService(kEventQueueServiceCID, &rv); - if (NS_FAILED(rv)) return rv; + rv = eventQService->CreateMonitoredThreadEventQueue(); + if (NS_FAILED(rv)) return rv; - // - // Create the connections and threads... - // - for (i=0; iGetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); + if (NS_FAILED(rv)) return rv; -#if defined(USE_TIMERS) - // - // Start up the timer to test Suspend/Resume APIs on the transport... - // - gPeriodicTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); - if (NS_SUCCEEDED(rv)) { - gPeriodicTimer->Init(TimerCallback, nsnull, 1000); - } -#endif /* USE_TIMERS */ + nsCOMPtr sts = + do_GetService(kSocketTransportServiceCID, &rv); + if (NS_FAILED(rv)) return rv; - // Enter the message pump to allow the URL load to proceed. - Pump_PLEvents(eventQService); + LOG(("phase 1 tests...\n")); - PRTime endTime; - endTime = PR_Now(); + LOG(("flags = { OPEN_UNBUFFERED, OPEN_UNBUFFERED }\n")); + rv = RunCloseTest(sts, argv[1], atoi(argv[2]), + nsITransport::OPEN_UNBUFFERED, + nsITransport::OPEN_UNBUFFERED); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); - // printf("Elapsed time: %d\n", (PRInt32)(endTime/1000UL - gElapsedTime/1000UL)); - } // this scopes the nsCOMPtrs - // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM - rv = NS_ShutdownXPCOM(nsnull); - NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); - return 0; + LOG(("flags = { OPEN_BUFFERED, OPEN_UNBUFFERED }\n")); + rv = RunCloseTest(sts, argv[1], atoi(argv[2]), + 0 /* nsITransport::OPEN_BUFFERED */, + nsITransport::OPEN_UNBUFFERED); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); + + LOG(("flags = { OPEN_UNBUFFERED, OPEN_BUFFERED }\n")); + rv = RunCloseTest(sts, argv[1], atoi(argv[2]), + nsITransport::OPEN_UNBUFFERED, + 0 /*nsITransport::OPEN_BUFFERED */); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); + + LOG(("flags = { OPEN_BUFFERED, OPEN_BUFFERED }\n")); + rv = RunCloseTest(sts, argv[1], atoi(argv[2]), + 0 /*nsITransport::OPEN_BUFFERED */, + 0 /*nsITransport::OPEN_BUFFERED */); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); + + LOG(("calling Shutdown on socket transport service:\n")); + sts->Shutdown(); + + LOG(("calling Init on socket transport service:\n")); + sts->Init(); + + LOG(("phase 2 tests...\n")); + + LOG(("flags = { OPEN_UNBUFFERED, OPEN_UNBUFFERED }\n")); + rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], + nsITransport::OPEN_UNBUFFERED, + nsITransport::OPEN_UNBUFFERED); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); + + LOG(("flags = { OPEN_BUFFERED, OPEN_UNBUFFERED }\n")); + rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], + 0 /* nsITransport::OPEN_BUFFERED */, + nsITransport::OPEN_UNBUFFERED); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); + + LOG(("flags = { OPEN_UNBUFFERED, OPEN_BUFFERED }\n")); + rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], + nsITransport::OPEN_UNBUFFERED, + 0 /*nsITransport::OPEN_BUFFERED */); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); + + LOG(("flags = { OPEN_BUFFERED, OPEN_BUFFERED }\n")); + rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], + 0 /*nsITransport::OPEN_BUFFERED */, + 0 /*nsITransport::OPEN_BUFFERED */); + NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); + + LOG(("waiting 1 second before calling Shutdown...\n")); + PR_Sleep(PR_SecondsToInterval(1)); + + LOG(("calling Shutdown on socket transport service:\n")); + sts->Shutdown(); + + NS_RELEASE(gEventQ); + + // give background threads a chance to finish whatever work they may + // be doing. + LOG(("waiting 1 second before exiting...\n")); + PR_Sleep(PR_SecondsToInterval(1)); + } // this scopes the nsCOMPtrs + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return NS_OK; } diff --git a/mozilla/netwerk/test/TestUpload.cpp b/mozilla/netwerk/test/TestUpload.cpp index 2dfe494da58..f66b1f5d982 100644 --- a/mozilla/netwerk/test/TestUpload.cpp +++ b/mozilla/netwerk/test/TestUpload.cpp @@ -50,6 +50,14 @@ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); +#include "prlog.h" +#if defined(PR_LOGGING) +// +// set NSPR_LOG_MODULES=Test:5 +// +static PRLogModuleInfo *gTestLog = nsnull; +#endif +#define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) static int gKeepRunning = 1; static nsIEventQueue* gEventQ = nsnull; @@ -83,6 +91,7 @@ NS_IMPL_ISUPPORTS1(InputTestConsumer, nsIStreamListener) NS_IMETHODIMP InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context) { + LOG(("InputTestConsumer::OnStartRequest\n")); return NS_OK; } @@ -115,6 +124,7 @@ NS_IMETHODIMP InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context, nsresult aStatus) { + LOG(("InputTestConsumer::OnStopRequest [status=%x]\n", aStatus)); gKeepRunning = PR_FALSE; return NS_OK; } @@ -132,6 +142,10 @@ main(int argc, char* argv[]) char* uriSpec = argv[1]; char* fileName = argv[2]; +#if defined(PR_LOGGING) + gTestLog = PR_NewLogModule("Test"); +#endif + { nsCOMPtr servMan; NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); diff --git a/mozilla/rdf/base/src/nsRDFXMLParser.cpp b/mozilla/rdf/base/src/nsRDFXMLParser.cpp index dfcc5df029f..89f1c4642b8 100644 --- a/mozilla/rdf/base/src/nsRDFXMLParser.cpp +++ b/mozilla/rdf/base/src/nsRDFXMLParser.cpp @@ -130,8 +130,7 @@ nsRDFXMLParser::ParseString(nsIRDFDataSource* aSink, nsIURI* aBaseURI, const nsA nsCOMPtr channel; rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aBaseURI, stream, NS_LITERAL_CSTRING("text/xml"), - NS_LITERAL_CSTRING(""), - aString.Length()); + NS_LITERAL_CSTRING("")); if (NS_FAILED(rv)) return rv; listener->OnStartRequest(channel, nsnull); diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp index b110da3057c..2b57a617805 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -54,8 +54,7 @@ #include "nsIRefreshURI.h" #include "nsIDocumentLoader.h" #include "nsIHelperAppLauncherDialog.h" -#include "nsITransport.h" -#include "nsIFileTransportService.h" +#include "nsNetUtil.h" #include "nsCExternalHandlerService.h" // contains contractids for the helper app service #include "nsIIOService.h" #include "nsNetCID.h" @@ -1242,20 +1241,8 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel) } #endif - NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); - nsCOMPtr fts = - do_GetService(kFileTransportServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr fileTransport; - rv = fts->CreateTransport(mTempFile, - PR_WRONLY | PR_CREATE_FILE, - 0600, - PR_TRUE, - getter_AddRefs(fileTransport)); - if (NS_FAILED(rv)) return rv; - - rv = fileTransport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(mOutStream)); + rv = NS_NewLocalFileOutputStream(getter_AddRefs(mOutStream), mTempFile, + PR_WRONLY | PR_CREATE_FILE, 0600); #ifdef XP_MAC nsXPIDLCString contentType; diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h index daf853e10d4..0636993bb81 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h @@ -39,6 +39,7 @@ #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsILocalFile.h" +#include "nsIChannel.h" #include "nsIRDFDataSource.h" #include "nsIRDFResource.h" diff --git a/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp index ac82260c108..70831c8bcc4 100644 --- a/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp @@ -34,6 +34,7 @@ #include "nsIProcess.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" +#include "nsNetCID.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsHashtable.h" diff --git a/mozilla/widget/src/mac/nsMacMessagePump.cpp b/mozilla/widget/src/mac/nsMacMessagePump.cpp index 454cc9b9cd8..b9c5c4f58a4 100644 --- a/mozilla/widget/src/mac/nsMacMessagePump.cpp +++ b/mozilla/widget/src/mac/nsMacMessagePump.cpp @@ -83,8 +83,8 @@ #include "nsPIWidgetMac.h" #include "nsPIEventSinkStandalone.h" -#include "nsISocketTransportService.h" -#include "nsIFileTransportService.h" +//#include "nsISocketTransportService.h" +//include "nsIFileTransportService.h" #if TARGET_CARBON && !XP_MACOSX #include "MenuSharing.h" @@ -314,8 +314,8 @@ void nsMacMessagePump::DoMessagePump() } } -static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); -static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); +//static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); +//static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); //#define BUSINESS_INDICATOR #define kIdleHysterysisTicks 60 diff --git a/mozilla/xpcom/build/dlldeps.cpp b/mozilla/xpcom/build/dlldeps.cpp index 02919f6430a..461afdc6c55 100644 --- a/mozilla/xpcom/build/dlldeps.cpp +++ b/mozilla/xpcom/build/dlldeps.cpp @@ -69,6 +69,7 @@ #include "nsIGenericFactory.h" #include "nsHashtableEnumerator.h" #include "nsIPipe.h" +#include "nsStreamUtils.h" #include "nsCWeakReference.h" #include "nsWeakReference.h" #include "nsISizeOfHandler.h" @@ -114,7 +115,10 @@ void XXXNeverCalled() nsSupportsArray(); NS_GetNumberOfAtoms(); nsFileURL(NULL); - NS_NewPipe(NULL, NULL, 0, 0, PR_FALSE, PR_FALSE, NULL); + NS_NewPipe2(NULL, NULL, PR_FALSE, PR_FALSE, 0, 0, NULL); + NS_NewInputStreamReadyEvent(NULL, NULL, NULL); + NS_NewOutputStreamReadyEvent(NULL, NULL, NULL); + NS_AsyncCopy(NULL, NULL, PR_TRUE, PR_TRUE, 0, 0, NULL); nsFileSpec s; nsFixedSizeAllocator a; nsRecyclingAllocator recyclingAllocator(2); diff --git a/mozilla/xpcom/io/MANIFEST b/mozilla/xpcom/io/MANIFEST index b06a8ae3b52..71110ab62c2 100644 --- a/mozilla/xpcom/io/MANIFEST +++ b/mozilla/xpcom/io/MANIFEST @@ -12,3 +12,4 @@ nsDirectoryServiceDefs.h nsDirectoryServiceUtils.h nsStringIO.h nsAppDirectoryServiceDefs.h +nsStreamUtils.h diff --git a/mozilla/xpcom/io/MANIFEST_IDL b/mozilla/xpcom/io/MANIFEST_IDL index 73ff795a4f4..9b5c516c0bd 100644 --- a/mozilla/xpcom/io/MANIFEST_IDL +++ b/mozilla/xpcom/io/MANIFEST_IDL @@ -13,8 +13,8 @@ nsILocalFile.idl nsIMultiplexInputStream.idl nsIObjectInputStream.idl nsIObjectOutputStream.idl -nsIObservableInputStream.idl -nsIObservableOutputStream.idl +nsIAsyncInputStream.idl +nsIAsyncOutputStream.idl nsIOutputStream.idl nsIPipe.idl nsIScriptableInputStream.idl diff --git a/mozilla/xpcom/io/Makefile.in b/mozilla/xpcom/io/Makefile.in index ec7ad01b8dd..de80fa2ff7e 100644 --- a/mozilla/xpcom/io/Makefile.in +++ b/mozilla/xpcom/io/Makefile.in @@ -54,7 +54,8 @@ CPPSRCS = \ nsLinebreakConverter.cpp \ nsLocalFileCommon.cpp \ nsMultiplexInputStream.cpp \ - nsPipe2.cpp \ + nsPipe3.cpp \ + nsStreamUtils.cpp \ nsScriptableInputStream.cpp \ nsSegmentedBuffer.cpp \ nsSpecialSystemDirectory.cpp \ @@ -90,10 +91,12 @@ EXPORTS = \ nsIUnicharInputStream.h \ nsLinebreakConverter.h \ nsLocalFile.h \ + nsMultiplexInputStream.h \ nsScriptableInputStream.h \ nsSpecialSystemDirectory.h \ nsStorageStream.h \ nsStringIO.h \ + nsStreamUtils.h \ $(NULL) ifeq ($(MOZ_WIDGET_TOOLKIT),os2) @@ -127,8 +130,8 @@ XPIDLSRCS = \ nsIStorageStream.idl \ nsIStreamBufferAccess.idl \ nsIStringStream.idl \ - nsIObservableInputStream.idl \ - nsIObservableOutputStream.idl \ + nsIAsyncInputStream.idl \ + nsIAsyncOutputStream.idl \ $(NULL) ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) diff --git a/mozilla/xpcom/io/nsIPipe.idl b/mozilla/xpcom/io/nsIPipe.idl index b3122016959..8fa0902b701 100644 --- a/mozilla/xpcom/io/nsIPipe.idl +++ b/mozilla/xpcom/io/nsIPipe.idl @@ -35,12 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsISupports.idl" +#include "nsIAsyncInputStream.idl" +#include "nsIAsyncOutputStream.idl" -interface nsIPipe; interface nsIMemory; -interface nsIInputStream; -interface nsIOutputStream; [scriptable, uuid(f4211abc-61b3-11d4-9877-00c04fa0cf4a)] interface nsIPipe : nsISupports @@ -48,21 +46,14 @@ interface nsIPipe : nsISupports /** * initialize this pipe */ - void initialize(in unsigned long segmentSize, - in unsigned long maxSize, - in boolean nonBlockingInput, - in boolean nonBlockingOutput, - in nsIMemory segmentAllocator); + void init(in boolean nonBlockingInput, + in boolean nonBlockingOutput, + in unsigned long segmentSize, + in unsigned long segmentCount, + in nsIMemory segmentAllocator); - /** - * supports nsIObservableInputStream and nsISearchableInputStream - */ - readonly attribute nsIInputStream inputStream; - - /** - * supports nsIObservableOutputStream - */ - readonly attribute nsIOutputStream outputStream; + readonly attribute nsIAsyncInputStream inputStream; + readonly attribute nsIAsyncOutputStream outputStream; }; [scriptable, uuid(8C39EF62-F7C9-11d4-98F5-001083010E9B)] @@ -85,15 +76,40 @@ interface nsISearchableInputStream : nsISupports }; %{C++ -#define NS_PIPE_DEFAULT_SEGMENT_SIZE 4096 -#define NS_PIPE_DEFAULT_BUFFER_SIZE (1024*1024) extern NS_COM nsresult -NS_NewPipe(nsIInputStream* *inStrResult, - nsIOutputStream* *outStrResult, - PRUint32 segmentSize = NS_PIPE_DEFAULT_SEGMENT_SIZE, - PRUint32 maxSize = NS_PIPE_DEFAULT_BUFFER_SIZE, +NS_NewPipe2(nsIAsyncInputStream **pipeIn, + nsIAsyncOutputStream **pipeOut, + PRBool nonBlockingInput = PR_FALSE, + PRBool nonBlockingOutput = PR_FALSE, + PRUint32 segmentSize = 0, + PRUint32 segmentCount = 0, + nsIMemory *segmentAlloc = nsnull); + +inline nsresult +NS_NewPipe(nsIInputStream **pipeIn, + nsIOutputStream **pipeOut, + PRUint32 segmentSize = 0, + PRUint32 maxSize = 0, PRBool nonBlockingInput = PR_FALSE, PRBool nonBlockingOutput = PR_FALSE, - nsIMemory* segmentAllocator = nsnull); + nsIMemory *segmentAlloc = nsnull) +{ + PRUint32 segmentCount; + if (segmentSize == 0) + segmentCount = 0; // use default + else + segmentCount = maxSize / segmentSize; + + nsIAsyncInputStream *in; + nsIAsyncOutputStream *out; + nsresult rv = NS_NewPipe2(&in, &out, nonBlockingInput, nonBlockingOutput, + segmentSize, segmentCount, segmentAlloc); + if (NS_FAILED(rv)) return rv; + + *pipeIn = in; + *pipeOut = out; + return NS_OK; +} + %} diff --git a/mozilla/xpcom/io/nsInputStreamTee.cpp b/mozilla/xpcom/io/nsInputStreamTee.cpp index 8171c4ab935..005198443ae 100644 --- a/mozilla/xpcom/io/nsInputStreamTee.cpp +++ b/mozilla/xpcom/io/nsInputStreamTee.cpp @@ -85,6 +85,8 @@ nsInputStreamTee::TeeSegment(const char *buf, PRUint32 count) // ok, this is not a fatal error... just drop our reference to mSink // and continue on as if nothing happened. NS_WARNING("Write failed (non-fatal)"); + // catch possible misuse of the input stream tee + NS_ASSERTION(rv != NS_BASE_STREAM_WOULD_BLOCK, "sink must be a blocking stream"); mSink = 0; break; } @@ -181,16 +183,6 @@ nsInputStreamTee::GetSource(nsIInputStream **source) NS_IMETHODIMP nsInputStreamTee::SetSink(nsIOutputStream *sink) { - if (sink) { - PRBool nonBlocking = PR_FALSE; - nsresult rv = sink->IsNonBlocking(&nonBlocking); - if (NS_FAILED(rv)) - return rv; - if (nonBlocking) { - NS_NOTREACHED("Can only tee data to a blocking output stream"); - return NS_ERROR_NOT_IMPLEMENTED; - } - } mSink = sink; return NS_OK; } diff --git a/mozilla/xpcom/io/nsSegmentedBuffer.h b/mozilla/xpcom/io/nsSegmentedBuffer.h index 1e3f7679773..299214b0f60 100644 --- a/mozilla/xpcom/io/nsSegmentedBuffer.h +++ b/mozilla/xpcom/io/nsSegmentedBuffer.h @@ -72,7 +72,7 @@ public: } PRUint32 GetSegmentSize() { return mSegmentSize; } - + PRUint32 GetMaxSize() { return mMaxSize; } PRUint32 GetSize() { return GetSegmentCount() * mSegmentSize; } char* GetSegment(PRUint32 indx) { diff --git a/mozilla/xpcom/io/nsStorageStream.cpp b/mozilla/xpcom/io/nsStorageStream.cpp index 546c586e091..ac9349bb1c6 100644 --- a/mozilla/xpcom/io/nsStorageStream.cpp +++ b/mozilla/xpcom/io/nsStorageStream.cpp @@ -492,6 +492,9 @@ nsStorageInputStream::Seek(PRInt32 aWhence, PRInt32 aOffset) return NS_ERROR_UNEXPECTED; } + if (pos == mLogicalCursor) + return NS_OK; + return Seek(pos); } diff --git a/mozilla/xpcom/io/nsStorageStream.h b/mozilla/xpcom/io/nsStorageStream.h index 0eb6b1386b6..16473b65338 100644 --- a/mozilla/xpcom/io/nsStorageStream.h +++ b/mozilla/xpcom/io/nsStorageStream.h @@ -37,7 +37,7 @@ class nsSegmentedBuffer; class nsStorageStream : public nsIStorageStream, - public nsIOutputStream + public nsIOutputStream { public: nsStorageStream(); diff --git a/mozilla/xpcom/io/nsStringStream.cpp b/mozilla/xpcom/io/nsStringStream.cpp index bdc4d37c048..914093f9a1f 100644 --- a/mozilla/xpcom/io/nsStringStream.cpp +++ b/mozilla/xpcom/io/nsStringStream.cpp @@ -318,7 +318,8 @@ class ConstCharImpl 0, aCount, result); if (NS_SUCCEEDED(rv)) mOffset += *result; - return rv; + // errors returned from the writer end here! + return NS_OK; } protected: diff --git a/mozilla/xpcom/macbuild/XPCOMIDL.xml b/mozilla/xpcom/macbuild/XPCOMIDL.xml index 789b8d09971..47185a87ab5 100644 --- a/mozilla/xpcom/macbuild/XPCOMIDL.xml +++ b/mozilla/xpcom/macbuild/XPCOMIDL.xml @@ -852,14 +852,14 @@ Name - nsIObservableInputStream.idl + nsIAsyncInputStream.idl MacOS Text Name - nsIObservableOutputStream.idl + nsIAsyncOutputStream.idl MacOS Text @@ -1401,12 +1401,12 @@ Name - nsIObservableInputStream.idl + nsIAsyncInputStream.idl MacOS Name - nsIObservableOutputStream.idl + nsIAsyncOutputStream.idl MacOS @@ -2555,14 +2555,14 @@ Name - nsIObservableInputStream.idl + nsIAsyncInputStream.idl MacOS Text Name - nsIObservableOutputStream.idl + nsIAsyncOutputStream.idl MacOS Text @@ -3104,12 +3104,12 @@ Name - nsIObservableInputStream.idl + nsIAsyncInputStream.idl MacOS Name - nsIObservableOutputStream.idl + nsIAsyncOutputStream.idl MacOS @@ -3668,13 +3668,13 @@ headers Name - nsIObservableInputStream.idl + nsIAsyncInputStream.idl MacOS headers Name - nsIObservableOutputStream.idl + nsIAsyncOutputStream.idl MacOS diff --git a/mozilla/xpcom/macbuild/xpcomPPC.xml b/mozilla/xpcom/macbuild/xpcomPPC.xml index 1502a9d2b4b..adb3a1c089d 100644 --- a/mozilla/xpcom/macbuild/xpcomPPC.xml +++ b/mozilla/xpcom/macbuild/xpcomPPC.xml @@ -1487,7 +1487,14 @@ Name - nsPipe2.cpp + nsPipe3.cpp + MacOS + Text + Debug + + + Name + nsStreamUtils.cpp MacOS Text Debug @@ -2258,7 +2265,12 @@ Name - nsPipe2.cpp + nsPipe3.cpp + MacOS + + + Name + nsStreamUtils.cpp MacOS @@ -3999,7 +4011,14 @@ Name - nsPipe2.cpp + nsPipe3.cpp + MacOS + Text + Debug + + + Name + nsStreamUtils.cpp MacOS Text Debug @@ -4775,7 +4794,12 @@ Name - nsPipe2.cpp + nsPipe3.cpp + MacOS + + + Name + nsStreamUtils.cpp MacOS @@ -5547,7 +5571,13 @@ xpcom.shlb Name - nsPipe2.cpp + nsPipe3.cpp + MacOS + + + xpcom.shlb + Name + nsStreamUtils.cpp MacOS diff --git a/mozilla/xpcom/tests/TestPipes.cpp b/mozilla/xpcom/tests/TestPipes.cpp index 6522927607c..aaef34ca731 100644 --- a/mozilla/xpcom/tests/TestPipes.cpp +++ b/mozilla/xpcom/tests/TestPipes.cpp @@ -40,8 +40,6 @@ #include "nsIRunnable.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" -#include "nsIObservableInputStream.h" -#include "nsIObservableOutputStream.h" #include "nsIServiceManager.h" #include "prprf.h" #include "prinrval.h" @@ -59,6 +57,22 @@ char kTestPattern[] = "My hovercraft is full of eels.\n"; PRBool gTrace = PR_FALSE; +static nsresult +WriteAll(nsIOutputStream *os, const char *buf, PRUint32 bufLen, PRUint32 *lenWritten) +{ + const char *p = buf; + *lenWritten = 0; + while (bufLen) { + PRUint32 n; + nsresult rv = os->Write(p, bufLen, &n); + if (NS_FAILED(rv)) return rv; + p += n; + bufLen -= n; + *lenWritten += n; + } + return NS_OK; +} + class nsReceiver : public nsIRunnable { public: NS_DECL_ISUPPORTS @@ -126,8 +140,9 @@ TestPipe(nsIInputStream* in, nsIOutputStream* out) PRIntervalTime start = PR_IntervalNow(); for (PRUint32 i = 0; i < ITERATIONS; i++) { PRUint32 writeCount; - char* buf = PR_smprintf("%d %s", i, kTestPattern); - rv = out->Write(buf, strlen(buf), &writeCount); + char *buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + rv = WriteAll(out, buf, len, &writeCount); if (gTrace) { printf("wrote: "); for (PRUint32 j = 0; j < writeCount; j++) { @@ -203,9 +218,9 @@ public: } PRUint32 WaitForReceipt() { - PRUint32 result = mReceived; nsAutoCMonitor mon(this); - if (mReceived == 0) { + PRUint32 result = mReceived; + while (result == 0) { mon.Wait(); NS_ASSERTION(mReceived >= 0, "failed to receive"); result = mReceived; @@ -240,7 +255,7 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out) PRUint32 len = strlen(buf); len = len * rand() / RAND_MAX; len = PR_MAX(1, len); - rv = out->Write(buf, len, &writeCount); + rv = WriteAll(out, buf, len, &writeCount); if (NS_FAILED(rv)) return rv; NS_ASSERTION(writeCount == len, "didn't write enough"); total += writeCount; @@ -268,6 +283,8 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out) //////////////////////////////////////////////////////////////////////////////// +#if 0 + class nsPipeObserver : public nsIInputStreamObserver, public nsIOutputStreamObserver { @@ -380,48 +397,23 @@ TestPipeObserver() NS_RELEASE(out); return NS_OK; } +#endif //////////////////////////////////////////////////////////////////////////////// -class nsPump : public nsIInputStreamObserver, - public nsIOutputStreamObserver, +class nsPump : /*public nsIInputStreamObserver, + public nsIOutputStreamObserver,*/ public nsIRunnable { public: NS_DECL_ISUPPORTS - NS_IMETHOD OnFull(nsIOutputStream *outStr) { - printf("OnFull outStr=%p\n", outStr); - nsAutoCMonitor mon(this); - mon.Notify(); - return NS_OK; - } - - NS_IMETHOD OnWrite(nsIOutputStream *outStr, PRUint32 amount) { - printf("OnWrite outStr=%p amount=%d\n", outStr, amount); - return NS_OK; - } - - NS_IMETHOD OnEmpty(nsIInputStream *inStr) { - printf("OnEmpty inStr=%p\n", inStr); - nsAutoCMonitor mon(this); - mon.Notify(); - return NS_OK; - } - - NS_IMETHOD OnClose(nsIInputStream *inStr) { - printf("OnClose inStr=%p\n", inStr); - nsAutoCMonitor mon(this); - mon.Notify(); - return NS_OK; - } - NS_IMETHOD Run() { nsresult rv; PRUint32 count; while (PR_TRUE) { nsAutoCMonitor mon(this); - rv = mOut->WriteFrom(mIn, -1, &count); + rv = mOut->WriteFrom(mIn, ~0U, &count); if (NS_FAILED(rv)) { printf("Write failed\n"); break; @@ -454,8 +446,8 @@ protected: PRUint32 mCount; }; -NS_IMPL_THREADSAFE_ISUPPORTS3(nsPump, nsIInputStreamObserver, - nsIOutputStreamObserver, nsIRunnable) +NS_IMPL_THREADSAFE_ISUPPORTS1(nsPump, + nsIRunnable) nsresult TestChainedPipes() @@ -496,7 +488,8 @@ TestChainedPipes() PRUint32 len = strlen(buf); len = len * rand() / RAND_MAX; len = PR_MAX(1, len); - rv = out1->Write(buf, len, &writeCount); + rv = WriteAll(out1, buf, len, &writeCount); + //rv = out1->Write(buf, len, &writeCount); if (NS_FAILED(rv)) return rv; NS_ASSERTION(writeCount == len, "didn't write enough"); total += writeCount; @@ -645,8 +638,8 @@ main(int argc, char* argv[]) TestSearch("baz", 2); #endif - rv = TestPipeObserver(); - NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipeObserver failed"); + //rv = TestPipeObserver(); + //NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipeObserver failed"); rv = TestChainedPipes(); NS_ASSERTION(NS_SUCCEEDED(rv), "TestChainedPipes failed"); RunTests(16, 1); diff --git a/mozilla/xpcom/threads/MANIFEST b/mozilla/xpcom/threads/MANIFEST index 5a213b1b856..25da4a2a5f5 100644 --- a/mozilla/xpcom/threads/MANIFEST +++ b/mozilla/xpcom/threads/MANIFEST @@ -1,4 +1,4 @@ nsAutoLock.h plevent.h nsProcess.h - +nsEventQueueUtils.h diff --git a/mozilla/xpcom/threads/Makefile.in b/mozilla/xpcom/threads/Makefile.in index bbfd784b4f3..0fc43ba6bcd 100644 --- a/mozilla/xpcom/threads/Makefile.in +++ b/mozilla/xpcom/threads/Makefile.in @@ -56,6 +56,7 @@ EXPORTS = \ nsAutoLock.h \ plevent.h \ nsProcess.h \ + nsEventQueueUtils.h \ $(NULL) XPIDLSRCS = \ diff --git a/mozilla/xpfe/browser/src/nsBrowserStatusFilter.cpp b/mozilla/xpfe/browser/src/nsBrowserStatusFilter.cpp index c31756e3963..4629e170008 100644 --- a/mozilla/xpfe/browser/src/nsBrowserStatusFilter.cpp +++ b/mozilla/xpfe/browser/src/nsBrowserStatusFilter.cpp @@ -36,7 +36,6 @@ * ***** END LICENSE BLOCK ***** */ #include "nsBrowserStatusFilter.h" -#include "nsIFileTransportService.h" #include "nsIChannel.h" #include "nsITimer.h" #include "nsIServiceManager.h" @@ -123,10 +122,6 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress *aWebProgress, if (!mListener) return NS_OK; - // ignore local/resource/chrome files - if (aStatus == NS_NET_STATUS_READ_FROM || aStatus == NS_NET_STATUS_WROTE_TO) - return NS_OK; - if (aStateFlags & STATE_START) { if (aStateFlags & STATE_IS_NETWORK) { mTotalRequests = 0; @@ -241,10 +236,6 @@ nsBrowserStatusFilter::OnStatusChange(nsIWebProgress *aWebProgress, if (!mListener) return NS_OK; - // ignore local/resource/chrome files - if (aStatus == NS_NET_STATUS_READ_FROM || aStatus == NS_NET_STATUS_WROTE_TO) - return NS_OK; - // // limit frequency of calls to OnStatusChange // diff --git a/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp b/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp index ca7b396e50a..3f34ed42cd3 100644 --- a/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp +++ b/mozilla/xpfe/components/winhooks/nsWindowsHooks.cpp @@ -54,8 +54,7 @@ #include "nsXPIDLString.h" #include "nsString.h" #include "nsMemory.h" -#include "nsNetCID.h" -#include "nsIFileStreams.h" +#include "nsNetUtil.h" // The order of these headers is important on Win2K because CreateDirectory // is |#undef|-ed in nsFileSpec.h, so we need to pull in windows.h for the // first time after nsFileSpec.h. diff --git a/mozilla/xpinstall/src/nsXPInstallManager.cpp b/mozilla/xpinstall/src/nsXPInstallManager.cpp index a472e7416d8..5df38b3dccd 100644 --- a/mozilla/xpinstall/src/nsXPInstallManager.cpp +++ b/mozilla/xpinstall/src/nsXPInstallManager.cpp @@ -35,7 +35,6 @@ #include "nsIFileURL.h" #include "nsITransport.h" -#include "nsIFileTransportService.h" #include "nsIOutputStream.h" #include "nsNetUtil.h" #include "nsIInputStream.h" @@ -795,26 +794,10 @@ nsXPInstallManager::OnStartRequest(nsIRequest* request, nsISupports *ctxt) { NS_ASSERTION( !mItem->mOutStream, "Received double OnStartRequest from Necko"); - NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID); - nsCOMPtr fts = - do_GetService( kFileTransportServiceCID, &rv ); - - if (NS_SUCCEEDED(rv) && !mItem->mOutStream) - { - nsCOMPtr outTransport; - - rv = fts->CreateTransport(mItem->mFile, - PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, - 0664, - PR_TRUE, - getter_AddRefs( outTransport)); - - if (NS_SUCCEEDED(rv)) - { - // Open output stream. - rv = outTransport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs( mItem->mOutStream ) ); - } - } + rv = NS_NewLocalFileOutputStream(getter_AddRefs(mItem->mOutStream), + mItem->mFile, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0664); } return rv; }