зеркало из https://github.com/mozilla/gecko-dev.git
Bug 65827
File extension (.php) determined from Content-Type header (or url extension) overrides filename in Content-Disposition header. r=bz sr=darin
This commit is contained in:
Родитель
aea8247f00
Коммит
7204f246e1
|
@ -107,7 +107,72 @@ static const char NEVER_ASK_FOR_OPEN_FILE_PREF[] = "openFile";
|
||||||
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||||||
static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
|
static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
|
||||||
|
|
||||||
// The following static table lists all of the "default" content type mappings we are going to use.
|
// Helper functions for Content-Disposition headers
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The following static table lists all of the "default" content type mappings we are going to use
|
||||||
struct nsDefaultMimeTypeEntry {
|
struct nsDefaultMimeTypeEntry {
|
||||||
const char* mMimeType;
|
const char* mMimeType;
|
||||||
const char* mFileExtension;
|
const char* mFileExtension;
|
||||||
|
@ -314,9 +379,29 @@ NS_IMETHODIMP nsExternalHelperAppService::DoContent(const char *aMimeContentType
|
||||||
nsCOMPtr<nsIURI> uri;
|
nsCOMPtr<nsIURI> uri;
|
||||||
channel->GetURI(getter_AddRefs(uri));
|
channel->GetURI(getter_AddRefs(uri));
|
||||||
|
|
||||||
|
// Firstly, get the content-disposition header
|
||||||
|
nsCAutoString disp;
|
||||||
|
ExtractDisposition(channel, disp);
|
||||||
|
if (!disp.IsEmpty()) {
|
||||||
|
nsAutoString filename;
|
||||||
|
GetFilenameFromDisposition(filename, disp, uri);
|
||||||
|
if (!filename.IsEmpty()) {
|
||||||
|
LOG(("Getting filename from disposition: Disp='%s', filename='%s'\n",
|
||||||
|
disp.get(), NS_ConvertUTF16toUTF8(filename).get()));
|
||||||
|
PRInt32 pointPos = filename.RFindChar('.');
|
||||||
|
if (pointPos != kNotFound) {
|
||||||
|
const nsAString & ext = Substring(filename, pointPos + 1, filename.Length() - pointPos);
|
||||||
|
CopyUTF16toUTF8(ext, fileExtension);
|
||||||
|
LOG(("...found extension '%s'\n", fileExtension.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// If the method is post, don't bother getting the file extension;
|
// If the method is post, don't bother getting the file extension;
|
||||||
// it will belong to a CGI script anyway
|
// it will belong to a CGI script anyway
|
||||||
if (uri && !methodIsPost) {
|
// Also, if we already have an extension, don't bother
|
||||||
|
if (uri && !methodIsPost && fileExtension.IsEmpty()) {
|
||||||
url = do_QueryInterface(uri);
|
url = do_QueryInterface(uri);
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
|
@ -915,25 +1000,12 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel* aChan
|
||||||
* permission...o.t. just use our temp file
|
* permission...o.t. just use our temp file
|
||||||
*/
|
*/
|
||||||
nsCAutoString disp;
|
nsCAutoString disp;
|
||||||
nsresult rv = NS_OK;
|
ExtractDisposition(aChannel, disp);
|
||||||
// First see whether this is an http channel
|
|
||||||
nsCOMPtr<nsIHttpChannel> httpChannel( do_QueryInterface( aChannel ) );
|
|
||||||
if ( httpChannel )
|
|
||||||
{
|
|
||||||
rv = httpChannel->GetResponseHeader( NS_LITERAL_CSTRING("content-disposition"), disp );
|
|
||||||
}
|
|
||||||
if ( NS_FAILED(rv) || disp.IsEmpty() )
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIMultiPartChannel> multipartChannel( do_QueryInterface( aChannel ) );
|
|
||||||
if ( multipartChannel )
|
|
||||||
{
|
|
||||||
rv = multipartChannel->GetContentDisposition( disp );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// content-disposition: has format:
|
// content-disposition: has format:
|
||||||
// disposition-type < ; name=value >* < ; filename=value > < ; name=value >*
|
// disposition-type < ; name=value >* < ; filename=value > < ; name=value >*
|
||||||
if ( NS_SUCCEEDED( rv ) && !disp.IsEmpty() )
|
if (!disp.IsEmpty())
|
||||||
{
|
{
|
||||||
|
nsresult rv;
|
||||||
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return;
|
return;
|
||||||
|
@ -956,25 +1028,7 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel* aChan
|
||||||
|
|
||||||
// We may not have a disposition type listed; some servers suck.
|
// We may not have a disposition type listed; some servers suck.
|
||||||
// But they could have listed a filename anyway.
|
// But they could have listed a filename anyway.
|
||||||
nsCOMPtr<nsIURI> srcUri;
|
GetFilenameFromDisposition(mSuggestedFileName, disp, mSourceUrl, mimehdrpar);
|
||||||
GetSource(getter_AddRefs(srcUri));
|
|
||||||
nsCOMPtr<nsIURL> url = do_QueryInterface(srcUri);
|
|
||||||
|
|
||||||
nsCAutoString fallbackCharset;
|
|
||||||
nsAutoString fileName;
|
|
||||||
if (url)
|
|
||||||
url->GetOriginCharset(fallbackCharset);
|
|
||||||
// Get the value of 'filename' parameter
|
|
||||||
rv = mimehdrpar->GetParameter(disp, "filename", fallbackCharset,
|
|
||||||
PR_TRUE, nsnull, fileName);
|
|
||||||
if (NS_FAILED(rv) || fileName.IsEmpty())
|
|
||||||
// Try 'name' parameter, instead.
|
|
||||||
rv = mimehdrpar->GetParameter(disp, "name",fallbackCharset, PR_TRUE,
|
|
||||||
nsnull, fileName);
|
|
||||||
if (NS_FAILED(rv) || fileName.IsEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
mSuggestedFileName = fileName;
|
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
// Make sure extension is still correct.
|
// Make sure extension is still correct.
|
||||||
|
@ -1207,7 +1261,7 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
|
||||||
// ignore failure...
|
// ignore failure...
|
||||||
ExtractSuggestedFileNameFromChannel(aChannel);
|
ExtractSuggestedFileNameFromChannel(aChannel);
|
||||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface( aChannel );
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface( aChannel );
|
||||||
if ( httpChannel )
|
if (httpChannel)
|
||||||
{
|
{
|
||||||
// Turn off content encoding conversions if needed
|
// Turn off content encoding conversions if needed
|
||||||
PRBool applyConversion = PR_TRUE;
|
PRBool applyConversion = PR_TRUE;
|
||||||
|
|
|
@ -401,23 +401,16 @@ already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetByExtension(const char *a
|
||||||
|
|
||||||
already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS(const char *aMIMEType, const char *aFileExt)
|
already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS(const char *aMIMEType, const char *aFileExt)
|
||||||
{
|
{
|
||||||
if (PL_strcasecmp(aMIMEType, APPLICATION_OCTET_STREAM) == 0) {
|
|
||||||
/* XXX Gross hack to wallpaper over the most common Win32
|
|
||||||
* extension issues caused by the fix for bug 116938. See bug
|
|
||||||
* 120327, comment 271 for why this is needed. Not even sure we
|
|
||||||
* want to remove this once we have fixed all this stuff to work
|
|
||||||
* right; any info we get from the OS on this type is pretty much
|
|
||||||
* useless....
|
|
||||||
* Just lookup by extension for this filetype.
|
|
||||||
*/
|
|
||||||
aMIMEType = nsnull;
|
|
||||||
// If we now have nothing to lookup from, return
|
|
||||||
if (!aFileExt || !*aFileExt)
|
|
||||||
return nsnull;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCAutoString fileExtension;
|
nsCAutoString fileExtension;
|
||||||
if (aMIMEType && *aMIMEType) {
|
/* XXX The strcasecmp is a gross hack to wallpaper over the most common Win32
|
||||||
|
* extension issues caused by the fix for bug 116938. See bug
|
||||||
|
* 120327, comment 271 for why this is needed. Not even sure we
|
||||||
|
* want to remove this once we have fixed all this stuff to work
|
||||||
|
* right; any info we get from the OS on this type is pretty much
|
||||||
|
* useless....
|
||||||
|
* We'll do extension-based lookup for this type later in this function.
|
||||||
|
*/
|
||||||
|
if (aMIMEType && *aMIMEType && PL_strcasecmp(aMIMEType, APPLICATION_OCTET_STREAM) != 0) {
|
||||||
// (1) try to use the windows mime database to see if there is a mapping to a file extension
|
// (1) try to use the windows mime database to see if there is a mapping to a file extension
|
||||||
// (2) try to see if we have some left over 4.x registry info we can peek at...
|
// (2) try to see if we have some left over 4.x registry info we can peek at...
|
||||||
GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension);
|
GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче