From 5b394a26a3e9518dd00bd0cfffea9dc7b22ab7c7 Mon Sep 17 00:00:00 2001 From: "rpotts%netscape.com" Date: Tue, 29 May 2001 22:10:50 +0000 Subject: [PATCH] bug #81937 (r=valeski, sr=mscott, a=selmer) multipart/x-mixed-replace content was not being retargetted correctly... --- docshell/base/nsDocShell.cpp | 3 + .../converters/nsMultiMixedConv.cpp | 375 +++++++++++++++--- .../streamconv/converters/nsMultiMixedConv.h | 13 +- uriloader/base/nsDocLoader.cpp | 6 +- 4 files changed, 343 insertions(+), 54 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 066bc031ebe0..30f8e516c391 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -3737,6 +3737,9 @@ nsDocShell::CreateContentViewer(const char *aContentType, if (currentLoadGroup) currentLoadGroup->RemoveRequest(request, nsnull, NS_OK); + // Update the notification callbacks, so that progress and + // status information are sent to the right docshell... + aOpenedChannel->SetNotificationCallbacks(this); } NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull), diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/netwerk/streamconv/converters/nsMultiMixedConv.cpp index 1cb571baaf5b..f82b059ff27f 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -30,13 +30,311 @@ #include "nsMimeTypes.h" #include "nsIByteArrayInputStream.h" + +// +// nsPartChannel is a "dummy" channel which represents an individual part of +// a multipart/mixed stream... +// +// Instances on this channel are passed out to the consumer through the +// nsIStreamListener interface. +// +class nsPartChannel : public nsIChannel, + public nsIByteRangeRequest +{ +public: + nsPartChannel(nsIChannel *aMultipartChannel); + + void InitializeByteRange(PRInt32 aStart, PRInt32 aEnd); + + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUEST + NS_DECL_NSICHANNEL + NS_DECL_NSIBYTERANGEREQUEST + +protected: + virtual ~nsPartChannel(); + +protected: + nsCOMPtr mMultipartChannel; + + nsresult mStatus; + nsLoadFlags mLoadFlags; + + nsCOMPtr mLoadGroup; + + nsCString mContentType; + PRInt32 mContentLength; + + PRBool mIsByteRangeRequest; + PRInt32 mByteRangeStart; + PRInt32 mByteRangeEnd; +}; + +nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel) : + mStatus(NS_OK), + mContentLength(-1), + mIsByteRangeRequest(PR_FALSE), + mByteRangeStart(0), + mByteRangeEnd(0) +{ + NS_INIT_ISUPPORTS(); + + mMultipartChannel = aMultipartChannel; + + // Inherit the load flags from the original channel... + mMultipartChannel->GetLoadFlags(&mLoadFlags); + + mMultipartChannel->GetLoadGroup(getter_AddRefs(mLoadGroup)); +} + +nsPartChannel::~nsPartChannel() +{ +} + +void nsPartChannel::InitializeByteRange(PRInt32 aStart, PRInt32 aEnd) +{ + mIsByteRangeRequest = PR_TRUE; + + mByteRangeStart = aStart; + mByteRangeEnd = aEnd; +} + + +// +// nsISupports implementation... +// + +NS_IMPL_ADDREF(nsPartChannel) +NS_IMPL_RELEASE(nsPartChannel) + +NS_INTERFACE_MAP_BEGIN(nsPartChannel) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel) + NS_INTERFACE_MAP_ENTRY(nsIRequest) + NS_INTERFACE_MAP_ENTRY(nsIChannel) + NS_INTERFACE_MAP_ENTRY(nsIByteRangeRequest) +NS_INTERFACE_MAP_END + +// +// nsIRequest implementation... +// + +NS_IMETHODIMP +nsPartChannel::GetName(PRUnichar * *aResult) +{ + return mMultipartChannel->GetName(aResult); +} + +NS_IMETHODIMP +nsPartChannel::IsPending(PRBool *aResult) +{ + // For now, consider the active lifetime of each part the same as + // the underlying multipart channel... This is not exactly right, + // but it is good enough :-) + return mMultipartChannel->IsPending(aResult); +} + +NS_IMETHODIMP +nsPartChannel::GetStatus(nsresult *aResult) +{ + nsresult rv = NS_OK; + + if (NS_FAILED(mStatus)) { + *aResult = mStatus; + } else { + rv = mMultipartChannel->GetStatus(aResult); + } + + return rv; +} + +NS_IMETHODIMP +nsPartChannel::Cancel(nsresult aStatus) +{ + // Cancelling an individual part must not cancel the underlying + // multipart channel... + mStatus = aStatus; + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::Suspend(void) +{ + // Suspending an individual part must not suspend the underlying + // multipart channel... + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::Resume(void) +{ + // Resuming an individual part must not resume the underlying + // multipart channel... + return NS_OK; +} + +// +// nsIChannel implementation +// + +NS_IMETHODIMP +nsPartChannel::GetOriginalURI(nsIURI * *aURI) +{ + return mMultipartChannel->GetOriginalURI(aURI); +} + +NS_IMETHODIMP +nsPartChannel::SetOriginalURI(nsIURI *aURI) +{ + return mMultipartChannel->SetOriginalURI(aURI); +} + +NS_IMETHODIMP +nsPartChannel::GetURI(nsIURI * *aURI) +{ + return mMultipartChannel->GetURI(aURI); +} + +NS_IMETHODIMP +nsPartChannel::Open(nsIInputStream **result) +{ + // This channel cannot be opened! + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsPartChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) +{ + // This channel cannot be opened! + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsPartChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) +{ + *aLoadFlags = mLoadFlags; + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::SetLoadFlags(nsLoadFlags aLoadFlags) +{ + mLoadFlags = aLoadFlags; + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) +{ + *aLoadGroup = mLoadGroup; + NS_IF_ADDREF(*aLoadGroup); + + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) +{ + mLoadGroup = aLoadGroup; + + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::GetOwner(nsISupports* *aOwner) +{ + return mMultipartChannel->GetOwner(aOwner); +} + +NS_IMETHODIMP +nsPartChannel::SetOwner(nsISupports* aOwner) +{ + return mMultipartChannel->SetOwner(aOwner); +} + +NS_IMETHODIMP +nsPartChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks) +{ + return mMultipartChannel->GetNotificationCallbacks(aCallbacks); +} + +NS_IMETHODIMP +nsPartChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) +{ + return mMultipartChannel->SetNotificationCallbacks(aCallbacks); +} + +NS_IMETHODIMP +nsPartChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) +{ + return mMultipartChannel->GetSecurityInfo(aSecurityInfo); +} + +NS_IMETHODIMP +nsPartChannel::GetContentType(char * *aContentType) +{ + *aContentType = mContentType.ToNewCString(); + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::SetContentType(const char *aContentType) +{ + mContentType.Assign(aContentType); + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::GetContentLength(PRInt32 *aContentLength) +{ + *aContentLength = mContentLength; + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::SetContentLength(PRInt32 aContentLength) +{ + mContentLength = aContentLength; + return NS_OK; +} + + +// +// nsIByteRangeRequest implementation... +// + +NS_IMETHODIMP +nsPartChannel::GetIsByteRangeRequest(PRBool *aIsByteRangeRequest) +{ + *aIsByteRangeRequest = mIsByteRangeRequest; + + return NS_OK; +} + + +NS_IMETHODIMP +nsPartChannel::GetStartRange(PRInt32 *aStartRange) +{ + *aStartRange = mByteRangeStart; + + return NS_OK; +} + +NS_IMETHODIMP +nsPartChannel::GetEndRange(PRInt32 *aEndRange) +{ + *aEndRange = mByteRangeEnd; + return NS_OK; +} + + + + + // nsISupports implementation -NS_IMPL_THREADSAFE_ISUPPORTS5(nsMultiMixedConv, +NS_IMPL_THREADSAFE_ISUPPORTS3(nsMultiMixedConv, nsIStreamConverter, - nsIStreamListener, - nsIRequestObserver, - nsIByteRangeRequest, - nsIChannel); + nsIStreamListener, + nsIRequestObserver); // nsIStreamConverter implementation @@ -321,28 +619,6 @@ nsMultiMixedConv::OnStopRequest(nsIRequest *request, nsISupports *ctxt, } -NS_IMETHODIMP -nsMultiMixedConv::GetIsByteRangeRequest(PRBool *aIsByteRangeRequest) -{ - *aIsByteRangeRequest = mIsByteRangeRequest; - return NS_OK; -} - - -NS_IMETHODIMP -nsMultiMixedConv::GetStartRange(PRInt32 *aStartRange) -{ - *aStartRange = mByteRangeStart; - return NS_OK; -} - -NS_IMETHODIMP -nsMultiMixedConv::GetEndRange(PRInt32 *aEndRange) -{ - *aEndRange = mByteRangeEnd; - return NS_OK; -} - // nsMultiMixedConv methods nsMultiMixedConv::nsMultiMixedConv() { NS_INIT_ISUPPORTS(); @@ -359,6 +635,10 @@ nsMultiMixedConv::nsMultiMixedConv() { nsMultiMixedConv::~nsMultiMixedConv() { NS_ASSERTION(!mBuffer, "all buffered data should be gone"); + if (mBuffer) { + nsMemory::Free(mBuffer); + mBuffer = nsnull; + } } nsresult @@ -377,12 +657,7 @@ nsMultiMixedConv::BufferData(char *aData, PRUint32 aLen) { nsresult nsMultiMixedConv::SendStart(nsIChannel *aChannel) { - nsresult rv = NS_OK; - - // First build up a dummy uri. - nsCOMPtr partURI; - rv = aChannel->GetURI(getter_AddRefs(partURI)); - if (NS_FAILED(rv)) return rv; + nsresult rv = NS_OK; if (mContentType.IsEmpty()) mContentType = UNKNOWN_CONTENT_TYPE; @@ -391,11 +666,22 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) { // before starting up another "part." that would be bad. NS_ASSERTION(!mPartChannel, "tisk tisk, shouldn't be overwriting a channel"); - rv = NS_NewInputStreamChannel(getter_AddRefs(mPartChannel), - partURI, - nsnull, // inStr - mContentType.get(), - mContentLength); + nsPartChannel *newChannel; + newChannel = new nsPartChannel(aChannel); + if (!newChannel) + return NS_ERROR_OUT_OF_MEMORY; + + if (mIsByteRangeRequest) { + newChannel->InitializeByteRange(mByteRangeStart, mByteRangeEnd); + } + + // Set up the new part channel... + mPartChannel = newChannel; + + rv = mPartChannel->SetContentType(mContentType); + if (NS_FAILED(rv)) return rv; + + mPartChannel->SetContentLength(mContentLength); if (NS_FAILED(rv)) return rv; nsLoadFlags loadFlags = 0; @@ -403,19 +689,18 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) { loadFlags |= nsIChannel::LOAD_REPLACE; mPartChannel->SetLoadFlags(loadFlags); - nsCOMPtr loadGroup; - (void)aChannel->GetLoadGroup(getter_AddRefs(loadGroup)); + nsCOMPtr loadGroup; + (void)mPartChannel->GetLoadGroup(getter_AddRefs(loadGroup)); + // Add the new channel to the load group (if any) if (loadGroup) { - rv = mPartChannel->SetLoadGroup(loadGroup); - if (NS_FAILED(rv)) return rv; rv = loadGroup->AddRequest(mPartChannel, nsnull); if (NS_FAILED(rv)) return rv; } // Let's start off the load. NOTE: we don't forward on the channel passed // into our OnDataAvailable() as it's the root channel for the raw stream. - return mFinalListener->OnStartRequest(this, mContext); + return mFinalListener->OnStartRequest(mPartChannel, mContext); } @@ -424,7 +709,7 @@ nsMultiMixedConv::SendStop(nsresult aStatus) { nsresult rv = NS_OK; if (mPartChannel) { - rv = mFinalListener->OnStopRequest(this, mContext, aStatus); + rv = mFinalListener->OnStopRequest(mPartChannel, mContext, aStatus); // don't check for failure here, we need to remove the channel from // the loadgroup. @@ -466,7 +751,7 @@ nsMultiMixedConv::SendData(char *aBuffer, PRUint32 aLen) { rv = inStream->Available(&len); if (NS_FAILED(rv)) return rv; - return mFinalListener->OnDataAvailable(this, mContext, inStream, 0, len); + return mFinalListener->OnDataAvailable(mPartChannel, mContext, inStream, 0, len); } PRInt32 diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.h b/netwerk/streamconv/converters/nsMultiMixedConv.h index ec5866b77c54..5df1596f02a0 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.h +++ b/netwerk/streamconv/converters/nsMultiMixedConv.h @@ -76,16 +76,12 @@ static NS_DEFINE_CID(kMultiMixedConverterCID, NS_MULTIMIXEDCONVERTER_CI // // -class nsMultiMixedConv : public nsIStreamConverter, public nsIByteRangeRequest, public nsIChannel { +class nsMultiMixedConv : public nsIStreamConverter { public: NS_DECL_ISUPPORTS NS_DECL_NSISTREAMCONVERTER NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSIBYTERANGEREQUEST - - NS_FORWARD_SAFE_NSICHANNEL(mPartChannel) - NS_FORWARD_SAFE_NSIREQUEST(mPartChannel) nsMultiMixedConv(); virtual ~nsMultiMixedConv(); @@ -102,10 +98,10 @@ protected: // member data PRBool mNewPart; // Are we processing the beginning of a part? - PRBool mProcessingHeaders; + PRBool mProcessingHeaders; nsCOMPtr mFinalListener; // this guy gets the converted data via his OnDataAvailable() - nsXPIDLCString mToken; + nsXPIDLCString mToken; PRUint32 mTokenLen; nsCOMPtrmPartChannel; // the channel for the given part we're processing. @@ -118,6 +114,9 @@ protected: PRUint32 mBufLen; PRBool mFirstOnData; // used to determine if we're in our first OnData callback. + // The following members are for tracking the byte ranges in + // multipart/mixed content which specified the 'Content-Range:' + // header... PRInt32 mByteRangeStart; PRInt32 mByteRangeEnd; PRBool mIsByteRangeRequest; diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index 8f4b24898d04..b448c45f7cef 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp @@ -431,11 +431,13 @@ nsDocLoaderImpl::OnStartRequest(nsIRequest *request, nsISupports *aCtxt) count)); } #endif /* PR_LOGGING */ - + PRBool bJustStartedLoading = PR_FALSE; + PRUint32 loadFlags = 0; request->GetLoadFlags(&loadFlags); if (!mIsLoadingDocument && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) { + bJustStartedLoading = PR_TRUE; mIsLoadingDocument = PR_TRUE; ClearInternalProgress(); // only clear our progress if we are starting a new load.... } @@ -468,7 +470,7 @@ nsDocLoaderImpl::OnStartRequest(nsIRequest *request, nsISupports *aCtxt) // Only fire the start document load notification for the first // document URI... Do not fire it again for redirections // - if (!(loadFlags & nsIChannel::LOAD_REPLACE)) { + if (bJustStartedLoading) { // Update the progress status state mProgressStateFlags = nsIWebProgressListener::STATE_START;