bug 589292 - add contentDisposition{Filename} props to nsIChannel. r=honzab sr=bzbarsky

This commit is contained in:
Nick Hurley 2011-09-09 15:41:04 -07:00
Родитель 926c81069f
Коммит 924d548d31
36 изменённых файлов: 704 добавлений и 282 удалений

Просмотреть файл

@ -129,51 +129,18 @@ StringBeginsWithLowercaseLiteral(nsAString& aString,
return StringHead(aString, N).LowerCaseEqualsLiteral(aSubstring);
}
// XXXsayrer put this in here to get on the branch with minimal delay.
// Trunk really needs to factor this out. This is the third usage.
PRBool
HasAttachmentDisposition(nsIHttpChannel* httpChannel)
{
if (!httpChannel)
return PR_FALSE;
nsCAutoString contentDisposition;
nsresult rv =
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"),
contentDisposition);
if (NS_SUCCEEDED(rv) && !contentDisposition.IsEmpty()) {
nsCOMPtr<nsIURI> uri;
httpChannel->GetURI(getter_AddRefs(uri));
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
nsCAutoString fallbackCharset;
if (uri)
uri->GetOriginCharset(fallbackCharset);
nsAutoString dispToken;
// Get the disposition type
rv = mimehdrpar->GetParameter(contentDisposition, "", fallbackCharset,
PR_TRUE, nsnull, dispToken);
// RFC 2183, section 2.8 says that an unknown disposition
// value should be treated as "attachment"
// XXXbz this code is duplicated in GetFilenameAndExtensionFromChannel in
// nsExternalHelperAppService. Factor it out!
if (NS_FAILED(rv) ||
(!dispToken.IsEmpty() &&
!StringBeginsWithLowercaseLiteral(dispToken, "inline") &&
// Broken sites just send
// Content-Disposition: filename="file"
// without a disposition token... screen those out.
!StringBeginsWithLowercaseLiteral(dispToken, "filename") &&
// Also in use is Content-Disposition: name="file"
!StringBeginsWithLowercaseLiteral(dispToken, "name")))
// We have a content-disposition of "attachment" or unknown
return PR_TRUE;
}
}
PRUint32 disp;
nsresult rv = httpChannel->GetContentDisposition(&disp);
if (NS_SUCCEEDED(rv) && disp == nsIChannel::DISPOSITION_ATTACHMENT)
return PR_TRUE;
return PR_FALSE;
}

Просмотреть файл

@ -6749,14 +6749,11 @@ nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
}
}
} else {
nsCOMPtr<nsIMultiPartChannel> partChannel = do_QueryInterface(aChannel);
if (partChannel) {
nsCAutoString contentDisp;
rv = partChannel->GetContentDisposition(contentDisp);
if (NS_SUCCEEDED(rv) && !contentDisp.IsEmpty()) {
SetHeaderData(nsGkAtoms::headerContentDisposition,
NS_ConvertASCIItoUTF16(contentDisp));
}
nsCAutoString contentDisp;
rv = aChannel->GetContentDispositionHeader(contentDisp);
if (NS_SUCCEEDED(rv)) {
SetHeaderData(nsGkAtoms::headerContentDisposition,
NS_ConvertASCIItoUTF16(contentDisp));
}
}
}

Просмотреть файл

@ -1027,6 +1027,24 @@ nsJSChannel::SetContentCharset(const nsACString &aContentCharset)
return mStreamChannel->SetContentCharset(aContentCharset);
}
NS_IMETHODIMP
nsJSChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return mStreamChannel->GetContentDisposition(aContentDisposition);
}
NS_IMETHODIMP
nsJSChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return mStreamChannel->GetContentDispositionFilename(aContentDispositionFilename);
}
NS_IMETHODIMP
nsJSChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return mStreamChannel->GetContentDispositionHeader(aContentDispositionHeader);
}
NS_IMETHODIMP
nsJSChannel::GetContentLength(PRInt32 *aContentLength)
{

Просмотреть файл

@ -666,6 +666,32 @@ nsJARChannel::SetContentCharset(const nsACString &aContentCharset)
return NS_OK;
}
NS_IMETHODIMP
nsJARChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
if (mContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
*aContentDisposition = mContentDisposition;
return NS_OK;
}
NS_IMETHODIMP
nsJARChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsJARChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
if (mContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
aContentDispositionHeader = mContentDispositionHeader;
return NS_OK;
}
NS_IMETHODIMP
nsJARChannel::GetContentLength(PRInt32 *result)
{
@ -806,7 +832,6 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
}
if (NS_SUCCEEDED(status) && channel) {
nsCAutoString header;
// Grab the security info from our base channel
channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
@ -815,6 +840,7 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
// We only want to run scripts if the server really intended to
// send us a JAR file. Check the server-supplied content type for
// a JAR type.
nsCAutoString header;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
header);
nsCAutoString contentType;
@ -825,10 +851,6 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
mIsUnsafe = !(contentType.Equals(channelContentType) &&
(contentType.EqualsLiteral("application/java-archive") ||
contentType.EqualsLiteral("application/x-jar")));
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Disposition"),
header);
if (NS_SUCCEEDED(rv))
SetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, header);
} else {
nsCOMPtr<nsIJARChannel> innerJARChannel(do_QueryInterface(channel));
if (innerJARChannel) {
@ -836,11 +858,10 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
innerJARChannel->GetIsUnsafe(&unsafe);
mIsUnsafe = unsafe;
}
// Soon-to-be common way to get Disposition: right now only nsIJARChannel
rv = NS_GetContentDisposition(request, header);
if (NS_SUCCEEDED(rv))
SetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, header);
}
channel->GetContentDispositionHeader(mContentDispositionHeader);
mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
}
if (NS_SUCCEEDED(status) && mIsUnsafe &&

Просмотреть файл

@ -96,6 +96,10 @@ private:
nsCOMPtr<nsISupports> mListenerContext;
nsCString mContentType;
nsCString mContentCharset;
nsCString mContentDispositionHeader;
/* mContentDisposition is uninitialized if mContentDispositionHeader is
* empty */
PRUint32 mContentDisposition;
PRInt32 mContentLength;
PRUint32 mLoadFlags;
nsresult mStatus;

Двоичные данные
modules/libjar/test/unit/data/test_bug589292.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,22 @@
// Make sure we behave appropriately when asking for content-disposition
const Cc = Components.classes;
const Ci = Components.interfaces;
const path = "data/test_bug589292.zip";
function run_test() {
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var spec = "jar:" + ios.newFileURI(do_get_file(path)).spec + "!/foo.txt";
var channel = ios.newChannel(spec, null, null);
instr = channel.open();
var val;
try {
val = channel.contentDisposition;
do_check_true(false, "The channel has content disposition?!");
} catch (e) {
// This is what we want to happen - there's no underlying channel, so no
// content-disposition header is available
do_check_true(true, "How are you reading this?!");
}
}

Просмотреть файл

@ -10,6 +10,7 @@ tail =
[test_bug407303.js]
[test_bug453254.js]
[test_bug458158.js]
[test_bug589292.js]
[test_bug597702.js]
[test_bug637286.js]
[test_bug658093.js]

Просмотреть файл

@ -398,6 +398,24 @@ nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
{
*aContentLength = mContentLength;

Просмотреть файл

@ -635,6 +635,24 @@ nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
{
*aContentLength = mContentLength;

Просмотреть файл

@ -654,6 +654,24 @@ nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsIconChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
{
*aContentLength = mContentLength;

Просмотреть файл

@ -994,11 +994,10 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
/* NS_WARNING if the content type from the channel isn't the same if the sniffing */
#endif
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
if (mContentType.IsEmpty()) {
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |sniffing of mimetype failed|");
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
rv = NS_ERROR_FAILURE;
if (chan) {
rv = chan->GetContentType(mContentType);
@ -1041,14 +1040,8 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
/* set our content disposition as a property */
nsCAutoString disposition;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"), disposition);
} else {
nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
if (multiPartChannel) {
multiPartChannel->GetContentDisposition(disposition);
}
if (chan) {
chan->GetContentDispositionHeader(disposition);
}
if (!disposition.IsEmpty()) {
nsCOMPtr<nsISupportsCString> contentDisposition(do_CreateInstance("@mozilla.org/supports-cstring;1"));
@ -1114,6 +1107,7 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
if (imageType == imgIContainer::TYPE_RASTER) {
/* Use content-length as a size hint for http channels. */
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
nsCAutoString contentLength;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),

Просмотреть файл

@ -58,12 +58,6 @@
*/
#define NS_CHANNEL_PROP_CONTENT_LENGTH_STR "content-length"
/**
* MIME Content-Disposition header of channel.
* Not available before onStartRequest.
* Type: nsACString
*/
#define NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR "content-disposition"
/**
* Exists to allow content policy mechanism to function properly during channel
@ -74,13 +68,10 @@
#ifdef IMPL_NS_NET
#define NS_CHANNEL_PROP_CONTENT_LENGTH gNetStrings->kContentLength
#define NS_CHANNEL_PROP_CONTENT_DISPOSITION gNetStrings->kContentDisposition
#define NS_CHANNEL_PROP_CHANNEL_POLICY gNetStrings->kChannelPolicy
#else
#define NS_CHANNEL_PROP_CONTENT_LENGTH \
NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_LENGTH_STR)
#define NS_CHANNEL_PROP_CONTENT_DISPOSITION \
NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR)
#define NS_CHANNEL_PROP_CHANNEL_POLICY \
NS_LITERAL_STRING(NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
#endif

Просмотреть файл

@ -56,7 +56,7 @@ interface nsIStreamListener;
*
* This interface must be used only from the XPCOM main thread.
*/
[scriptable, uuid(c63a055a-a676-4e71-bf3c-6cfa11082018)]
[scriptable, uuid(06f6ada3-7729-4e72-8d3f-bf8ba630ff9b)]
interface nsIChannel : nsIRequest
{
/**
@ -272,4 +272,39 @@ interface nsIChannel : nsIRequest
* the URI when opening the channel.
*/
const unsigned long LOAD_CLASSIFY_URI = 1 << 22;
/**
* Access to the type implied or stated by the Content-Disposition header
* if available and if applicable. This allows determining inline versus
* attachment.
*
* Implementations should throw NS_ERROR_NOT_AVAILABLE if the header either
* doesn't exist for this type of channel or is empty, and
* DISPOSITION_ATTACHMENT if an invalid/noncompliant value is present.
*/
readonly attribute unsigned long contentDisposition;
const unsigned long DISPOSITION_INLINE = 0;
const unsigned long DISPOSITION_ATTACHMENT = 1;
/**
* Access to the filename portion of the Content-Disposition header if
* available and if applicable. This allows getting the preferred filename
* without having to parse it out yourself.
*
* Implementations should throw NS_ERROR_NOT_AVAILABLE if the header doesn't
* exist for this type of channel, if the header is empty, if the header
* doesn't contain a filename portion, or the value of the filename
* attribute is empty/missing.
*/
readonly attribute AString contentDispositionFilename;
/**
* Access to the raw Content-Disposition header if available and applicable.
*
* Implementations should throw NS_ERROR_NOT_AVAILABLE if the header either
* doesn't exist for this type of channel or is empty.
*
* @deprecated Use contentDisposition/contentDispositionFilename instead.
*/
readonly attribute ACString contentDispositionHeader;
};

Просмотреть файл

@ -45,7 +45,7 @@ interface nsIChannel;
* associated with a MultiPartChannel.
*/
[scriptable, uuid(ba78db7b-b88c-4b76-baf9-3c2296a585ae)]
[scriptable, uuid(4b04e835-d131-42af-8bf0-74289f99374f)]
interface nsIMultiPartChannel : nsISupports
{
/**
@ -53,13 +53,6 @@ interface nsIMultiPartChannel : nsISupports
*/
readonly attribute nsIChannel baseChannel;
/**
* Access to the Content-Disposition header field of this part of
* a multipart message. This allows getting the preferred
* handling method, preferred filename, etc. See RFC 2183.
*/
attribute ACString contentDisposition;
/**
* Attribute guaranteed to be different for different parts of
* the same multipart document.

Просмотреть файл

@ -49,7 +49,6 @@ public:
/** "content-length" */
const nsLiteralString kContentLength;
const nsLiteralString kContentDisposition;
const nsLiteralString kChannelPolicy;
};

Просмотреть файл

@ -106,6 +106,7 @@
#include "nsIChannelPolicy.h"
#include "nsISocketProviderService.h"
#include "nsISocketProvider.h"
#include "nsIMIMEHeaderParam.h"
#include "mozilla/Services.h"
#include "nsIRedirectChannelRegistrar.h"
@ -244,19 +245,6 @@ NS_NewChannel(nsIChannel **result,
return rv;
}
// For now, works only with JARChannel. Future: with all channels that may
// have Content-Disposition header (JAR, nsIHttpChannel, and nsIMultiPartChannel).
inline nsresult
NS_GetContentDisposition(nsIRequest *channel,
nsACString &result)
{
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
if (props)
return props->GetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION,
result);
return NS_ERROR_NOT_AVAILABLE;
}
// Use this function with CAUTION. It creates a stream that blocks when you
// Read() from it and blocking the UI thread is a bad idea. If you don't want
// to implement a full blown asynchronous consumer (via nsIStreamListener) look
@ -1907,6 +1895,105 @@ NS_CheckIsJavaCompatibleURLString(nsCString& urlString, PRBool *result)
return NS_OK;
}
/** Given the first (disposition) token from a Content-Disposition header,
* tell whether it indicates the content is inline or attachment
* @param aDispToken the disposition token from the content-disposition header
*/
inline PRUint32
NS_GetContentDispositionFromToken(const nsAString& aDispToken)
{
// RFC 2183, section 2.8 says that an unknown disposition
// value should be treated as "attachment"
// If all of these tests eval to false, then we have a content-disposition of
// "attachment" or unknown
if (aDispToken.IsEmpty() ||
aDispToken.LowerCaseEqualsLiteral("inline") ||
// Broken sites just send
// Content-Disposition: filename="file"
// without a disposition token... screen those out.
StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename") ||
// Also in use is Content-Disposition: name="file"
StringHead(aDispToken, 4).LowerCaseEqualsLiteral("name"))
return nsIChannel::DISPOSITION_INLINE;
return nsIChannel::DISPOSITION_ATTACHMENT;
}
/** Determine the disposition (inline/attachment) of the content based on the
* Content-Disposition header
* @param aHeader the content-disposition header (full value)
* @param aChan the channel the header came from
*/
inline PRUint32
NS_GetContentDispositionFromHeader(const nsACString& aHeader, nsIChannel *aChan = nsnull)
{
nsresult rv;
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_FAILED(rv))
return nsIChannel::DISPOSITION_ATTACHMENT;
nsCAutoString fallbackCharset;
if (aChan) {
nsCOMPtr<nsIURI> uri;
aChan->GetURI(getter_AddRefs(uri));
if (uri)
uri->GetOriginCharset(fallbackCharset);
}
nsAutoString dispToken;
rv = mimehdrpar->GetParameter(aHeader, "", fallbackCharset, PR_TRUE, nsnull,
dispToken);
if (NS_FAILED(rv))
return nsIChannel::DISPOSITION_ATTACHMENT;
return NS_GetContentDispositionFromToken(dispToken);
}
/** Extracts the filename out of a content-disposition header
* @param aFilename [out] The filename. Can be empty on error.
* @param aDisposition Value of a Content-Disposition header
* @param aURI Optional. Will be used to get a fallback charset for the
* filename, if it is QI'able to nsIURL
*/
inline nsresult
NS_GetFilenameFromDisposition(nsAString& aFilename,
const nsACString& aDisposition,
nsIURI* aURI = nsnull)
{
aFilename.Truncate();
nsresult rv;
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
nsCAutoString fallbackCharset;
if (url)
url->GetOriginCharset(fallbackCharset);
// Get the value of 'filename' parameter
rv = mimehdrpar->GetParameter(aDisposition, "filename",
fallbackCharset, PR_TRUE, nsnull,
aFilename);
if (NS_FAILED(rv) || aFilename.IsEmpty()) {
// Try 'name' parameter, instead.
rv = mimehdrpar->GetParameter(aDisposition, "name", fallbackCharset,
PR_TRUE, nsnull, aFilename);
}
if (NS_FAILED(rv)) {
aFilename.Truncate();
return rv;
}
if (aFilename.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
return NS_OK;
}
/**
* Make sure Personal Security Manager is initialized
*/

Просмотреть файл

@ -519,6 +519,24 @@ nsBaseChannel::SetContentCharset(const nsACString &aContentCharset)
return NS_OK;
}
NS_IMETHODIMP
nsBaseChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsBaseChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsBaseChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsBaseChannel::GetContentLength(PRInt32 *aContentLength)
{

Просмотреть файл

@ -41,7 +41,6 @@ NS_HIDDEN_(nsNetStrings*) gNetStrings;
nsNetStrings::nsNetStrings()
: NS_LITERAL_STRING_INIT(kContentLength, NS_CHANNEL_PROP_CONTENT_LENGTH_STR),
NS_LITERAL_STRING_INIT(kContentDisposition, NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR),
NS_LITERAL_STRING_INIT(kChannelPolicy, NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
{}

Просмотреть файл

@ -376,6 +376,51 @@ HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
nsresult rv;
nsCString header;
rv = GetContentDispositionHeader(header);
if (NS_FAILED(rv))
return rv;
*aContentDisposition = NS_GetContentDispositionFromHeader(header, this);
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
{
aContentDispositionFilename.Truncate();
nsresult rv;
nsCString header;
rv = GetContentDispositionHeader(header);
if (NS_FAILED(rv))
return rv;
return NS_GetFilenameFromDisposition(aContentDispositionFilename,
header, mURI);
}
NS_IMETHODIMP
HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
{
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition,
aContentDispositionHeader);
if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetContentLength(PRInt32 *aContentLength)
{

Просмотреть файл

@ -116,6 +116,9 @@ public:
NS_IMETHOD SetContentType(const nsACString& aContentType);
NS_IMETHOD GetContentCharset(nsACString& aContentCharset);
NS_IMETHOD SetContentCharset(const nsACString& aContentCharset);
NS_IMETHOD GetContentDisposition(PRUint32 *aContentDisposition);
NS_IMETHOD GetContentDispositionFilename(nsAString& aContentDispositionFilename);
NS_IMETHOD GetContentDispositionHeader(nsACString& aContentDispositionHeader);
NS_IMETHOD GetContentLength(PRInt32 *aContentLength);
NS_IMETHOD SetContentLength(PRInt32 aContentLength);
NS_IMETHOD Open(nsIInputStream **aResult);

Просмотреть файл

@ -371,6 +371,30 @@ nsViewSourceChannel::SetContentCharset(const nsACString &aContentCharset)
return mChannel->SetContentCharset(aContentCharset);
}
NS_IMETHODIMP
nsViewSourceChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
return mChannel->GetContentDisposition(aContentDisposition);
}
NS_IMETHODIMP
nsViewSourceChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
return mChannel->GetContentDispositionFilename(aContentDispositionFilename);
}
NS_IMETHODIMP
nsViewSourceChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
return mChannel->GetContentDispositionHeader(aContentDispositionHeader);
}
NS_IMETHODIMP
nsViewSourceChannel::GetContentLength(PRInt32 *aContentLength)
{

Просмотреть файл

@ -535,6 +535,24 @@ WyciwygChannelChild::SetContentCharset(const nsACString & aContentCharset)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WyciwygChannelChild::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
WyciwygChannelChild::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
WyciwygChannelChild::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
/* attribute long contentLength; */
NS_IMETHODIMP
WyciwygChannelChild::GetContentLength(PRInt32 *aContentLength)

Просмотреть файл

@ -343,6 +343,24 @@ nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsWyciwygChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsWyciwygChannel::GetContentLength(PRInt32 *aContentLength)
{

Просмотреть файл

@ -120,6 +120,16 @@ nsresult nsPartChannel::SendOnStopRequest(nsISupports* aContext,
return listener->OnStopRequest(this, aContext, aStatus);
}
void nsPartChannel::SetContentDisposition(const nsACString& aContentDispositionHeader)
{
mContentDispositionHeader = aContentDispositionHeader;
nsCOMPtr<nsIURI> uri;
GetURI(getter_AddRefs(uri));
NS_GetFilenameFromDisposition(mContentDispositionFilename,
mContentDispositionHeader, uri);
mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
}
//
// nsISupports implementation...
//
@ -337,16 +347,32 @@ nsPartChannel::SetContentLength(PRInt32 aContentLength)
}
NS_IMETHODIMP
nsPartChannel::GetContentDisposition(nsACString &aContentDisposition)
nsPartChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
aContentDisposition = mContentDisposition;
if (mContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
*aContentDisposition = mContentDisposition;
return NS_OK;
}
NS_IMETHODIMP
nsPartChannel::SetContentDisposition(const nsACString &aContentDisposition)
nsPartChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
mContentDisposition = aContentDisposition;
if (mContentDispositionFilename.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
aContentDispositionFilename = mContentDispositionFilename;
return NS_OK;
}
NS_IMETHODIMP
nsPartChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
if (mContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
aContentDispositionHeader = mContentDispositionHeader;
return NS_OK;
}
@ -799,8 +825,7 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) {
rv = mPartChannel->SetContentLength(mContentLength); // XXX Truncates 64-bit!
if (NS_FAILED(rv)) return rv;
rv = mPartChannel->SetContentDisposition(mContentDisposition);
if (NS_FAILED(rv)) return rv;
mPartChannel->SetContentDisposition(mContentDisposition);
nsLoadFlags loadFlags = 0;
mPartChannel->GetLoadFlags(&loadFlags);

Просмотреть файл

@ -76,6 +76,9 @@ public:
nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream,
PRUint32 aOffset, PRUint32 aLen);
nsresult SendOnStopRequest(nsISupports* aContext, nsresult aStatus);
/* SetContentDisposition expects the full value of the Content-Disposition
* header */
void SetContentDisposition(const nsACString& aContentDispositionHeader);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUEST
@ -97,7 +100,9 @@ protected:
nsCString mContentType;
nsCString mContentCharset;
nsCString mContentDisposition;
PRUint32 mContentDisposition;
nsString mContentDispositionFilename;
nsCString mContentDispositionHeader;
PRUint64 mContentLength;
PRBool mIsByteRangeRequest;

Просмотреть файл

@ -349,12 +349,12 @@ function completeTest11(request, data, ctx)
do_check_eq(request.status, 0);
try {
// TODO when bug XXX lands, also get channel C-D properties and make sure
// they're blank
dispo = request.getResponseHeader("Content-Disposition");
do_check_eq(dispo, "attachment; filename=foo");
var chan = request.QueryInterface(Ci.nsIChannel);
do_check_eq(chan.contentDisposition, chan.DISPOSITION_ATTACHMENT);
do_check_eq(chan.contentDispositionFilename, "foo");
do_check_eq(chan.contentDispositionHeader, "attachment; filename=foo");
} catch (ex) {
do_throw("Content-Disposition should be present");
do_throw("error parsing Content-Disposition: " + ex);
}
endTests();

Просмотреть файл

@ -0,0 +1,179 @@
//
// cleaner HTTP header test infrastructure
//
// tests bugs: 589292, [add more here: see hg log for definitive list]
//
// TO ADD NEW TESTS:
// 1) Increment up 'lastTest' to new number (say, "99")
// 2) Add new test 'handler99' and 'completeTest99' functions.
// 3) If your test should fail the necko channel, set
// test_flags[99] = CL_EXPECT_FAILURE.
//
// TO DEBUG JUST ONE TEST: temporarily change firstTest and lastTest to equal
// the test # you're interested in.
//
// For tests that need duplicate copies of headers to be sent, see
// test_duplicate_headers.js
var firstTest = 1; // set to test of interest when debugging
var lastTest = 4; // set to test of interest when debugging
////////////////////////////////////////////////////////////////////////////////
// Note: sets Cc and Ci variables
do_load_httpd_js();
var httpserver = new nsHttpServer();
var index = 0;
var nextTest = firstTest;
var test_flags = new Array();
var testPathBase = "/test_headers";
function run_test()
{
httpserver.start(4444);
do_test_pending();
run_test_number(nextTest);
}
function runNextTest()
{
if (nextTest == lastTest) {
endTests();
return;
}
nextTest++;
// Make sure test functions exist
if (eval("handler" + nextTest) == undefined)
do_throw("handler" + nextTest + " undefined!");
if (eval("completeTest" + nextTest) == undefined)
do_throw("completeTest" + nextTest + " undefined!");
run_test_number(nextTest);
}
function run_test_number(num)
{
testPath = testPathBase + num;
httpserver.registerPathHandler(testPath, eval("handler" + num));
var channel = setupChannel(testPath);
flags = test_flags[num]; // OK if flags undefined for test
channel.asyncOpen(new ChannelListener(eval("completeTest" + num),
channel, flags), null);
}
function setupChannel(url)
{
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var chan = ios.newChannel("http://localhost:4444" + url, "", null);
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
return httpChan;
}
function endTests()
{
httpserver.stop(do_test_finished);
}
////////////////////////////////////////////////////////////////////////////////
// Test 1: test Content-Disposition channel attributes
function handler1(metadata, response)
{
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Disposition", "attachment; filename=foo");
response.setHeader("Content-Type", "text/plain", false);
var body = "foo";
}
function completeTest1(request, data, ctx)
{
try {
var chan = request.QueryInterface(Ci.nsIChannel);
do_check_eq(chan.contentDisposition, chan.DISPOSITION_ATTACHMENT);
do_check_eq(chan.contentDispositionFilename, "foo");
do_check_eq(chan.contentDispositionHeader, "attachment; filename=foo");
} catch (ex) {
do_throw("error parsing Content-Disposition: " + ex);
}
runNextTest();
}
////////////////////////////////////////////////////////////////////////////////
// Test 2: no filename
function handler2(metadata, response)
{
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Content-Disposition", "attachment");
var body = "foo";
response.bodyOutputStream.write(body, body.length);
}
function completeTest2(request, data, ctx)
{
try {
var chan = request.QueryInterface(Ci.nsIChannel);
do_check_eq(chan.contentDisposition, chan.DISPOSITION_ATTACHMENT);
do_check_eq(chan.contentDispositionHeader, "attachment");
filename = chan.contentDispositionFilename; // should barf
do_throw("Should have failed getting Content-Disposition filename");
} catch (ex) {
do_print("correctly ate exception");
}
runNextTest();
}
////////////////////////////////////////////////////////////////////////////////
// Test 3: filename missing
function handler3(metadata, response)
{
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Content-Disposition", "attachment; filename=");
var body = "foo";
response.bodyOutputStream.write(body, body.length);
}
function completeTest3(request, data, ctx)
{
try {
var chan = request.QueryInterface(Ci.nsIChannel);
do_check_eq(chan.contentDisposition, chan.DISPOSITION_ATTACHMENT);
do_check_eq(chan.contentDispositionHeader, "attachment; filename=");
filename = chan.contentDispositionFilename; // should barf
do_throw("Should have failed getting Content-Disposition filename");
} catch (ex) {
do_print("correctly ate exception");
}
runNextTest();
}
////////////////////////////////////////////////////////////////////////////////
// Test 4: inline
function handler4(metadata, response)
{
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Content-Disposition", "inline");
var body = "foo";
response.bodyOutputStream.write(body, body.length);
}
function completeTest4(request, data, ctx)
{
try {
var chan = request.QueryInterface(Ci.nsIChannel);
do_check_eq(chan.contentDisposition, chan.DISPOSITION_INLINE);
do_check_eq(chan.contentDispositionHeader, "inline");
filename = chan.contentDispositionFilename; // should barf
do_throw("Should have failed getting Content-Disposition filename");
} catch (ex) {
do_print("correctly ate exception");
}
runNextTest();
}

Просмотреть файл

@ -126,6 +126,7 @@ skip-if = os == "android"
[test_gre_resources.js]
[test_gzipped_206.js]
[test_head.js]
[test_headers.js]
[test_http_headers.js]
[test_httpcancel.js]
[test_httpsuspend.js]

Просмотреть файл

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
function run_test() {
run_test_in_child("../unit/test_headers.js");
}

Просмотреть файл

@ -7,6 +7,7 @@ tail =
[test_duplicate_headers_wrap.js]
[test_event_sink_wrap.js]
[test_head_wrap.js]
[test_headers_wrap.js]
[test_httpcancel_wrap.js]
[test_httpsuspend_wrap.js]
[test_post_wrap.js]

Просмотреть файл

@ -385,58 +385,10 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
// future, because the user has specified external handling for the MIME
// type.
PRBool forceExternalHandling = PR_FALSE;
nsCAutoString disposition;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
nsCOMPtr<nsIURI> uri;
if (httpChannel)
{
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"),
disposition);
httpChannel->GetURI(getter_AddRefs(uri));
}
else
{
nsCOMPtr<nsIMultiPartChannel> multipartChannel(do_QueryInterface(request));
if (multipartChannel)
{
rv = multipartChannel->GetContentDisposition(disposition);
} else {
// Soon-to-be common way to get Disposition: right now only JARChannel
rv = NS_GetContentDisposition(request, disposition);
}
}
LOG((" Disposition header: '%s'", disposition.get()));
if (NS_SUCCEEDED(rv) && !disposition.IsEmpty())
{
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
nsCAutoString fallbackCharset;
if (uri)
uri->GetOriginCharset(fallbackCharset);
nsAutoString dispToken;
// Get the disposition type
rv = mimehdrpar->GetParameter(disposition, "", fallbackCharset,
PR_TRUE, nsnull, dispToken);
// RFC 2183, section 2.8 says that an unknown disposition
// value should be treated as "attachment"
// XXXbz this code is duplicated in GetFilenameAndExtensionFromChannel in
// nsExternalHelperAppService. Factor it out!
if (NS_FAILED(rv) ||
(!dispToken.IsEmpty() &&
!dispToken.LowerCaseEqualsLiteral("inline") &&
// Broken sites just send
// Content-Disposition: filename="file"
// without a disposition token... screen those out.
!dispToken.EqualsIgnoreCase("filename", 8) &&
// Also in use is Content-Disposition: name="file"
!dispToken.EqualsIgnoreCase("name", 4)))
// We have a content-disposition of "attachment" or unknown
forceExternalHandling = PR_TRUE;
}
}
PRUint32 disposition;
rv = aChannel->GetContentDisposition(&disposition);
if (NS_SUCCEEDED(rv) && disposition == nsIChannel::DISPOSITION_ATTACHMENT)
forceExternalHandling = PR_TRUE;
LOG((" forceExternalHandling: %s", forceExternalHandling ? "yes" : "no"));
@ -576,6 +528,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
// Before dispatching to the external helper app service, check for an HTTP
// error page. If we got one, we don't want to handle it with a helper app,
// really.
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
if (httpChannel) {
PRBool requestSucceeded;
httpChannel->GetRequestSucceeded(&requestSucceeded);

Просмотреть файл

@ -72,7 +72,7 @@ ExternalHelperAppParent::ExternalHelperAppParent(
void
ExternalHelperAppParent::Init(ContentParent *parent,
const nsCString& aMimeContentType,
const nsCString& aContentDisposition,
const nsCString& aContentDispositionHeader,
const PRBool& aForceSave,
const IPC::URI& aReferrer)
{
@ -85,7 +85,9 @@ ExternalHelperAppParent::Init(ContentParent *parent,
SetPropertyAsInt64(NS_CHANNEL_PROP_CONTENT_LENGTH, mContentLength);
if (aReferrer)
SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), aReferrer);
SetContentDisposition(aContentDisposition);
mContentDispositionHeader = aContentDispositionHeader;
NS_GetFilenameFromDisposition(mContentDispositionFilename, mContentDispositionHeader, mURI);
mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
helperAppService->DoContent(aMimeContentType, this, nsnull,
aForceSave, getter_AddRefs(mListener));
}
@ -299,6 +301,36 @@ ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetContentDisposition(PRUint32 *aContentDisposition)
{
if (mContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
*aContentDisposition = mContentDisposition;
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
{
if (mContentDispositionFilename.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
aContentDispositionFilename = mContentDispositionFilename;
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
{
if (mContentDispositionHeader.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
aContentDispositionHeader = mContentDispositionHeader;
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetContentLength(PRInt32 *aContentLength)
{
@ -343,20 +375,6 @@ ExternalHelperAppParent::GetBaseChannel(nsIChannel* *aChannel)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetContentDisposition(nsACString& aContentDisposition)
{
aContentDisposition = mContentDisposition;
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppParent::SetContentDisposition(const nsACString& aDisposition)
{
mContentDisposition = aDisposition;
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetPartID(PRUint32* aPartID)
{

Просмотреть файл

@ -83,7 +83,9 @@ private:
nsLoadFlags mLoadFlags;
nsresult mStatus;
PRInt64 mContentLength;
nsCString mContentDisposition;
PRUint32 mContentDisposition;
nsString mContentDispositionFilename;
nsCString mContentDispositionHeader;
nsCString mEntityID;
};

Просмотреть файл

@ -227,66 +227,6 @@ static nsresult UnescapeFragment(const nsACString& aFragment, nsIURI* aURI,
return rv;
}
/** Gets the content-disposition header from a channel, using nsIHttpChannel
* or nsIMultipartChannel if available
* @param aChannel The channel to extract the disposition header from
* @param aDisposition Reference to a string where the header is to be stored
*/
static void ExtractDisposition(nsIChannel* aChannel, nsACString& aDisposition)
{
aDisposition.Truncate();
// First see whether this is an http channel
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
if (httpChannel)
{
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"), aDisposition);
}
if (aDisposition.IsEmpty())
{
nsCOMPtr<nsIMultiPartChannel> multipartChannel(do_QueryInterface(aChannel));
if (multipartChannel)
{
multipartChannel->GetContentDisposition(aDisposition);
}
}
}
/** Extracts the filename out of a content-disposition header
* @param aFilename [out] The filename. Can be empty on error.
* @param aDisposition Value of a Content-Disposition header
* @param aURI Optional. Will be used to get a fallback charset for the
* filename, if it is QI'able to nsIURL
* @param aMIMEHeaderParam Optional. Pointer to a nsIMIMEHeaderParam class, so
* that it doesn't need to be fetched by this function.
*/
static void GetFilenameFromDisposition(nsAString& aFilename,
const nsACString& aDisposition,
nsIURI* aURI = nsnull,
nsIMIMEHeaderParam* aMIMEHeaderParam = nsnull)
{
aFilename.Truncate();
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar(aMIMEHeaderParam);
if (!mimehdrpar) {
mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID);
if (!mimehdrpar)
return;
}
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
nsCAutoString fallbackCharset;
if (url)
url->GetOriginCharset(fallbackCharset);
// Get the value of 'filename' parameter
nsresult rv = mimehdrpar->GetParameter(aDisposition, "filename", fallbackCharset,
PR_TRUE, nsnull, aFilename);
if (NS_FAILED(rv) || aFilename.IsEmpty())
// Try 'name' parameter, instead.
rv = mimehdrpar->GetParameter(aDisposition, "name", fallbackCharset, PR_TRUE,
nsnull, aFilename);
}
/**
* Given a channel, returns the filename and extension the channel has.
* This uses the URL and other sources (nsIMultiPartChannel).
@ -318,51 +258,19 @@ static PRBool GetFilenameAndExtensionFromChannel(nsIChannel* aChannel,
* user. we shouldn't actually use that without their
* permission... otherwise just use our temp file
*/
nsCAutoString disp;
ExtractDisposition(aChannel, disp);
PRBool handleExternally = PR_FALSE;
nsCOMPtr<nsIURI> uri;
nsresult rv;
aChannel->GetURI(getter_AddRefs(uri));
// content-disposition: has format:
// disposition-type < ; name=value >* < ; filename=value > < ; name=value >*
if (!disp.IsEmpty())
PRUint32 disp;
nsresult rv = aChannel->GetContentDisposition(&disp);
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_FAILED(rv))
return PR_FALSE;
nsCAutoString fallbackCharset;
uri->GetOriginCharset(fallbackCharset);
// Get the disposition type
nsAutoString dispToken;
rv = mimehdrpar->GetParameter(disp, "", fallbackCharset, PR_TRUE,
nsnull, dispToken);
// RFC 2183, section 2.8 says that an unknown disposition
// value should be treated as "attachment"
// XXXbz this code is duplicated in nsDocumentOpenInfo::DispatchContent.
// Factor it out! Maybe store it in the nsDocumentOpenInfo?
if (NS_FAILED(rv) ||
(!dispToken.IsEmpty() &&
!dispToken.LowerCaseEqualsLiteral("inline") &&
// Broken sites just send
// Content-Disposition: filename="file"
// without a disposition token... screen those out.
!dispToken.EqualsIgnoreCase("filename", 8) &&
// Also in use is Content-Disposition: name="file"
!dispToken.EqualsIgnoreCase("name", 4)))
{
// We have a content-disposition of "attachment" or unknown
aChannel->GetContentDispositionFilename(aFileName);
if (disp == nsIChannel::DISPOSITION_ATTACHMENT)
handleExternally = PR_TRUE;
}
// We may not have a disposition type listed; some servers suck.
// But they could have listed a filename anyway.
GetFilenameFromDisposition(aFileName, disp, uri, mimehdrpar);
} // we had a disp header
}
// If the disposition header didn't work, try the filename from nsIURL
nsCOMPtr<nsIURI> uri;
aChannel->GetURI(getter_AddRefs(uri));
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
if (url && aFileName.IsEmpty())
{
@ -715,7 +623,7 @@ NS_IMETHODIMP nsExternalHelperAppService::DoContent(const nsACString& aMimeConte
nsCString disp;
if (channel)
ExtractDisposition(channel, disp);
channel->GetContentDispositionHeader(disp);
nsCOMPtr<nsIURI> referrer;
rv = NS_GetReferrerFromChannel(channel, getter_AddRefs(referrer));

Просмотреть файл

@ -247,6 +247,21 @@ NS_IMETHODIMP nsExtProtocolChannel::SetContentCharset(const nsACString &aContent
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsExtProtocolChannel::GetContentDisposition(PRUint32 *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsExtProtocolChannel::GetContentLength(PRInt32 * aContentLength)
{
*aContentLength = -1;