Skip to content

Commit

Permalink
Bug 337051: Add origin and referrer URL metadata to downloaded files …
Browse files Browse the repository at this point in the history
…on OS X. r=mstange,pamadini
  • Loading branch information
bdaehlie committed Sep 13, 2016
1 parent 27cb0a7 commit 0a55463
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);

/**
Expand Down
6 changes: 6 additions & 0 deletions toolkit/components/jsdownloads/src/DownloadIntegration.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
55 changes: 54 additions & 1 deletion toolkit/components/jsdownloads/src/DownloadPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#ifdef XP_MACOSX
#include <CoreFoundation/CoreFoundation.h>
#include "../../../../../xpcom/io/CocoaFileUtils.h"
#endif

#ifdef MOZ_WIDGET_ANDROID
Expand Down Expand Up @@ -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) \
Expand Down Expand Up @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions xpcom/io/CocoaFileUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
115 changes: 115 additions & 0 deletions xpcom/io/CocoaFileUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 0a55463

Please sign in to comment.