diff --git a/mozilla/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/mozilla/netwerk/streamconv/converters/nsMultiMixedConv.cpp index d0293d3fe36..a20072cd128 100644 --- a/mozilla/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/mozilla/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -573,6 +573,14 @@ nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context, } else { mNewPart = PR_TRUE; + // Reset state so we don't carry it over from part to part + mContentType.Truncate(); + mContentLength = -1; + mContentDisposition.Truncate(); + mIsByteRangeRequest = PR_FALSE; + mByteRangeStart = 0; + mByteRangeEnd = 0; + rv = SendStop(NS_OK); if (NS_FAILED(rv)) ERR_OUT // reset the token to front. this allows us to treat @@ -873,7 +881,7 @@ nsMultiMixedConv::ParseHeaders(nsIChannel *aChannel, char *&aPtr, PRUint32 &aLen, PRBool *_retval) { // NOTE: this data must be ascii. // NOTE: aPtr is NOT null terminated! - nsresult rv = NS_OK; + nsresult rv = NS_OK; char *cursor = aPtr, *newLine = nsnull; PRUint32 cursorLen = aLen; PRBool done = PR_FALSE; diff --git a/mozilla/uriloader/base/nsURILoader.cpp b/mozilla/uriloader/base/nsURILoader.cpp index e76605fb836..4a32960dd79 100644 --- a/mozilla/uriloader/base/nsURILoader.cpp +++ b/mozilla/uriloader/base/nsURILoader.cpp @@ -54,6 +54,7 @@ #include "nsIStreamConverterService.h" #include "nsWeakReference.h" #include "nsIHttpChannel.h" +#include "nsIMultiPartChannel.h" #include "netCore.h" #include "nsCRT.h" @@ -284,29 +285,83 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports * nsCOMPtr contentListener; nsXPIDLCString desiredContentType; - // - // First step: See if any nsIURIContentListener prefers to handle this - // content type. - // - PRBool abortDispatch = PR_FALSE; - rv = uriLoader->DispatchContent(contentType.get(), - mIsContentPreferred, - request, aCtxt, - m_contentListener, - m_originalContext, - getter_Copies(desiredContentType), - getter_AddRefs(contentListener), - &abortDispatch); + // Check whether the data should be forced to be handled + // externally. This could happen because the Content-Disposition + // header is set so, or, in the future, because the user has + // specified external handling for the MIME type. + PRBool forceExternalHandling = PR_FALSE; + nsCAutoString disposition; + nsCOMPtr httpChannel(do_QueryInterface(request)); + if (httpChannel) + { + rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"), + disposition); + } + else + { + nsCOMPtr multipartChannel(do_QueryInterface(request)); + if (multipartChannel) + { + rv = multipartChannel->GetContentDisposition(disposition); + } + } - // if the uri loader says to abort the dispatch then someone - // else must have stepped in and taken over for us...so stop.. + if (NS_SUCCEEDED(rv) && !disposition.IsEmpty()) + { + nsCAutoString::const_iterator start, end; + disposition.BeginReading(start); + disposition.EndReading(end); + // skip leading whitespace + while (start != end && nsCRT::IsAsciiSpace(*start)) + { + ++start; + } + nsCAutoString::const_iterator iter = start; + // walk forward till we hit the next whitespace or semicolon + while (iter != end && *iter != ';' && !nsCRT::IsAsciiSpace(*iter)) + { + ++iter; + } + if (start != iter && + Substring(start, iter).Equals(NS_LITERAL_CSTRING("attachment"), + nsCaseInsensitiveCStringComparator())) + { + // We have a content-disposition of "attachment" + forceExternalHandling = PR_TRUE; + } + } + + if (!forceExternalHandling) + { + // + // First step: See if any nsIURIContentListener prefers to handle this + // content type. + // + PRBool abortDispatch = PR_FALSE; + rv = uriLoader->DispatchContent(contentType.get(), + mIsContentPreferred, + request, aCtxt, + m_contentListener, + m_originalContext, + getter_Copies(desiredContentType), + getter_AddRefs(contentListener), + &abortDispatch); + + // if the uri loader says to abort the dispatch then someone + // else must have stepped in and taken over for us...so stop.. + + if (abortDispatch) return NS_OK; + } - if (abortDispatch) return NS_OK; // // Second step: If no listener prefers this type, see if any stream // decoders exist to transform this content type into // some other. // + + // We always want to do this, since even content being forced to + // be handled externally may need decoding (eg via the unknown + // content decoder) if (!contentListener) { rv = RetargetOutput(request, contentType.get(), "*/*", nsnull); @@ -331,41 +386,46 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports * // if (contentListener) { - PRBool bAbortProcess = PR_FALSE; - nsCAutoString contentTypeToUse; - if (desiredContentType) - contentTypeToUse.Assign(desiredContentType); - else - contentTypeToUse.Assign(contentType); - - // We need to first figure out if we are retargeting the load to a content listener - // that is different from the one that originated the request....if so, set - // LOAD_RETARGETED_DOCUMENT_URI on the channel. - - if (contentListener.get() != m_contentListener.get()) + if (!forceExternalHandling) { - // we must be retargeting...so set an appropriate flag on the channel - nsLoadFlags loadFlags = 0; - aChannel->GetLoadFlags(&loadFlags); - loadFlags |= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI; - aChannel->SetLoadFlags(loadFlags); + PRBool bAbortProcess = PR_FALSE; + nsCAutoString contentTypeToUse; + if (desiredContentType) + contentTypeToUse.Assign(desiredContentType); + else + contentTypeToUse.Assign(contentType); + + // We need to first figure out if we are retargeting the load + // to a content listener that is different from the one that + // originated the request....if so, set + // LOAD_RETARGETED_DOCUMENT_URI on the channel. + + if (contentListener != m_contentListener) + { + // we must be retargeting...so set an appropriate flag on + // the channel + nsLoadFlags loadFlags = 0; + aChannel->GetLoadFlags(&loadFlags); + loadFlags |= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI; + aChannel->SetLoadFlags(loadFlags); + } + + rv = contentListener->DoContent(contentTypeToUse.get(), + mIsContentPreferred, + request, + getter_AddRefs(contentStreamListener), + &bAbortProcess); + + // Do not continue loading if nsIURIContentListener::DoContent(...) + // fails - It means that an unexpected error occurred... + // + // If bAbortProcess is TRUE then the listener is doing all the work from + // here...we are done!!! + if (NS_FAILED(rv) || bAbortProcess) { + return rv; + } } - - rv = contentListener->DoContent(contentTypeToUse.get(), - mIsContentPreferred, - request, - getter_AddRefs(contentStreamListener), - &bAbortProcess); - - // Do not continue loading if nsIURIContentListener::DoContent(...) - // fails - It means that an unexpected error occurred... - // - // If bAbortProcess is TRUE then the listener is doing all the work from - // here...we are done!!! - if (NS_FAILED(rv) || bAbortProcess) { - return rv; - } - + // try to detect if there is a helper application we an use... if (!contentStreamListener) { diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp index ad1789eae28..ab8470046f7 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -743,6 +743,7 @@ nsExternalAppHandler::nsExternalAppHandler() NS_INIT_ISUPPORTS(); mCanceled = PR_FALSE; mReceivedDispositionInfo = PR_FALSE; + mHandlingAttachment = PR_FALSE; mStopRequestIssued = PR_FALSE; mDataBuffer = (char *) nsMemory::Alloc((sizeof(char) * DATA_BUFFER_SIZE)); mProgressListenerInitialized = PR_FALSE; @@ -873,10 +874,29 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel* aChan // disposition-type < ; name=value >* < ; filename=value > < ; name=value >* if ( NS_SUCCEEDED( rv ) && !disp.IsEmpty() ) { - nsACString::const_iterator start, end; + nsCAutoString::const_iterator start, end; disp.BeginReading(start); disp.EndReading(end); - nsACString::const_iterator iter = end; + // skip leading whitespace + while (start != end && nsCRT::IsAsciiSpace(*start)) { + ++start; + } + nsCAutoString::const_iterator iter = start; + // walk forward till we hit the next whitespace or semicolon + while (iter != end && *iter != ';' && !nsCRT::IsAsciiSpace(*iter)) { + ++iter; + } + if (start != iter && + Substring(start, iter).Equals(NS_LITERAL_CSTRING("attachment"), + nsCaseInsensitiveCStringComparator())) { + mHandlingAttachment = PR_TRUE; + } + + // We may not have a disposition type listed; some servers suck. + // But they could have listed a filename anyway. + disp.BeginReading(start); + iter = end; + if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("filename="), start, iter)) @@ -901,7 +921,7 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel* aChan if (endChar == ';' && iter != start) { --iter; while (iter != start && nsCRT::IsAsciiSpace(*iter)) { - iter--; + --iter; } ++iter; } @@ -1189,7 +1209,13 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo // they want us to do with this content... PRBool alwaysAsk = PR_TRUE; - mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); + // If we're handling an attachment we want to default to saving but + // always ask just in case + if (mHandlingAttachment) { + mMimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk); + } else { + mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); + } if (alwaysAsk) { // do this first! make sure we don't try to take an action until the user tells us what they want to do diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h index 1d0a33b97a4..bcd1950867e 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h @@ -186,6 +186,8 @@ protected: PRPackedBool mReceivedDispositionInfo; PRPackedBool mStopRequestIssued; PRPackedBool mProgressListenerInitialized; + // This is set when handling something with "Content-Disposition: attachment" + PRPackedBool mHandlingAttachment; PRInt64 mTimeDownloadStarted; PRInt32 mContentLength; PRInt32 mProgress; // Number of bytes received (for sending progress notifications).