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:
bzbarsky%mit.edu 2002-09-03 22:00:22 +00:00
parent 8fa7c6fc08
commit 98dea7435c
4 changed files with 150 additions and 54 deletions

View File

@ -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;

View File

@ -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)
{

View File

@ -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

View File

@ -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).