mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Honor content-disposition: attachment even when it's set on content we
can handle internally. Bug 98360, r=law,rpotts, sr=darin. Correct whitespace this time.
This commit is contained in:
parent
8fa7c6fc08
commit
98dea7435c
@ -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;
|
||||
|
@ -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<nsIURIContentListener> 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<nsIHttpChannel> httpChannel(do_QueryInterface(request));
|
||||
if (httpChannel)
|
||||
{
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"),
|
||||
disposition);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIMultiPartChannel> 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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
Loading…
Reference in New Issue
Block a user