author | Haik Aftandilian <haftandilian@mozilla.com> |
Wed, 27 Mar 2019 22:49:33 +0000 | |
changeset 466483 | 7d40ca9aee44642578636744d9f44d298031ff8c |
parent 466482 | 2b0b4377cc2bf358d49240bdf0b776276c760849 |
child 466484 | 09efa187c2cdd1d49a1726f7188858a412851cc5 |
push id | 35768 |
push user | opoprus@mozilla.com |
push date | Thu, 28 Mar 2019 09:55:54 +0000 |
treeherder | mozilla-central@c045dd97faf2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bzbarsky, froydnj |
bugs | 1452278 |
milestone | 68.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/docshell/build/components.conf +++ b/docshell/build/components.conf @@ -66,18 +66,19 @@ Classes = [ }, { 'cid': '{a7f800e0-4306-11d4-98d0-001083010e9b}', 'contract_ids': [ '@mozilla.org/mime;1', '@mozilla.org/uriloader/external-helper-app-service;1', '@mozilla.org/uriloader/external-protocol-service;1', ], - 'type': 'nsOSHelperAppService', - 'headers': ['nsOSHelperAppService.h'], + 'type': 'nsExternalHelperAppService', + 'constructor': 'nsExternalHelperAppService::GetSingleton', + 'headers': ['nsExternalHelperAppService.h'], 'init_method': 'Init', 'processes': ProcessSelector.ALLOW_IN_SOCKET_PROCESS, }, { 'cid': '{397b43f3-1470-4542-8a40-c718f7753563}', 'contract_ids': ['@mozilla.org/network/childProcessChannelListener;1'], 'singleton': True, 'type': 'mozilla::dom::ChildProcessChannelListener',
--- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -1044,20 +1044,26 @@ description = [PHal::GetWakeLockInfo] description = [PHal::LockScreenOrientation] description = [PPrinting::SavePrintSettings] description = [PHandlerService::FillHandlerInfo] description = +[PHandlerService::GetMIMEInfoFromOS] +description = Lets unprivileged child processes synchronously get MIME type/handler information from the OS +[PHandlerService::ExistsForProtocolOS] +description = bug 1382323 [PHandlerService::ExistsForProtocol] -description = bug 1382323 +description = [PHandlerService::Exists] description = [PHandlerService::GetTypeFromExtension] description = +[PHandlerService::GetApplicationDescription] +description = Lets unprivileged child processes synchronously get a description of the app that handles a given protocol scheme [PLayerTransaction::ShutdownSync] description = bug 1363126 [PClientSource::WorkerSyncPing] description = Synchronous ping allowing worker thread to confirm actor is created. Necessary to avoid racing with ClientHandle actors on main thread. [PRemoteSandboxBroker::LaunchApp] description = Synchronous launch of a child process that in turn launches and sandboxes another process. Called on a dedicated thread and targets a dedicated process, so this shouldn't block anything.
--- a/netwerk/mime/nsIMIMEService.idl +++ b/netwerk/mime/nsIMIMEService.idl @@ -67,9 +67,34 @@ interface nsIMIMEService : nsISupports { /** * Given a Type/Extension combination, returns the default extension * for this type. This may be identical to the passed-in extension. * * @param aMIMEType The Type to get information on. Must not be empty. * @param aFileExt File Extension. Can be empty. */ AUTF8String getPrimaryExtension(in ACString aMIMEType, in AUTF8String aFileExt); + + /* + * Returns an nsIMIMEInfo for the provided MIME type and extension + * obtained from an OS lookup. If no handler is found for the type and + * extension, returns a generic nsIMIMEInfo object. The MIME type and + * extension can be the empty string. When the type and extension don't + * map to the same handler, the semantics/resolution are platform + * specific. See the platform implementations for details. + * + * @param aType The MIME type to get handler information for. + * @param aFileExtension The filename extension to use either alone + * or with the MIME type to get handler information + * for. UTF-8 encoded. + * @param [out] aFound Out param indicating whether a MIMEInfo could + * be found for the provided type and/or extension. + * Set to false when neither extension nor the MIME + * type are mapped to a handler. + * @return A nsIMIMEInfo object. This function must return + * a MIMEInfo object if it can allocate one. The + * only justifiable reason for not returning one is + * an out-of-memory error. + */ + nsIMIMEInfo getMIMEInfoFromOS(in ACString aType, + in ACString aFileExtension, + out boolean aFound); };
--- a/uriloader/exthandler/ContentHandlerService.cpp +++ b/uriloader/exthandler/ContentHandlerService.cpp @@ -161,16 +161,35 @@ NS_IMETHODIMP ContentHandlerService::Fil HandlerInfo info, returnedInfo; nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info); mHandlerServiceChild->SendFillHandlerInfo(info, nsCString(aOverrideType), &returnedInfo); CopyHanderInfoTonsIHandlerInfo(returnedInfo, aHandlerInfo); return NS_OK; } +NS_IMETHODIMP ContentHandlerService::GetMIMEInfoFromOS( + nsIHandlerInfo* aHandlerInfo, const nsACString& aMIMEType, + const nsACString& aExtension, bool* aFound) { + nsresult rv = NS_ERROR_FAILURE; + HandlerInfo returnedInfo; + if (!mHandlerServiceChild->SendGetMIMEInfoFromOS(nsCString(aMIMEType), + nsCString(aExtension), &rv, + &returnedInfo, aFound)) { + return NS_ERROR_FAILURE; + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + CopyHanderInfoTonsIHandlerInfo(returnedInfo, aHandlerInfo); + return NS_OK; +} + NS_IMETHODIMP ContentHandlerService::Store(nsIHandlerInfo* aHandlerInfo) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP ContentHandlerService::Exists(nsIHandlerInfo* aHandlerInfo, bool* _retval) { HandlerInfo info; nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info); @@ -178,16 +197,26 @@ NS_IMETHODIMP ContentHandlerService::Exi return NS_OK; } NS_IMETHODIMP ContentHandlerService::Remove(nsIHandlerInfo* aHandlerInfo) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP +ContentHandlerService::ExistsForProtocolOS(const nsACString& aProtocolScheme, + bool* aRetval) { + if (!mHandlerServiceChild->SendExistsForProtocolOS(nsCString(aProtocolScheme), + aRetval)) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP ContentHandlerService::ExistsForProtocol(const nsACString& aProtocolScheme, bool* aRetval) { if (!mHandlerServiceChild->SendExistsForProtocol(nsCString(aProtocolScheme), aRetval)) { return NS_ERROR_FAILURE; } return NS_OK; } @@ -203,10 +232,20 @@ NS_IMETHODIMP ContentHandlerService::Get mHandlerServiceChild->SendGetTypeFromExtension(nsCString(aFileExtension), &type); _retval.Assign(type); mExtToTypeMap.Put(nsCString(aFileExtension), new nsCString(type)); return NS_OK; } +NS_IMETHODIMP ContentHandlerService::GetApplicationDescription( + const nsACString& aProtocolScheme, nsAString& aRetVal) { + nsresult rv = NS_ERROR_FAILURE; + nsAutoCString scheme(aProtocolScheme); + nsAutoString desc; + mHandlerServiceChild->SendGetApplicationDescription(scheme, &rv, &desc); + aRetVal.Assign(desc); + return rv; +} + } // namespace dom } // namespace mozilla
--- a/uriloader/exthandler/HandlerServiceParent.cpp +++ b/uriloader/exthandler/HandlerServiceParent.cpp @@ -1,8 +1,9 @@ +#include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/Logging.h" #include "HandlerServiceParent.h" #include "nsIHandlerService.h" #include "nsIMIMEInfo.h" #include "ContentHandlerService.h" #include "nsStringEnumerator.h" #ifdef MOZ_WIDGET_GTK # include "unix/nsGNOMERegistry.h" @@ -233,37 +234,107 @@ mozilla::ipc::IPCResult HandlerServicePa nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfoData)); nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID); handlerSvc->FillHandlerInfo(info, aOverrideType); ContentHandlerService::nsIHandlerInfoToHandlerInfo(info, handlerInfoData); return IPC_OK(); } +mozilla::ipc::IPCResult HandlerServiceParent::RecvGetMIMEInfoFromOS( + const nsCString& aMIMEType, const nsCString& aExtension, nsresult* aRv, + HandlerInfo* aHandlerInfoData, bool* aFound) { + *aFound = false; + nsCOMPtr<nsIMIMEService> mimeService = + do_GetService(NS_MIMESERVICE_CONTRACTID, aRv); + if (NS_WARN_IF(NS_FAILED(*aRv))) { + return IPC_OK(); + } + + nsCOMPtr<nsIMIMEInfo> mimeInfo; + *aRv = mimeService->GetMIMEInfoFromOS(aMIMEType, aExtension, aFound, + getter_AddRefs(mimeInfo)); + if (NS_WARN_IF(NS_FAILED(*aRv))) { + return IPC_OK(); + } + + if (mimeInfo) { + ContentHandlerService::nsIHandlerInfoToHandlerInfo(mimeInfo, + aHandlerInfoData); + } + + return IPC_OK(); +} + mozilla::ipc::IPCResult HandlerServiceParent::RecvExists( const HandlerInfo& aHandlerInfo, bool* exists) { nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfo)); nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID); handlerSvc->Exists(info, exists); return IPC_OK(); } -mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocol( +mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocolOS( const nsCString& aProtocolScheme, bool* aHandlerExists) { #ifdef MOZ_WIDGET_GTK // Check the GNOME registry for a protocol handler *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme.get()); #else *aHandlerExists = false; #endif return IPC_OK(); } +/* + * Check if a handler exists for the provided protocol. Check the datastore + * first and then fallback to checking the OS for a handler. + */ +mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocol( + const nsCString& aProtocolScheme, bool* aHandlerExists) { +#if defined(XP_MACOSX) + // Check the datastore and fallback to an OS check. + // ExternalProcotolHandlerExists() does the fallback. + nsresult rv; + nsCOMPtr<nsIExternalProtocolService> protoSvc = + do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + *aHandlerExists = false; + return IPC_OK(); + } + rv = protoSvc->ExternalProtocolHandlerExists(aProtocolScheme.get(), + aHandlerExists); + + if (NS_WARN_IF(NS_FAILED(rv))) { + *aHandlerExists = false; + } +#else + MOZ_RELEASE_ASSERT(false, "No implementation on this platform."); + *aHandlerExists = false; +#endif + return IPC_OK(); +} + mozilla::ipc::IPCResult HandlerServiceParent::RecvGetTypeFromExtension( const nsCString& aFileExtension, nsCString* type) { + nsresult rv; nsCOMPtr<nsIHandlerService> handlerSvc = - do_GetService(NS_HANDLERSERVICE_CONTRACTID); - handlerSvc->GetTypeFromExtension(aFileExtension, *type); + do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_OK(); + } + + rv = handlerSvc->GetTypeFromExtension(aFileExtension, *type); + mozilla::Unused << NS_WARN_IF(NS_FAILED(rv)); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult HandlerServiceParent::RecvGetApplicationDescription( + const nsCString& aScheme, nsresult* aRv, nsString* aDescription) { + nsCOMPtr<nsIExternalProtocolService> protoSvc = + do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID); + NS_ASSERTION(protoSvc, "No Helper App Service!"); + *aRv = protoSvc->GetApplicationDescription(aScheme, *aDescription); return IPC_OK(); } void HandlerServiceParent::ActorDestroy(ActorDestroyReason aWhy) {}
--- a/uriloader/exthandler/HandlerServiceParent.h +++ b/uriloader/exthandler/HandlerServiceParent.h @@ -8,24 +8,37 @@ class nsIHandlerApp; class HandlerServiceParent final : public mozilla::dom::PHandlerServiceParent { public: HandlerServiceParent(); NS_INLINE_DECL_REFCOUNTING(HandlerServiceParent) private: virtual ~HandlerServiceParent(); - virtual void ActorDestroy(ActorDestroyReason aWhy) override; + void ActorDestroy(ActorDestroyReason aWhy) override; - virtual mozilla::ipc::IPCResult RecvFillHandlerInfo( + mozilla::ipc::IPCResult RecvFillHandlerInfo( const HandlerInfo& aHandlerInfoData, const nsCString& aOverrideType, HandlerInfo* handlerInfoData) override; - virtual mozilla::ipc::IPCResult RecvExists(const HandlerInfo& aHandlerInfo, - bool* exits) override; - virtual mozilla::ipc::IPCResult RecvGetTypeFromExtension( + mozilla::ipc::IPCResult RecvGetMIMEInfoFromOS(const nsCString& aMIMEType, + const nsCString& aExtension, + nsresult* aRv, + HandlerInfo* aHandlerInfoData, + bool* aFound) override; + + mozilla::ipc::IPCResult RecvExists(const HandlerInfo& aHandlerInfo, + bool* exists) override; + + mozilla::ipc::IPCResult RecvGetTypeFromExtension( const nsCString& aFileExtension, nsCString* type) override; - virtual mozilla::ipc::IPCResult RecvExistsForProtocol( + mozilla::ipc::IPCResult RecvExistsForProtocolOS( const nsCString& aProtocolScheme, bool* aHandlerExists) override; + + mozilla::ipc::IPCResult RecvExistsForProtocol( + const nsCString& aProtocolScheme, bool* aHandlerExists) override; + + mozilla::ipc::IPCResult RecvGetApplicationDescription( + const nsCString& aScheme, nsresult* aRv, nsString* aDescription) override; }; #endif
--- a/uriloader/exthandler/PHandlerService.ipdl +++ b/uriloader/exthandler/PHandlerService.ipdl @@ -26,20 +26,36 @@ struct HandlerInfo { sync protocol PHandlerService { manager PContent; parent: sync FillHandlerInfo(HandlerInfo aHandlerInfoData, nsCString aOverrideType) returns (HandlerInfo handlerInfoData); + + /* + * Check if an OS handler exists for the given protocol scheme. + */ + sync ExistsForProtocolOS(nsCString aProtocolScheme) + returns (bool exists); + + /* + * Check if a handler exists for the given protocol scheme. Check + * the datastore first and then fallback to an OS handler check. + */ sync ExistsForProtocol(nsCString aProtocolScheme) returns (bool exists); + sync Exists(HandlerInfo aHandlerInfo) returns (bool exists); sync GetTypeFromExtension(nsCString aFileExtension) returns (nsCString type); + sync GetMIMEInfoFromOS(nsCString aMIMEType, nsCString aExtension) + returns (nsresult rv, HandlerInfo handlerInfoData, bool found); + sync GetApplicationDescription(nsCString aScheme) + returns (nsresult rv, nsString description); async __delete__(); }; } // namespace dom } // namespace mozilla
--- a/uriloader/exthandler/android/nsOSHelperAppService.cpp +++ b/uriloader/exthandler/android/nsOSHelperAppService.cpp @@ -6,32 +6,35 @@ #include "nsOSHelperAppService.h" #include "nsMIMEInfoAndroid.h" #include "AndroidBridge.h" nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() {} nsOSHelperAppService::~nsOSHelperAppService() {} -already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS( - const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound) { +nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, + bool* aFound, + nsIMIMEInfo** aMIMEInfo) { RefPtr<nsMIMEInfoAndroid> mimeInfo; *aFound = false; if (!aMIMEType.IsEmpty()) *aFound = nsMIMEInfoAndroid::GetMimeInfoForMimeType( aMIMEType, getter_AddRefs(mimeInfo)); if (!*aFound) *aFound = nsMIMEInfoAndroid::GetMimeInfoForFileExt( aFileExt, getter_AddRefs(mimeInfo)); // Code that calls this requires an object regardless if the OS has // something for us, so we return the empty object. if (!*aFound) mimeInfo = new nsMIMEInfoAndroid(aMIMEType); - return mimeInfo.forget(); + mimeInfo.forget(aMIMEInfo); + return NS_OK; } nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme, bool* aExists) { *aExists = mozilla::AndroidBridge::Bridge()->GetHandlersForURL( NS_ConvertUTF8toUTF16(aScheme)); return NS_OK; }
--- a/uriloader/exthandler/android/nsOSHelperAppService.h +++ b/uriloader/exthandler/android/nsOSHelperAppService.h @@ -9,25 +9,26 @@ #include "nsCExternalHandlerService.h" #include "nsExternalHelperAppService.h" class nsOSHelperAppService : public nsExternalHelperAppService { public: nsOSHelperAppService(); virtual ~nsOSHelperAppService(); - virtual already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS( - const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound); + nsresult GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) override; - virtual MOZ_MUST_USE nsresult OSProtocolHandlerExists(const char* aScheme, - bool* aExists); + MOZ_MUST_USE nsresult OSProtocolHandlerExists(const char* aScheme, + bool* aExists) override; NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, - nsIHandlerInfo** _retval); + nsIHandlerInfo** _retval) override; static nsIHandlerApp* CreateAndroidHandlerApp( const nsAString& aName, const nsAString& aDescription, const nsAString& aPackageName, const nsAString& aClassName, const nsACString& aMimeType, const nsAString& aAction = EmptyString()); }; #endif /* nsOSHelperAppService_h */
--- a/uriloader/exthandler/mac/nsOSHelperAppService.h +++ b/uriloader/exthandler/mac/nsOSHelperAppService.h @@ -21,37 +21,30 @@ class nsIMimeInfo; class nsOSHelperAppService : public nsExternalHelperAppService { public: virtual ~nsOSHelperAppService(); // override nsIExternalProtocolService methods NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval) override; - // method overrides --> used to hook the mime service into internet config.... - NS_IMETHOD GetFromTypeAndExtension(const nsACString& aType, - const nsACString& aFileExt, - nsIMIMEInfo** aMIMEInfo) override; - already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound) override; + nsresult GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) override; + NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsIHandlerInfo** _retval) override; - // override so we can have a child process sandbox-friendly implementation - bool GetMIMETypeFromOSForExtension(const nsACString& aExtension, - nsACString& aMIMEType) override; - // GetFileTokenForPath must be implemented by each platform. // platformAppPath --> a platform specific path to an application that we got // out of the rdf data source. This can be a mac file // spec, a unix path or a windows path depending on the // platform // aFile --> an nsIFile representation of that platform application path. - virtual MOZ_MUST_USE nsresult GetFileTokenForPath( - const char16_t* platformAppPath, nsIFile** aFile) override; + MOZ_MUST_USE nsresult GetFileTokenForPath(const char16_t* platformAppPath, + nsIFile** aFile) override; MOZ_MUST_USE nsresult OSProtocolHandlerExists(const char* aScheme, bool* aHandlerExists) override; }; #endif // nsOSHelperAppService_h__
--- a/uriloader/exthandler/mac/nsOSHelperAppService.mm +++ b/uriloader/exthandler/mac/nsOSHelperAppService.mm @@ -53,18 +53,18 @@ using mozilla::LogLevel; - (NSArray *)extensionsForMIMEType:(NSString *)aString; @end nsOSHelperAppService::~nsOSHelperAppService() {} nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char *aProtocolScheme, bool *aHandlerExists) { // CFStringCreateWithBytes() can fail even if we're not out of memory -- - // for example if the 'bytes' parameter is something very wierd (like "ÿÿ~" - // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's + // for example if the 'bytes' parameter is something very weird (like + // "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // specified in the 'encoding' parameter. See bug 548719. CFStringRef schemeString = ::CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)aProtocolScheme, strlen(aProtocolScheme), kCFStringEncodingUTF8, false); if (schemeString) { // LSCopyDefaultHandlerForURLScheme() can fail to find the default handler // for aProtocolScheme when it's never been explicitly set (using // LSSetDefaultHandlerForURLScheme()). For example, Safari is the default @@ -192,22 +192,16 @@ nsresult nsOSHelperAppService::GetFileTo *aFile = localFile; NS_IF_ADDREF(*aFile); return NS_OK; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } -NS_IMETHODIMP nsOSHelperAppService::GetFromTypeAndExtension(const nsACString &aType, - const nsACString &aFileExt, - nsIMIMEInfo **aMIMEInfo) { - return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo); -} - // Returns the MIME types an application bundle explicitly claims to handle. // Returns NULL if aAppRef doesn't explicitly claim to handle any MIME types. // If the return value is non-NULL, the caller is responsible for freeing it. // This isn't necessarily the same as the MIME types the application bundle // is registered to handle in the Launch Services database. (For example // the Preview application is normally registered to handle the application/pdf // MIME type, even though it doesn't explicitly claim to handle *any* MIME // types in its Info.plist. This is probably because Preview does explicitly @@ -270,22 +264,21 @@ static CFArrayRef GetMIMETypesHandledByA ::CFRelease(infoDict); if (!::CFArrayGetCount(mimeTypes)) { ::CFRelease(mimeTypes); mimeTypes = NULL; } return mimeTypes; } -// aMIMEType and aFileExt might not match, If they don't we set *aFound to -// false and return a minimal nsIMIMEInfo structure. -already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString &aMIMEType, - const nsACString &aFileExt, - bool *aFound) { +nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString &aMIMEType, + const nsACString &aFileExt, bool *aFound, + nsIMIMEInfo **aMIMEInfo) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL; + MOZ_ASSERT(XRE_IsParentProcess()); *aFound = false; const nsCString &flatType = PromiseFlatCString(aMIMEType); const nsCString &flatExt = PromiseFlatCString(aFileExt); MOZ_LOG(mLog, LogLevel::Debug, ("Mac: HelperAppService lookup for type '%s' ext '%s'\n", flatType.get(), flatExt.get())); @@ -305,36 +298,36 @@ already_AddRefed<nsIMIMEInfo> nsOSHelper FSRef extAppFSRef; CFStringRef cfMIMEType = NULL; if (!aMIMEType.IsEmpty()) { typeIsOctetStream = aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM); CFURLRef appURL = NULL; // CFStringCreateWithCString() can fail even if we're not out of memory -- - // for example if the 'cStr' parameter is something very weird (like "ÿÿ~" - // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's + // for example if the 'cStr' parameter is something very weird (like + // "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // specified in the 'encoding' parameter. See bug 548719. cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(), kCFStringEncodingUTF8); if (cfMIMEType) { err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL); if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) { haveAppForType = true; MOZ_LOG(mLog, LogLevel::Debug, ("LSCopyApplicationForMIMEType found a default application\n")); } if (appURL) { ::CFRelease(appURL); } } } if (!aFileExt.IsEmpty()) { // CFStringCreateWithCString() can fail even if we're not out of memory -- - // for example if the 'cStr' parameter is something very wierd (like "ÿÿ~" - // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's + // for example if the 'cStr' parameter is something very weird (like + // "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // specified in the 'encoding' parameter. See bug 548719. CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8); if (cfExt) { err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt, kLSRolesAll, &extAppFSRef, nullptr); if (err == noErr) { haveAppForExt = true; MOZ_LOG(mLog, LogLevel::Debug, ("LSGetApplicationForInfo found a default application\n")); @@ -440,20 +433,21 @@ already_AddRefed<nsIMIMEInfo> nsOSHelper // Otherwise set the MIME type to a reasonable fallback. mimeInfoMac->SetMIMEType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM)); } } if (typeAppIsDefault || extAppIsDefault) { if (haveAppForExt) mimeInfoMac->AppendExtension(aFileExt); - nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); - if (!app) { + nsresult rv; + nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) { [localPool release]; - return nullptr; + return rv; } CFStringRef cfAppName = NULL; if (typeAppIsDefault) { app->InitWithFSRef(&typeAppFSRef); ::LSCopyItemAttribute((const FSRef *)&typeAppFSRef, kLSRolesAll, kLSItemDisplayName, (CFTypeRef *)&cfAppName); } else { @@ -511,19 +505,20 @@ already_AddRefed<nsIMIMEInfo> nsOSHelper } ::CFRelease(cfType); } } MOZ_LOG(mLog, LogLevel::Debug, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound)); [localPool release]; - return mimeInfoMac.forget(); + mimeInfoMac.forget(aMIMEInfo); + return NS_OK; - NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL; + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } NS_IMETHODIMP nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme, bool *found, nsIHandlerInfo **_retval) { NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!"); nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(), found); @@ -545,36 +540,8 @@ nsOSHelperAppService::GetProtocolHandler nsAutoString desc; rv = GetApplicationDescription(aScheme, desc); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetApplicationDescription failed"); handlerInfo->SetDefaultDescription(desc); } return NS_OK; } - -/* - * Override GetMIMETypeFromOSForExtension() so that we can proxy requests for - * the MIME type to the parent when we're executing in the child process. If - * we're in the parent process, query the OS directly. - */ -bool nsOSHelperAppService::GetMIMETypeFromOSForExtension(const nsACString &aExtension, - nsACString &aMIMEType) { - if (XRE_IsParentProcess()) { - return nsExternalHelperAppService::GetMIMETypeFromOSForExtension(aExtension, aMIMEType); - } - - nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID); - if (NS_WARN_IF(!handlerSvc)) { - return false; - } - - nsresult rv = handlerSvc->GetTypeFromExtension(aExtension, aMIMEType); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - if (aMIMEType.IsEmpty()) { - return false; - } - - return true; -}
--- a/uriloader/exthandler/moz.build +++ b/uriloader/exthandler/moz.build @@ -31,16 +31,18 @@ else: EXPORTS += [ osdir + '/nsOSHelperAppService.h' ] EXPORTS += [ 'ContentHandlerService.h', 'nsExternalHelperAppService.h', + 'nsMIMEInfoChild.h', + 'nsOSHelperAppServiceChild.h', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': EXPORTS += [ '%s/%s' % (osdir, f) for f in [ 'nsExternalURLHandlerService.h', ]] EXPORTS += [ @@ -56,16 +58,17 @@ UNIFIED_SOURCES += [ 'ContentHandlerService.cpp', 'ExternalHelperAppChild.cpp', 'ExternalHelperAppParent.cpp', 'HandlerServiceParent.cpp', 'nsExternalHelperAppService.cpp', 'nsExternalProtocolHandler.cpp', 'nsLocalHandlerApp.cpp', 'nsMIMEInfoImpl.cpp', + 'nsOSHelperAppServiceChild.cpp', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': UNIFIED_SOURCES += [ 'mac/nsLocalHandlerAppMac.mm', 'mac/nsMIMEInfoMac.mm', 'mac/nsOSHelperAppService.mm', ]
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -38,16 +38,18 @@ #include "nsReadableUtils.h" #include "nsIRequest.h" #include "nsDirectoryServiceDefs.h" #include "nsIInterfaceRequestor.h" #include "nsThreadUtils.h" #include "nsAutoPtr.h" #include "nsIMutableArray.h" #include "nsIRedirectHistoryEntry.h" +#include "nsOSHelperAppService.h" +#include "nsOSHelperAppServiceChild.h" // used to access our datastore of user-configured helper applications #include "nsIHandlerService.h" #include "nsIMIMEInfo.h" #include "nsIRefreshURI.h" // XXX needed to redirect according to Refresh: URI #include "nsIDocumentLoader.h" // XXX needed to get orig. channel and assoc. refresh uri #include "nsIHelperAppLauncherDialog.h" #include "nsIContentDispatchChooser.h" @@ -100,16 +102,17 @@ #ifdef XP_WIN # include "nsWindowsHelpers.h" #endif #ifdef MOZ_WIDGET_ANDROID # include "FennecJNIWrappers.h" #endif +#include "mozilla/ClearOnShutdown.h" #include "mozilla/Preferences.h" #include "mozilla/ipc/URIUtils.h" using namespace mozilla; using namespace mozilla::ipc; // Download Folder location constants #define NS_PREF_DOWNLOAD_DIR "browser.download.dir" @@ -568,16 +571,42 @@ static const nsExtraMimeTypeEntry extraM */ static const nsDefaultMimeTypeEntry nonDecodableExtensions[] = { {APPLICATION_GZIP, "gz"}, {APPLICATION_GZIP, "tgz"}, {APPLICATION_ZIP, "zip"}, {APPLICATION_COMPRESS, "z"}, {APPLICATION_GZIP, "svgz"}}; +static StaticRefPtr<nsExternalHelperAppService> sExtHelperAppSvcSingleton; + +/** + * On Mac child processes, return an nsOSHelperAppServiceChild for remoting + * OS calls to the parent process. On all other platforms use + * nsOSHelperAppService. + */ +/* static */ +already_AddRefed<nsExternalHelperAppService> +nsExternalHelperAppService::GetSingleton() { + if (!sExtHelperAppSvcSingleton) { +#ifdef XP_MACOSX + if (XRE_IsParentProcess()) { + sExtHelperAppSvcSingleton = new nsOSHelperAppService(); + } else { + sExtHelperAppSvcSingleton = new nsOSHelperAppServiceChild(); + } +#else + sExtHelperAppSvcSingleton = new nsOSHelperAppService(); +#endif /* XP_MACOSX */ + ClearOnShutdown(&sExtHelperAppSvcSingleton); + } + + return do_AddRef(sExtHelperAppSvcSingleton); +} + NS_IMPL_ISUPPORTS(nsExternalHelperAppService, nsIExternalHelperAppService, nsPIExternalAppLauncher, nsIExternalProtocolService, nsIMIMEService, nsIObserver, nsISupportsWeakReference) nsExternalHelperAppService::nsExternalHelperAppService() {} nsresult nsExternalHelperAppService::Init() { // Add an observer for profile change nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); @@ -2478,25 +2507,28 @@ NS_IMETHODIMP nsExternalHelperAppService if (NS_FAILED(rv)) return NS_ERROR_NOT_AVAILABLE; } // We promise to only send lower case mime types to the OS ToLowerCase(typeToUse); // (1) Ask the OS for a mime info bool found; - *_retval = GetMIMEInfoFromOS(typeToUse, aFileExt, &found).take(); + nsresult rv = GetMIMEInfoFromOS(typeToUse, aFileExt, &found, _retval); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + LOG(("OS gave back 0x%p - found: %i\n", *_retval, found)); // If we got no mimeinfo, something went wrong. Probably lack of memory. if (!*_retval) return NS_ERROR_OUT_OF_MEMORY; // (2) Now, let's see if we can find something in our datastore // This will not overwrite the OS information that interests us // (i.e. default application, default app. description) - nsresult rv; nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID); if (handlerSvc) { bool hasHandler = false; (void)handlerSvc->Exists(*_retval, &hasHandler); if (hasHandler) { rv = handlerSvc->FillHandlerInfo(*_retval, EmptyCString()); LOG(("Data source: Via type: retval 0x%08" PRIx32 "\n", @@ -2791,12 +2823,22 @@ bool nsExternalHelperAppService::GetType } return false; } bool nsExternalHelperAppService::GetMIMETypeFromOSForExtension( const nsACString& aExtension, nsACString& aMIMEType) { bool found = false; - nsCOMPtr<nsIMIMEInfo> mimeInfo = - GetMIMEInfoFromOS(EmptyCString(), aExtension, &found); - return found && mimeInfo && NS_SUCCEEDED(mimeInfo->GetMIMEType(aMIMEType)); + nsCOMPtr<nsIMIMEInfo> mimeInfo; + nsresult rv = GetMIMEInfoFromOS(EmptyCString(), aExtension, &found, + getter_AddRefs(mimeInfo)); + return NS_SUCCEEDED(rv) && found && mimeInfo && + NS_SUCCEEDED(mimeInfo->GetMIMEType(aMIMEType)); } + +nsresult nsExternalHelperAppService::GetMIMEInfoFromOS( + const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) { + *aMIMEInfo = nullptr; + *aFound = false; + return NS_ERROR_NOT_IMPLEMENTED; +}
--- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -63,63 +63,45 @@ class nsExternalHelperAppService : publi /** * Initializes internal state. Will be called automatically when * this service is first instantiated. */ MOZ_MUST_USE nsresult Init(); /** - * Given a mimetype and an extension, looks up a mime info from the OS. - * The mime type is given preference. This function follows the same rules - * as nsIMIMEService::GetFromTypeAndExtension. - * This is supposed to be overridden by the platform-specific - * nsOSHelperAppService! - * @param aFileExt The file extension; may be empty. UTF-8 encoded. - * @param [out] aFound - * Should be set to true if the os has a mapping, to - * false otherwise. Must not be null. - * @return A MIMEInfo. This function must return a MIMEInfo object if it - * can allocate one. The only justifiable reason for not - * returning one is an out-of-memory error. - * If null, the value of aFound is unspecified. - */ - virtual already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS( - const nsACString& aMIMEType, const nsACString& aFileExt, - bool* aFound) = 0; - - /** * Given a string identifying an application, create an nsIFile representing * it. This function should look in $PATH for the application. * The base class implementation will first try to interpret platformAppPath * as an absolute path, and if that fails it will look for a file next to the * mozilla executable. Subclasses can override this method if they want a * different behaviour. * @param platformAppPath A platform specific path to an application that we * got out of the rdf data source. This can be a mac * file spec, a unix path or a windows path depending * on the platform * @param aFile [out] An nsIFile representation of that platform * application path. */ virtual nsresult GetFileTokenForPath(const char16_t* platformAppPath, nsIFile** aFile); - virtual nsresult OSProtocolHandlerExists(const char* aScheme, - bool* aExists) = 0; + NS_IMETHOD OSProtocolHandlerExists(const char* aScheme, bool* aExists) = 0; /** * Given an extension, get a MIME type string. If not overridden by * the OS-specific nsOSHelperAppService, will call into GetMIMEInfoFromOS * with an empty mimetype. * @return true if we successfully found a mimetype. */ virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension, nsACString& aMIMEType); + static already_AddRefed<nsExternalHelperAppService> GetSingleton(); + protected: virtual ~nsExternalHelperAppService(); /** * Searches the "extra" array of MIMEInfo objects for an object * with a specific type. If found, it will modify the passed-in * MIMEInfo. Otherwise, it will return an error and the MIMEInfo * will be untouched.
--- a/uriloader/exthandler/nsIHandlerService.idl +++ b/uriloader/exthandler/nsIHandlerService.idl @@ -124,10 +124,39 @@ interface nsIHandlerService : nsISupport /** * Whether or not there is a handler known to the OS for the * specified protocol type. * * @param aProtocolScheme scheme to check for support * * @returns whether or not a handler exists */ + boolean existsForProtocolOS(in ACString aProtocolScheme); + + /** + * Whether or not there is a handler in the datastore or OS for + * the specified protocol type. If there is no handler in the datastore, + * falls back to a check for an OS handler. + * + * @param aProtocolScheme scheme to check for support + * + * @returns whether or not a handler exists + */ boolean existsForProtocol(in ACString aProtocolScheme); + + /* + * Fill in a handler info object using information from the OS, taking into + * account the MIME type and file extension. When the OS handler + * for the MIME type and extension match, |aFound| is returned as true. If + * either the MIME type or extension is the empty string and a handler is + * found, |aFound| is returned as true. + */ + void getMIMEInfoFromOS(in nsIHandlerInfo aHandlerInfo, + in ACString aMIMEType, + in ACString aExtension, + out bool aFound); + + /* + * Get a description for the application responsible for handling + * the provided protocol. + */ + AString getApplicationDescription(in ACString aProtocolScheme); };
new file mode 100644 --- /dev/null +++ b/uriloader/exthandler/nsMIMEInfoChild.h @@ -0,0 +1,49 @@ +/* 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/. */ + +#ifndef nsMIMEInfoChild_h +#define nsMIMEInfoChild_h + +#include "nsMIMEInfoImpl.h" + +/* + * A platform-generic nsMIMEInfo implementation to be used in child process + * generic code that needs a MIMEInfo with limited functionality. + */ +class nsChildProcessMIMEInfo : public nsMIMEInfoImpl { + public: + explicit nsChildProcessMIMEInfo(const char* aMIMEType = "") + : nsMIMEInfoImpl(aMIMEType) {} + + explicit nsChildProcessMIMEInfo(const nsACString& aMIMEType) + : nsMIMEInfoImpl(aMIMEType) {} + + nsChildProcessMIMEInfo(const nsACString& aType, HandlerClass aClass) + : nsMIMEInfoImpl(aType, aClass) {} + + NS_IMETHOD LaunchWithFile(nsIFile* aFile) override { + return NS_ERROR_NOT_IMPLEMENTED; + }; + + protected: + virtual MOZ_MUST_USE nsresult LoadUriInternal(nsIURI* aURI) override { + return NS_ERROR_NOT_IMPLEMENTED; + }; + +#ifdef DEBUG + virtual MOZ_MUST_USE nsresult LaunchDefaultWithFile(nsIFile* aFile) override { + return NS_ERROR_UNEXPECTED; + } +#endif + static MOZ_MUST_USE nsresult OpenApplicationWithURI(nsIFile* aApplication, + const nsCString& aURI) { + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD GetDefaultDescription(nsAString& aDefaultDescription) override { + return NS_ERROR_NOT_IMPLEMENTED; + }; +}; + +#endif
new file mode 100644 --- /dev/null +++ b/uriloader/exthandler/nsOSHelperAppServiceChild.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 <sys/types.h> +#include <sys/stat.h> +#include "mozilla/Logging.h" +#include "mozilla/net/NeckoCommon.h" +#include "nsOSHelperAppServiceChild.h" +#include "nsMIMEInfoChild.h" +#include "nsISupports.h" +#include "nsString.h" +#include "nsTArray.h" +#include "nsIURL.h" +#include "nsIFile.h" +#include "nsIHandlerService.h" +#include "nsMimeTypes.h" +#include "nsMIMEInfoImpl.h" +#include "nsIStringBundle.h" +#include "nsIPromptService.h" +#include "nsMemory.h" +#include "nsCRT.h" +#include "nsEmbedCID.h" + +#undef LOG +#define LOG(args) \ + MOZ_LOG(nsExternalHelperAppService::mLog, mozilla::LogLevel::Info, args) +#undef LOG_ERR +#define LOG_ERR(args) \ + MOZ_LOG(nsExternalHelperAppService::mLog, mozilla::LogLevel::Error, args) +#undef LOG_ENABLED +#define LOG_ENABLED() \ + MOZ_LOG_TEST(nsExternalHelperAppService::mLog, mozilla::LogLevel::Info) + +nsresult nsOSHelperAppServiceChild::ExternalProtocolHandlerExists( + const char* aProtocolScheme, bool* aHandlerExists) { + nsresult rv; + nsCOMPtr<nsIHandlerService> handlerSvc = + do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + LOG_ERR(("nsOSHelperAppServiceChild error: no handler service")); + return rv; + } + + nsAutoCString scheme(aProtocolScheme); + *aHandlerExists = false; + rv = handlerSvc->ExistsForProtocol(scheme, aHandlerExists); + LOG( + ("nsOSHelperAppServiceChild::OSProtocolHandlerExists(): " + "protocol: %s, result: %" PRId32, + aProtocolScheme, static_cast<uint32_t>(rv))); + mozilla::Unused << NS_WARN_IF(NS_FAILED(rv)); + return rv; +} + +nsresult nsOSHelperAppServiceChild::OSProtocolHandlerExists(const char* aScheme, + bool* aExists) { + // Use ExternalProtocolHandlerExists() which includes the + // OS-level check and remotes the call to the parent process. + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsOSHelperAppServiceChild::GetApplicationDescription(const nsACString& aScheme, + nsAString& aRetVal) { + nsresult rv; + nsCOMPtr<nsIHandlerService> handlerSvc = + do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + LOG_ERR(("nsOSHelperAppServiceChild error: no handler service")); + return rv; + } + + rv = handlerSvc->GetApplicationDescription(aScheme, aRetVal); + LOG( + ("nsOSHelperAppServiceChild::GetApplicationDescription(): " + "scheme: %s, result: %" PRId32 ", description: %s", + PromiseFlatCString(aScheme).get(), static_cast<uint32_t>(rv), + NS_ConvertUTF16toUTF8(aRetVal).get())); + mozilla::Unused << NS_WARN_IF(NS_FAILED(rv)); + return rv; +} + +NS_IMETHODIMP +nsOSHelperAppServiceChild::GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, + bool* aFound, + nsIMIMEInfo** aMIMEInfo) { + RefPtr<nsChildProcessMIMEInfo> mimeInfo = + new nsChildProcessMIMEInfo(aMIMEType); + + nsCOMPtr<nsIHandlerService> handlerSvc = + do_GetService(NS_HANDLERSERVICE_CONTRACTID); + if (handlerSvc) { + nsresult rv = + handlerSvc->GetMIMEInfoFromOS(mimeInfo, aMIMEType, aFileExt, aFound); + LOG( + ("nsOSHelperAppServiceChild::GetMIMEInfoFromOS(): " + "MIME type: %s, extension: %s, result: %" PRId32, + PromiseFlatCString(aMIMEType).get(), + PromiseFlatCString(aFileExt).get(), static_cast<uint32_t>(rv))); + mozilla::Unused << NS_WARN_IF(NS_FAILED(rv)); + if (NS_FAILED(rv)) { + return rv; + } + } else { + LOG_ERR(("nsOSHelperAppServiceChild error: no handler service")); + *aFound = false; + } + + mimeInfo.forget(aMIMEInfo); + return NS_OK; +} + +NS_IMETHODIMP +nsOSHelperAppServiceChild::GetProtocolHandlerInfoFromOS( + const nsACString& aScheme, bool* aFound, nsIHandlerInfo** aRetVal) { + MOZ_ASSERT(!aScheme.IsEmpty(), "No scheme was specified!"); + + nsresult rv = + OSProtocolHandlerExists(PromiseFlatCString(aScheme).get(), aFound); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsChildProcessMIMEInfo* handlerInfo = + new nsChildProcessMIMEInfo(aScheme, nsMIMEInfoBase::eProtocolInfo); + NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY); + NS_ADDREF(*aRetVal = handlerInfo); + + if (!*aFound) { + // Code that calls this requires an object no matter whether the OS has + // something for us, so we return the empty object. + return NS_OK; + } + + nsAutoString description; + rv = GetApplicationDescription(aScheme, description); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetApplicationDescription failed"); + handlerInfo->SetDefaultDescription(description); + return NS_OK; +} + +nsresult nsOSHelperAppServiceChild::GetFileTokenForPath( + const char16_t* platformAppPath, nsIFile** aFile) { + return NS_ERROR_NOT_IMPLEMENTED; +}
new file mode 100644 --- /dev/null +++ b/uriloader/exthandler/nsOSHelperAppServiceChild.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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/. */ + +#ifndef nsOSHelperAppServiceChild_h__ +#define nsOSHelperAppServiceChild_h__ + +#include "nsExternalHelperAppService.h" + +class nsIMIMEInfo; + +/* + * Provides a generic implementation of the nsExternalHelperAppService + * platform-specific methods by remoting calls to the parent process. + * Only provides implementations for the methods needed in unprivileged + * child processes. + */ +class nsOSHelperAppServiceChild : public nsExternalHelperAppService { + public: + nsOSHelperAppServiceChild() : nsExternalHelperAppService(){}; + virtual ~nsOSHelperAppServiceChild() = default; + + NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme, + bool* found, + nsIHandlerInfo** _retval) override; + + nsresult GetFileTokenForPath(const char16_t* platformAppPath, + nsIFile** aFile) override; + + NS_IMETHOD ExternalProtocolHandlerExists(const char* aProtocolScheme, + bool* aHandlerExists) override; + + NS_IMETHOD OSProtocolHandlerExists(const char* aScheme, + bool* aExists) override; + + NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, + nsAString& aRetVal) override; + + NS_IMETHOD GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) override; +}; + +#endif // nsOSHelperAppServiceChild_h__
--- a/uriloader/exthandler/uikit/nsOSHelperAppService.h +++ b/uriloader/exthandler/uikit/nsOSHelperAppService.h @@ -24,28 +24,29 @@ class nsOSHelperAppService final : publi // override nsIExternalProtocolService methods NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval); // method overrides --> used to hook the mime service into internet config.... NS_IMETHOD GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo** aMIMEInfo); - already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound); + NS_IMETHOD GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) override; NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsIHandlerInfo** _retval); // GetFileTokenForPath must be implemented by each platform. // platformAppPath --> a platform specific path to an application that we got // out of the rdf data source. This can be a mac file // spec, a unix path or a windows path depending on the // platform // aFile --> an nsIFile representation of that platform application path. virtual nsresult GetFileTokenForPath(const char16_t* platformAppPath, nsIFile** aFile); - nsresult OSProtocolHandlerExists(const char* aScheme, bool* aHandlerExists); + nsresult OSProtocolHandlerExists(const char* aScheme, + bool* aHandlerExists) override; }; #endif // nsOSHelperAppService_h__
--- a/uriloader/exthandler/uikit/nsOSHelperAppService.mm +++ b/uriloader/exthandler/uikit/nsOSHelperAppService.mm @@ -27,21 +27,22 @@ nsresult nsOSHelperAppService::GetFileTo } NS_IMETHODIMP nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo** aMIMEInfo) { return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo); } -already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound) { +NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) { + *aMIMEInfo = nullptr; *aFound = false; - return nullptr; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, +nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const char* aScheme, bool* found, nsIHandlerInfo** _retval) { *found = false; return NS_OK; }
--- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp +++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp @@ -1034,18 +1034,18 @@ nsresult nsOSHelperAppService::OSProtoco #else *aHandlerExists = false; #endif } else { *aHandlerExists = false; nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && handlerSvc) { - rv = handlerSvc->ExistsForProtocol(nsCString(aProtocolScheme), - aHandlerExists); + rv = handlerSvc->ExistsForProtocolOS(nsCString(aProtocolScheme), + aHandlerExists); } } return rv; } NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription( const nsACString& aScheme, nsAString& _retval) { @@ -1319,62 +1319,70 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel mimeInfo->SetDefaultDescription(handler); } else { mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk); } return mimeInfo.forget(); } -already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS( - const nsACString& aType, const nsACString& aFileExt, bool* aFound) { +nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aType, + const nsACString& aFileExt, + bool* aFound, + nsIMIMEInfo** aMIMEInfo) { *aFound = true; RefPtr<nsMIMEInfoBase> retval; // Fallback to lookup by extension when generic 'application/octet-stream' // content type is received. if (!aType.EqualsLiteral(APPLICATION_OCTET_STREAM)) { retval = GetFromType(PromiseFlatCString(aType)); } bool hasDefault = false; if (retval) retval->GetHasDefaultHandler(&hasDefault); if (!retval || !hasDefault) { RefPtr<nsMIMEInfoBase> miByExt = GetFromExtension(PromiseFlatCString(aFileExt)); // If we had no extension match, but a type match, use that - if (!miByExt && retval) return retval.forget(); + if (!miByExt && retval) { + retval.forget(aMIMEInfo); + return NS_OK; + } // If we had an extension match but no type match, set the mimetype and use // it if (!retval && miByExt) { if (!aType.IsEmpty()) miByExt->SetMIMEType(aType); miByExt.swap(retval); - return retval.forget(); + retval.forget(aMIMEInfo); + return NS_OK; } // If we got nothing, make a new mimeinfo if (!retval) { *aFound = false; retval = new nsMIMEInfoUnix(aType); if (retval) { if (!aFileExt.IsEmpty()) retval->AppendExtension(aFileExt); } - return retval.forget(); + retval.forget(aMIMEInfo); + return NS_OK; } // Copy the attributes of retval (mimeinfo from type) onto miByExt, to // return it // but reset to just collected mDefaultAppDescription (from ext) nsAutoString byExtDefault; miByExt->GetDefaultDescription(byExtDefault); retval->SetDefaultDescription(byExtDefault); retval->CopyBasicDataTo(miByExt); miByExt.swap(retval); } - return retval.forget(); + retval.forget(aMIMEInfo); + return NS_OK; } NS_IMETHODIMP nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsIHandlerInfo** _retval) { NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
--- a/uriloader/exthandler/unix/nsOSHelperAppService.h +++ b/uriloader/exthandler/unix/nsOSHelperAppService.h @@ -19,19 +19,19 @@ class nsILineInputStream; class nsMIMEInfoBase; class nsOSHelperAppService : public nsExternalHelperAppService { public: virtual ~nsOSHelperAppService(); // method overrides for mime.types and mime.info look up steps - already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMimeType, - const nsACString& aFileExt, - bool* aFound) override; + NS_IMETHOD GetMIMEInfoFromOS(const nsACString& aMimeType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) override; NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsIHandlerInfo** _retval) override; // override nsIExternalProtocolService methods nsresult OSProtocolHandlerExists(const char* aProtocolScheme, bool* aHandlerExists) override; NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
--- a/uriloader/exthandler/win/nsOSHelperAppService.cpp +++ b/uriloader/exthandler/win/nsOSHelperAppService.cpp @@ -371,18 +371,20 @@ already_AddRefed<nsMIMEInfoWin> nsOSHelp mimeInfo->SetDefaultApplicationHandler(defaultApplication); // Grab the general description GetMIMEInfoFromRegistry(appInfo, mimeInfo); return mimeInfo.forget(); } -already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS( - const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound) { +NS_IMETHODIMP +nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, + bool* aFound, nsIMIMEInfo** aMIMEInfo) { *aFound = true; const nsCString& flatType = PromiseFlatCString(aMIMEType); const nsCString& flatExt = PromiseFlatCString(aFileExt); nsAutoString fileExtension; /* XXX The Equals is a gross hack to wallpaper over the most common Win32 * extension issues caused by the fix for bug 116938. See bug @@ -425,38 +427,44 @@ already_AddRefed<nsIMIMEInfo> nsOSHelper mi->ExtensionExists(aFileExt, &extExist); if (!extExist) mi->AppendExtension(aFileExt); } } if (!mi || !hasDefault) { RefPtr<nsMIMEInfoWin> miByExt = GetByExtension(NS_ConvertUTF8toUTF16(aFileExt), flatType.get()); LOG(("Ext. lookup for '%s' found 0x%p\n", flatExt.get(), miByExt.get())); - if (!miByExt && mi) return mi.forget(); + if (!miByExt && mi) { + mi.forget(aMIMEInfo); + return NS_OK; + } if (miByExt && !mi) { - return miByExt.forget(); + miByExt.forget(aMIMEInfo); + return NS_OK; } if (!miByExt && !mi) { *aFound = false; mi = new nsMIMEInfoWin(flatType); if (!aFileExt.IsEmpty()) { mi->AppendExtension(aFileExt); } - return mi.forget(); + mi.forget(aMIMEInfo); + return NS_OK; } // if we get here, mi has no default app. copy from extension lookup. nsCOMPtr<nsIFile> defaultApp; nsAutoString desc; miByExt->GetDefaultDescription(desc); mi->SetDefaultDescription(desc); } - return mi.forget(); + mi.forget(aMIMEInfo); + return NS_OK; } NS_IMETHODIMP nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsIHandlerInfo** _retval) { NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
--- a/uriloader/exthandler/win/nsOSHelperAppService.h +++ b/uriloader/exthandler/win/nsOSHelperAppService.h @@ -26,26 +26,26 @@ class nsMIMEInfoWin; class nsIMIMEInfo; class nsOSHelperAppService : public nsExternalHelperAppService { public: nsOSHelperAppService(); virtual ~nsOSHelperAppService(); // override nsIExternalProtocolService methods - nsresult OSProtocolHandlerExists(const char* aProtocolScheme, - bool* aHandlerExists); + NS_IMETHOD OSProtocolHandlerExists(const char* aProtocolScheme, + bool* aHandlerExists) override; nsresult LoadUriInternal(nsIURI* aURL); NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval) override; // method overrides for windows registry look up steps.... - already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound); + NS_IMETHOD GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, bool* aFound, + nsIMIMEInfo** aMIMEInfo) override; NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsIHandlerInfo** _retval); virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension, nsACString& aMIMEType) override; /** Get the string value of a registry value and store it in result. * @return true on success, false on failure