зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1437281 - OSX dragging image to desktop changes OSX File associations r=mystor
On Mac, when dragging an image, add the image request's MIME type to the transfer so that the MIME-extension check can be done in the parent process to avoid content sandboxing issues. MozReview-Commit-ID: 3cb4fCr6GnL --HG-- extra : rebase_source : 43720237b467765401b5504c57bbc1b43d4dfdc0
This commit is contained in:
Родитель
2eec0e80c1
Коммит
c6b21edd12
|
@ -77,9 +77,11 @@ private:
|
|||
void AddString(DataTransfer* aDataTransfer,
|
||||
const nsAString& aFlavor,
|
||||
const nsAString& aData,
|
||||
nsIPrincipal* aPrincipal);
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden=false);
|
||||
nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
|
||||
DataTransfer* aDataTransfer);
|
||||
nsresult GetImageData(imgIContainer* aImage, imgIRequest* aRequest);
|
||||
static nsresult GetDraggableSelectionData(nsISelection* inSelection,
|
||||
nsIContent* inRealTargetNode,
|
||||
nsIContent **outImageOrLinkNode,
|
||||
|
@ -99,6 +101,9 @@ private:
|
|||
nsString mUrlString;
|
||||
nsString mImageSourceString;
|
||||
nsString mImageDestFileName;
|
||||
#if defined (XP_MACOSX)
|
||||
nsString mImageRequestMime;
|
||||
#endif
|
||||
nsString mTitleString;
|
||||
// will be filled automatically if you fill urlstring
|
||||
nsString mHtmlString;
|
||||
|
@ -138,22 +143,16 @@ NS_IMPL_ISUPPORTS(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider)
|
|||
// used on platforms where it's possible to drag items (e.g. images)
|
||||
// into the file system
|
||||
nsresult
|
||||
nsContentAreaDragDropDataProvider::SaveURIToFile(nsAString& inSourceURIString,
|
||||
nsContentAreaDragDropDataProvider::SaveURIToFile(nsIURI* inSourceURI,
|
||||
nsIFile* inDestFile,
|
||||
bool isPrivate)
|
||||
{
|
||||
nsCOMPtr<nsIURI> sourceURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(sourceURI), inSourceURIString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(sourceURI);
|
||||
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(inSourceURI);
|
||||
if (!sourceURL) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
rv = inDestFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
nsresult rv = inDestFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// we rely on the fact that the WPB is refcounted by the channel etc,
|
||||
|
@ -166,12 +165,56 @@ nsContentAreaDragDropDataProvider::SaveURIToFile(nsAString& inSourceURIString,
|
|||
persist->SetPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION);
|
||||
|
||||
// referrer policy can be anything since the referrer is nullptr
|
||||
return persist->SavePrivacyAwareURI(sourceURI, nullptr, nullptr,
|
||||
return persist->SavePrivacyAwareURI(inSourceURI, nullptr, nullptr,
|
||||
mozilla::net::RP_Unset,
|
||||
nullptr, nullptr,
|
||||
inDestFile, isPrivate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the provided filename extension is valid for the MIME type and
|
||||
* return the MIME type's primary extension.
|
||||
*
|
||||
* @param aExtension [in] the extension to check
|
||||
* @param aMimeType [in] the MIME type to check the extension with
|
||||
* @param aIsValidExtension [out] true if |aExtension| is valid for
|
||||
* |aMimeType|
|
||||
* @param aPrimaryExtension [out] the primary extension for the MIME type
|
||||
* to potentially be used as a replacement
|
||||
* for |aExtension|
|
||||
*/
|
||||
nsresult
|
||||
CheckAndGetExtensionForMime(const nsCString& aExtension,
|
||||
const nsCString& aMimeType,
|
||||
bool* aIsValidExtension,
|
||||
nsACString* aPrimaryExtension)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
rv = mimeService->GetFromTypeAndExtension(aMimeType, EmptyCString(),
|
||||
getter_AddRefs(mimeInfo));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mimeInfo->GetPrimaryExtension(*aPrimaryExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aExtension.IsEmpty()) {
|
||||
*aIsValidExtension = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = mimeInfo->ExtensionExists(aExtension, aIsValidExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is our nsIFlavorDataProvider callback. There are several
|
||||
// assumptions here that make this work:
|
||||
//
|
||||
|
@ -214,6 +257,10 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
|
|||
if (sourceURLString.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIURI> sourceURI;
|
||||
rv = NS_NewURI(getter_AddRefs(sourceURI), sourceURLString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aTransferable->GetTransferData(kFilePromiseDestFilename,
|
||||
getter_AddRefs(tmp), &dataSize);
|
||||
supportsString = do_QueryInterface(tmp);
|
||||
|
@ -225,6 +272,60 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
|
|||
if (targetFilename.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Use the image request's MIME type to ensure the filename's
|
||||
// extension is compatible with the OS's handler for this type.
|
||||
// If it isn't, or is missing, replace the extension with the
|
||||
// primary extension. On Mac, do this in the parent process
|
||||
// because sandboxing blocks access to MIME-handler info from
|
||||
// content processes.
|
||||
if (XRE_IsParentProcess()) {
|
||||
aTransferable->GetTransferData(kImageRequestMime,
|
||||
getter_AddRefs(tmp), &dataSize);
|
||||
supportsString = do_QueryInterface(tmp);
|
||||
if (!supportsString)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString imageRequestMime;
|
||||
supportsString->GetData(imageRequestMime);
|
||||
|
||||
// If we have a MIME type, check the extension is compatible
|
||||
if (!imageRequestMime.IsEmpty()) {
|
||||
// Build a URL to get the filename extension
|
||||
nsCOMPtr<nsIURL> imageURL = do_QueryInterface(sourceURI, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString extension;
|
||||
rv = imageURL->GetFileExtension(extension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ConvertUTF16toUTF8 mimeCString(imageRequestMime);
|
||||
bool isValidExtension;
|
||||
nsAutoCString primaryExtension;
|
||||
rv = CheckAndGetExtensionForMime(extension,
|
||||
mimeCString,
|
||||
&isValidExtension,
|
||||
&primaryExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isValidExtension) {
|
||||
// The filename extension is missing or incompatible
|
||||
// with the MIME type, replace it with the primary
|
||||
// extension.
|
||||
nsAutoCString newFileName;
|
||||
rv = imageURL->GetFileBaseName(newFileName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
newFileName.Append(".");
|
||||
newFileName.Append(primaryExtension);
|
||||
targetFilename = NS_ConvertUTF8toUTF16(newFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// make the filename safe for the filesystem
|
||||
targetFilename.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
|
||||
'-');
|
||||
#endif /* defined(XP_MACOSX) */
|
||||
|
||||
// get the target directory from the kFilePromiseDirectoryMime
|
||||
// flavor
|
||||
nsCOMPtr<nsISupports> dirPrimitive;
|
||||
|
@ -244,7 +345,7 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
|
|||
bool isPrivate;
|
||||
aTransferable->GetIsPrivateData(&isPrivate);
|
||||
|
||||
rv = SaveURIToFile(sourceURLString, file, isPrivate);
|
||||
rv = SaveURIToFile(sourceURI, file, isPrivate);
|
||||
// send back an nsIFile
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CallQueryInterface(file, aData);
|
||||
|
@ -362,6 +463,80 @@ DragDataProducer::GetNodeString(nsIContent* inNode,
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
DragDataProducer::GetImageData(imgIContainer* aImage, imgIRequest* aRequest)
|
||||
{
|
||||
nsCOMPtr<nsIURI> imgUri;
|
||||
aRequest->GetURI(getter_AddRefs(imgUri));
|
||||
|
||||
nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
|
||||
if (imgUrl) {
|
||||
nsAutoCString spec;
|
||||
nsresult rv = imgUrl->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// pass out the image source string
|
||||
CopyUTF8toUTF16(spec, mImageSourceString);
|
||||
|
||||
nsCString mimeType;
|
||||
aRequest->GetMimeType(getter_Copies(mimeType));
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Save the MIME type so we can make sure the extension
|
||||
// is compatible (and replace it if it isn't) when the
|
||||
// image is dropped. On Mac, we need to get the OS MIME
|
||||
// handler information in the parent due to sandboxing.
|
||||
CopyUTF8toUTF16(mimeType, mImageRequestMime);
|
||||
#else
|
||||
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
|
||||
getter_AddRefs(mimeInfo));
|
||||
if (mimeInfo) {
|
||||
nsAutoCString extension;
|
||||
imgUrl->GetFileExtension(extension);
|
||||
|
||||
bool validExtension;
|
||||
if (extension.IsEmpty() ||
|
||||
NS_FAILED(mimeInfo->ExtensionExists(extension,
|
||||
&validExtension)) ||
|
||||
!validExtension) {
|
||||
// Fix the file extension in the URL
|
||||
nsAutoCString primaryExtension;
|
||||
mimeInfo->GetPrimaryExtension(primaryExtension);
|
||||
|
||||
rv = NS_MutateURI(imgUrl)
|
||||
.Apply(NS_MutatorMethod(&nsIURLMutator::SetFileExtension,
|
||||
primaryExtension, nullptr))
|
||||
.Finalize(imgUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
#endif /* defined(XP_MACOSX) */
|
||||
|
||||
nsAutoCString fileName;
|
||||
imgUrl->GetFileName(fileName);
|
||||
|
||||
NS_UnescapeURL(fileName);
|
||||
|
||||
#if !defined(XP_MACOSX)
|
||||
// make the filename safe for the filesystem
|
||||
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
|
||||
#endif
|
||||
|
||||
CopyUTF8toUTF16(fileName, mImageDestFileName);
|
||||
|
||||
// and the image object
|
||||
mImage = aImage;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DragDataProducer::Produce(DataTransfer* aDataTransfer,
|
||||
bool* aCanDrag,
|
||||
|
@ -564,67 +739,9 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
|
|||
nsCOMPtr<imgIContainer> img =
|
||||
nsContentUtils::GetImageFromContent(image,
|
||||
getter_AddRefs(imgRequest));
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService("@mozilla.org/mime;1");
|
||||
|
||||
// Fix the file extension in the URL if necessary
|
||||
if (imgRequest && mimeService) {
|
||||
nsCOMPtr<nsIURI> imgUri;
|
||||
imgRequest->GetURI(getter_AddRefs(imgUri));
|
||||
|
||||
nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
|
||||
|
||||
if (imgUrl) {
|
||||
nsAutoCString extension;
|
||||
imgUrl->GetFileExtension(extension);
|
||||
|
||||
nsCString mimeType;
|
||||
imgRequest->GetMimeType(getter_Copies(mimeType));
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
|
||||
getter_AddRefs(mimeInfo));
|
||||
|
||||
if (mimeInfo) {
|
||||
nsAutoCString spec;
|
||||
rv = imgUrl->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// pass out the image source string
|
||||
CopyUTF8toUTF16(spec, mImageSourceString);
|
||||
|
||||
bool validExtension;
|
||||
if (extension.IsEmpty() ||
|
||||
NS_FAILED(mimeInfo->ExtensionExists(extension,
|
||||
&validExtension)) ||
|
||||
!validExtension) {
|
||||
// Fix the file extension in the URL
|
||||
nsAutoCString primaryExtension;
|
||||
mimeInfo->GetPrimaryExtension(primaryExtension);
|
||||
|
||||
rv = NS_MutateURI(imgUrl)
|
||||
.Apply(NS_MutatorMethod(&nsIURLMutator::SetFileExtension,
|
||||
primaryExtension, nullptr))
|
||||
.Finalize(imgUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsAutoCString fileName;
|
||||
imgUrl->GetFileName(fileName);
|
||||
|
||||
NS_UnescapeURL(fileName);
|
||||
|
||||
// make the filename safe for the filesystem
|
||||
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
|
||||
'-');
|
||||
|
||||
CopyUTF8toUTF16(fileName, mImageDestFileName);
|
||||
|
||||
// and the image object
|
||||
mImage = img;
|
||||
}
|
||||
}
|
||||
if (imgRequest) {
|
||||
rv = GetImageData(img, imgRequest);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (parentLink) {
|
||||
|
@ -730,11 +847,12 @@ void
|
|||
DragDataProducer::AddString(DataTransfer* aDataTransfer,
|
||||
const nsAString& aFlavor,
|
||||
const nsAString& aData,
|
||||
nsIPrincipal* aPrincipal)
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden)
|
||||
{
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(aData);
|
||||
aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal);
|
||||
aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal, aHidden);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -810,6 +928,10 @@ DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode,
|
|||
mImageSourceString, principal);
|
||||
AddString(aDataTransfer, NS_LITERAL_STRING(kFilePromiseDestFilename),
|
||||
mImageDestFileName, principal);
|
||||
#if defined(XP_MACOSX)
|
||||
AddString(aDataTransfer, NS_LITERAL_STRING(kImageRequestMime),
|
||||
mImageRequestMime, principal, /* aHidden= */ true);
|
||||
#endif
|
||||
|
||||
// if not an anchor, add the image url
|
||||
if (!mIsAnchor) {
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFLAVORDATAPROVIDER
|
||||
|
||||
nsresult SaveURIToFile(nsAString& inSourceURIString,
|
||||
nsresult SaveURIToFile(nsIURI* inSourceURI,
|
||||
nsIFile* inDestFile, bool isPrivate);
|
||||
};
|
||||
|
||||
|
|
|
@ -898,7 +898,7 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
|||
kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
|
||||
kFileMime, kFilePromiseMime, kFilePromiseURLMime,
|
||||
kFilePromiseDestFilename, kFilePromiseDirectoryMime,
|
||||
kMozTextInternal, kHTMLContext, kHTMLInfo };
|
||||
kMozTextInternal, kHTMLContext, kHTMLInfo, kImageRequestMime };
|
||||
|
||||
/*
|
||||
* Two passes are made here to iterate over all of the types. First, look for
|
||||
|
@ -1202,7 +1202,8 @@ nsresult
|
|||
DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
||||
nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal)
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden)
|
||||
{
|
||||
nsAutoString format;
|
||||
GetRealFormat(aFormat, format);
|
||||
|
@ -1211,7 +1212,7 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
|||
RefPtr<DataTransferItem> item =
|
||||
mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
|
||||
/* aInsertOnly = */ false,
|
||||
/* aHidden= */ false,
|
||||
aHidden,
|
||||
rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
|
|
@ -374,7 +374,8 @@ public:
|
|||
nsresult SetDataWithPrincipal(const nsAString& aFormat,
|
||||
nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden=false);
|
||||
|
||||
// Variation of SetDataWithPrincipal with handles extracting
|
||||
// kCustomTypesMime data into separate types.
|
||||
|
|
|
@ -41,6 +41,12 @@ interface nsIPrincipal;
|
|||
#define kHTMLContext "text/_moz_htmlcontext"
|
||||
#define kHTMLInfo "text/_moz_htmlinfo"
|
||||
|
||||
// Holds the MIME type from the image request. This is used to ensure the
|
||||
// local application handler for the request's MIME type accepts images with
|
||||
// the given filename extension (from kFilePromiseDestFilename). When the
|
||||
// image is dragged out, we replace the extension with a compatible extension.
|
||||
#define kImageRequestMime "text/_moz_requestmime"
|
||||
|
||||
// the source URL for a file promise
|
||||
#define kFilePromiseURLMime "application/x-moz-file-promise-url"
|
||||
// the destination filename for a file promise
|
||||
|
|
Загрузка…
Ссылка в новой задаче