Bug 337051: Add origin and referrer URL metadata to downloaded files on OS X. r=mstange,pamadini

This commit is contained in:
Josh Aas 2016-09-13 02:25:36 -05:00
parent 27cb0a7981
commit 0a5546331b
5 changed files with 184 additions and 2 deletions

View File

@ -26,6 +26,8 @@ interface mozIDownloadPlatform : nsISupports
*
* @param aSource
* Source URI of the download
* @param aReferrer
* Referrer URI of the download
* @param aTarget
* Downloaded file
* @param aContentType
@ -34,7 +36,7 @@ interface mozIDownloadPlatform : nsISupports
* True for private downloads
* @return none
*/
void downloadDone(in nsIURI aSource, in nsIFile aTarget,
void downloadDone(in nsIURI aSource, in nsIURI aReferrer, in nsIFile aTarget,
in ACString aContentType, in boolean aIsPrivate);
/**

View File

@ -679,7 +679,13 @@ this.DownloadIntegration = {
}
}
let aReferrer = null;
if (aDownload.source.referrer) {
aReferrer: NetUtil.newURI(aDownload.source.referrer);
}
gDownloadPlatform.downloadDone(NetUtil.newURI(aDownload.source.url),
aReferrer,
new FileUtils.File(aDownload.target.path),
aDownload.contentType,
aDownload.source.isPrivate);

View File

@ -24,6 +24,7 @@
#ifdef XP_MACOSX
#include <CoreFoundation/CoreFoundation.h>
#include "../../../../../xpcom/io/CocoaFileUtils.h"
#endif
#ifdef MOZ_WIDGET_ANDROID
@ -69,7 +70,32 @@ static void gio_set_metadata_done(GObject *source_obj, GAsyncResult *res, gpoint
}
#endif
nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIFile* aTarget,
#ifdef XP_MACOSX
// Caller is responsible for freeing any result (CF Create Rule)
CFURLRef CreateCFURLFromNSIURI(nsIURI *aURI) {
nsAutoCString spec;
if (aURI) {
aURI->GetSpec(spec);
}
CFStringRef urlStr = ::CFStringCreateWithCString(kCFAllocatorDefault,
spec.get(),
kCFStringEncodingUTF8);
if (!urlStr) {
return NULL;
}
CFURLRef url = ::CFURLCreateWithString(kCFAllocatorDefault,
urlStr,
NULL);
::CFRelease(urlStr);
return url;
}
#endif
nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIFile* aTarget,
const nsACString& aContentType, bool aIsPrivate)
{
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) \
@ -130,6 +156,33 @@ nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIFile* aTarget,
::CFNotificationCenterPostNotification(center, CFSTR("com.apple.DownloadFileFinished"),
observedObject, nullptr, TRUE);
::CFRelease(observedObject);
// Add OS X origin and referrer file metadata
CFStringRef pathCFStr = NULL;
if (!path.IsEmpty()) {
pathCFStr = ::CFStringCreateWithCharacters(kCFAllocatorDefault,
(const UniChar*)path.get(),
path.Length());
}
if (pathCFStr) {
CFURLRef sourceCFURL = CreateCFURLFromNSIURI(aSource);
CFURLRef referrerCFURL = CreateCFURLFromNSIURI(aReferrer);
CocoaFileUtils::AddOriginMetadataToFile(pathCFStr,
sourceCFURL,
referrerCFURL);
CocoaFileUtils::AddQuarantineMetadataToFile(pathCFStr,
sourceCFURL,
referrerCFURL);
::CFRelease(pathCFStr);
if (sourceCFURL) {
::CFRelease(sourceCFURL);
}
if (referrerCFURL) {
::CFRelease(referrerCFURL);
}
}
#endif
if (mozilla::Preferences::GetBool("device.storage.enabled", true)) {
// Tell DeviceStorage that a new file may have been added.

View File

@ -21,6 +21,12 @@ nsresult GetFileCreatorCode(CFURLRef aUrl, OSType* aCreatorCode);
nsresult SetFileCreatorCode(CFURLRef aUrl, OSType aCreatorCode);
nsresult GetFileTypeCode(CFURLRef aUrl, OSType* aTypeCode);
nsresult SetFileTypeCode(CFURLRef aUrl, OSType aTypeCode);
void AddOriginMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL);
void AddQuarantineMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL);
} // namespace CocoaFileUtils

View File

@ -136,4 +136,119 @@ nsresult SetFileTypeCode(CFURLRef url, OSType typeCode)
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
void AddOriginMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL) {
typedef OSStatus (*MDItemSetAttribute_type)(MDItemRef, CFStringRef, CFTypeRef);
static MDItemSetAttribute_type mdItemSetAttributeFunc = NULL;
static bool did_symbol_lookup = false;
if (!did_symbol_lookup) {
did_symbol_lookup = true;
CFBundleRef metadata_bundle = ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Metadata"));
if (!metadata_bundle) {
return;
}
mdItemSetAttributeFunc = (MDItemSetAttribute_type)
::CFBundleGetFunctionPointerForName(metadata_bundle, CFSTR("MDItemSetAttribute"));
}
if (!mdItemSetAttributeFunc) {
return;
}
MDItemRef mdItem = ::MDItemCreate(NULL, filePath);
if (!mdItem) {
return;
}
CFMutableArrayRef list = ::CFArrayCreateMutable(kCFAllocatorDefault, 2, NULL);
if (!list) {
::CFRelease(mdItem);
return;
}
// The first item in the list is the source URL of the downloaded file.
if (sourceURL) {
::CFArrayAppendValue(list, ::CFURLGetString(sourceURL));
}
// If the referrer is known, store that in the second position.
if (referrerURL) {
::CFArrayAppendValue(list, ::CFURLGetString(referrerURL));
}
mdItemSetAttributeFunc(mdItem, kMDItemWhereFroms, list);
::CFRelease(list);
::CFRelease(mdItem);
}
void AddQuarantineMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL) {
CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
filePath,
kCFURLPOSIXPathStyle,
false);
CFDictionaryRef quarantineProps = NULL;
Boolean success = ::CFURLCopyResourcePropertyForKey(fileURL,
kLSItemQuarantineProperties,
&quarantineProps,
NULL);
// If there aren't any quarantine properties then the user probably
// set up an exclusion and we don't need to add metadata.
if (!success || !quarantineProps) {
::CFRelease(fileURL);
return;
}
// We don't know what to do if the props aren't a dictionary.
if (::CFGetTypeID(quarantineProps) != ::CFDictionaryGetTypeID()) {
::CFRelease(fileURL);
::CFRelease(quarantineProps);
return;
}
// Make a mutable copy of the properties.
CFMutableDictionaryRef mutQuarantineProps =
::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)quarantineProps);
::CFRelease(quarantineProps);
// Add metadata that the OS couldn't infer.
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineTypeKey)) {
CFStringRef type = kLSQuarantineTypeOtherDownload;
CFStringRef scheme = ::CFURLCopyScheme(sourceURL);
if (::CFStringCompare(scheme, CFSTR("http"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
::CFStringCompare(scheme, CFSTR("http"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
type = kLSQuarantineTypeWebDownload;
}
::CFRelease(scheme);
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineTypeKey, type);
}
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey)) {
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineOriginURLKey, referrerURL);
}
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineDataURLKey)) {
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineDataURLKey, sourceURL);
}
// Set quarantine properties on file.
::CFURLSetResourcePropertyForKey(fileURL,
kLSItemQuarantineProperties,
mutQuarantineProps,
NULL);
::CFRelease(fileURL);
::CFRelease(mutQuarantineProps);
}
} // namespace CocoaFileUtils