forked from mirrors/gecko-dev
MozReview-Commit-ID: GuWeax0ubv3 --HG-- rename : toolkit/components/jsdownloads/src/DownloadCore.jsm => toolkit/components/downloads/DownloadCore.jsm rename : toolkit/components/jsdownloads/src/DownloadHistory.jsm => toolkit/components/downloads/DownloadHistory.jsm rename : toolkit/components/jsdownloads/src/DownloadIntegration.jsm => toolkit/components/downloads/DownloadIntegration.jsm rename : toolkit/components/jsdownloads/src/DownloadLegacy.js => toolkit/components/downloads/DownloadLegacy.js rename : toolkit/components/jsdownloads/src/DownloadList.jsm => toolkit/components/downloads/DownloadList.jsm rename : toolkit/components/jsdownloads/src/DownloadPaths.jsm => toolkit/components/downloads/DownloadPaths.jsm rename : toolkit/components/jsdownloads/src/DownloadPlatform.cpp => toolkit/components/downloads/DownloadPlatform.cpp rename : toolkit/components/jsdownloads/src/DownloadPlatform.h => toolkit/components/downloads/DownloadPlatform.h rename : toolkit/components/jsdownloads/src/DownloadStore.jsm => toolkit/components/downloads/DownloadStore.jsm rename : toolkit/components/jsdownloads/src/DownloadUIHelper.jsm => toolkit/components/downloads/DownloadUIHelper.jsm rename : toolkit/components/jsdownloads/src/Downloads.jsm => toolkit/components/downloads/Downloads.jsm rename : toolkit/components/jsdownloads/src/Downloads.manifest => toolkit/components/downloads/Downloads.manifest rename : toolkit/components/jsdownloads/src/moz.build => toolkit/components/downloads/moz.build rename : toolkit/components/jsdownloads/public/mozIDownloadPlatform.idl => toolkit/components/downloads/mozIDownloadPlatform.idl rename : toolkit/components/jsdownloads/test/browser/.eslintrc.js => toolkit/components/downloads/test/browser/.eslintrc.js rename : toolkit/components/jsdownloads/test/browser/browser.ini => toolkit/components/downloads/test/browser/browser.ini rename : toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js => toolkit/components/downloads/test/browser/browser_DownloadPDFSaver.js rename : toolkit/components/jsdownloads/test/browser/head.js => toolkit/components/downloads/test/browser/head.js rename : toolkit/components/jsdownloads/test/browser/testFile.html => toolkit/components/downloads/test/browser/testFile.html rename : toolkit/components/jsdownloads/test/data/.eslintrc.js => toolkit/components/downloads/test/data/.eslintrc.js rename : toolkit/components/jsdownloads/test/data/empty.txt => toolkit/components/downloads/test/data/empty.txt rename : toolkit/components/jsdownloads/test/data/source.txt => toolkit/components/downloads/test/data/source.txt rename : toolkit/components/jsdownloads/test/unit/.eslintrc.js => toolkit/components/downloads/test/unit/.eslintrc.js rename : toolkit/components/jsdownloads/test/unit/common_test_Download.js => toolkit/components/downloads/test/unit/common_test_Download.js rename : toolkit/components/jsdownloads/test/unit/head.js => toolkit/components/downloads/test/unit/head.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadCore.js => toolkit/components/downloads/test/unit/test_DownloadCore.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadHistory.js => toolkit/components/downloads/test/unit/test_DownloadHistory.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js => toolkit/components/downloads/test/unit/test_DownloadIntegration.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js => toolkit/components/downloads/test/unit/test_DownloadLegacy.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadList.js => toolkit/components/downloads/test/unit/test_DownloadList.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js => toolkit/components/downloads/test/unit/test_DownloadPaths.js rename : toolkit/components/jsdownloads/test/unit/test_DownloadStore.js => toolkit/components/downloads/test/unit/test_DownloadStore.js rename : toolkit/components/jsdownloads/test/unit/test_Downloads.js => toolkit/components/downloads/test/unit/test_Downloads.js rename : toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js => toolkit/components/downloads/test/unit/test_PrivateTemp.js rename : toolkit/components/jsdownloads/test/unit/xpcshell.ini => toolkit/components/downloads/test/unit/xpcshell.ini extra : rebase_source : 7062bc9278460abf0da3f1ae2ba02daa3c4f6abc
275 lines
8.4 KiB
C++
275 lines
8.4 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "DownloadPlatform.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsString.h"
|
|
#include "nsINestedURI.h"
|
|
#include "nsIProtocolHandler.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIFile.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/Services.h"
|
|
|
|
#define PREF_BDM_ADDTORECENTDOCS "browser.download.manager.addToRecentDocs"
|
|
|
|
#ifdef XP_WIN
|
|
#include <shlobj.h>
|
|
#include <urlmon.h>
|
|
#include "nsILocalFileWin.h"
|
|
#endif
|
|
|
|
#ifdef XP_MACOSX
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include "../../../xpcom/io/CocoaFileUtils.h"
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
#include "FennecJNIWrappers.h"
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
#include <gtk/gtk.h>
|
|
#endif
|
|
|
|
using namespace mozilla;
|
|
|
|
DownloadPlatform *DownloadPlatform::gDownloadPlatformService = nullptr;
|
|
|
|
NS_IMPL_ISUPPORTS(DownloadPlatform, mozIDownloadPlatform);
|
|
|
|
DownloadPlatform* DownloadPlatform::GetDownloadPlatform()
|
|
{
|
|
if (!gDownloadPlatformService) {
|
|
gDownloadPlatformService = new DownloadPlatform();
|
|
}
|
|
|
|
NS_ADDREF(gDownloadPlatformService);
|
|
|
|
#if defined(MOZ_WIDGET_GTK)
|
|
g_type_init();
|
|
#endif
|
|
|
|
return gDownloadPlatformService;
|
|
}
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
static void gio_set_metadata_done(GObject *source_obj, GAsyncResult *res, gpointer user_data)
|
|
{
|
|
GError *err = nullptr;
|
|
g_file_set_attributes_finish(G_FILE(source_obj), res, nullptr, &err);
|
|
if (err) {
|
|
#ifdef DEBUG
|
|
NS_DebugBreak(NS_DEBUG_WARNING, "Set file metadata failed: ", err->message, __FILE__, __LINE__);
|
|
#endif
|
|
g_error_free(err);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#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) \
|
|
|| defined(MOZ_WIDGET_GTK)
|
|
|
|
nsAutoString path;
|
|
if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) {
|
|
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID)
|
|
// On Windows and Gtk, add the download to the system's "recent documents"
|
|
// list, with a pref to disable.
|
|
{
|
|
bool addToRecentDocs = Preferences::GetBool(PREF_BDM_ADDTORECENTDOCS);
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
if (jni::IsFennec() && addToRecentDocs) {
|
|
java::DownloadsIntegration::ScanMedia(path, aContentType);
|
|
}
|
|
#else
|
|
if (addToRecentDocs && !aIsPrivate) {
|
|
#ifdef XP_WIN
|
|
::SHAddToRecentDocs(SHARD_PATHW, path.get());
|
|
#elif defined(MOZ_WIDGET_GTK)
|
|
GtkRecentManager* manager = gtk_recent_manager_get_default();
|
|
|
|
gchar* uri = g_filename_to_uri(NS_ConvertUTF16toUTF8(path).get(),
|
|
nullptr, nullptr);
|
|
if (uri) {
|
|
gtk_recent_manager_add_item(manager, uri);
|
|
g_free(uri);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
#ifdef MOZ_WIDGET_GTK
|
|
// Use GIO to store the source URI for later display in the file manager.
|
|
GFile* gio_file = g_file_new_for_path(NS_ConvertUTF16toUTF8(path).get());
|
|
nsCString source_uri;
|
|
nsresult rv = aSource->GetSpec(source_uri);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
GFileInfo *file_info = g_file_info_new();
|
|
g_file_info_set_attribute_string(file_info, "metadata::download-uri", source_uri.get());
|
|
g_file_set_attributes_async(gio_file,
|
|
file_info,
|
|
G_FILE_QUERY_INFO_NONE,
|
|
G_PRIORITY_DEFAULT,
|
|
nullptr, gio_set_metadata_done, nullptr);
|
|
g_object_unref(file_info);
|
|
g_object_unref(gio_file);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef XP_MACOSX
|
|
// On OS X, make the downloads stack bounce.
|
|
CFStringRef observedObject = ::CFStringCreateWithCString(kCFAllocatorDefault,
|
|
NS_ConvertUTF16toUTF8(path).get(),
|
|
kCFStringEncodingUTF8);
|
|
CFNotificationCenterRef center = ::CFNotificationCenterGetDistributedCenter();
|
|
::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 && !aIsPrivate) {
|
|
bool isFromWeb = IsURLPossiblyFromWeb(aSource);
|
|
|
|
CFURLRef sourceCFURL = CreateCFURLFromNSIURI(aSource);
|
|
CFURLRef referrerCFURL = CreateCFURLFromNSIURI(aReferrer);
|
|
|
|
CocoaFileUtils::AddOriginMetadataToFile(pathCFStr,
|
|
sourceCFURL,
|
|
referrerCFURL);
|
|
CocoaFileUtils::AddQuarantineMetadataToFile(pathCFStr,
|
|
sourceCFURL,
|
|
referrerCFURL,
|
|
isFromWeb);
|
|
|
|
::CFRelease(pathCFStr);
|
|
if (sourceCFURL) {
|
|
::CFRelease(sourceCFURL);
|
|
}
|
|
if (referrerCFURL) {
|
|
::CFRelease(referrerCFURL);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult DownloadPlatform::MapUrlToZone(const nsAString& aURL,
|
|
uint32_t* aZone)
|
|
{
|
|
#ifdef XP_WIN
|
|
RefPtr<IInternetSecurityManager> inetSecMgr;
|
|
if (FAILED(CoCreateInstance(CLSID_InternetSecurityManager, NULL,
|
|
CLSCTX_ALL, IID_IInternetSecurityManager,
|
|
getter_AddRefs(inetSecMgr)))) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
DWORD zone;
|
|
if (inetSecMgr->MapUrlToZone(PromiseFlatString(aURL).get(),
|
|
&zone, 0) != S_OK) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
} else {
|
|
*aZone = zone;
|
|
}
|
|
|
|
return NS_OK;
|
|
#else
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
#endif
|
|
}
|
|
|
|
// Check if a URI is likely to be web-based, by checking its URI flags.
|
|
// If in doubt (e.g. if anything fails during the check) claims things
|
|
// are from the web.
|
|
bool DownloadPlatform::IsURLPossiblyFromWeb(nsIURI* aURI)
|
|
{
|
|
nsCOMPtr<nsIIOService> ios = do_GetIOService();
|
|
nsCOMPtr<nsIURI> uri = aURI;
|
|
if (!ios) {
|
|
return true;
|
|
}
|
|
|
|
while (uri) {
|
|
// We're not using nsIIOService::ProtocolHasFlags because it doesn't
|
|
// take per-URI flags into account. We're also not using
|
|
// NS_URIChainHasFlags because we're checking for *any* of 3 flags
|
|
// to be present on *all* of the nested URIs, which it can't do.
|
|
nsAutoCString scheme;
|
|
nsresult rv = uri->GetScheme(scheme);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
nsCOMPtr<nsIProtocolHandler> ph;
|
|
rv = ios->GetProtocolHandler(scheme.get(), getter_AddRefs(ph));
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
uint32_t flags;
|
|
rv = ph->DoGetProtocolFlags(uri, &flags);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
// If not dangerous to load, not a UI resource and not a local file,
|
|
// assume this is from the web:
|
|
if (!(flags & nsIProtocolHandler::URI_DANGEROUS_TO_LOAD) &&
|
|
!(flags & nsIProtocolHandler::URI_IS_UI_RESOURCE) &&
|
|
!(flags & nsIProtocolHandler::URI_IS_LOCAL_FILE)) {
|
|
return true;
|
|
}
|
|
// Otherwise, check if the URI is nested, and if so go through
|
|
// the loop again:
|
|
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
|
|
uri = nullptr;
|
|
if (nestedURI) {
|
|
rv = nestedURI->GetInnerURI(getter_AddRefs(uri));
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|