Skip to content

Commit d2fb41d

Browse files
committed
Bug 1989609 - Create protocol handler to allow New Tabs in containers to use custom wallpapers. r=home-newtab-reviewers,necko-reviewers,mconley,kershaw,ckerschb
Differential Revision: https://phabricator.services.mozilla.com/D269466
1 parent 10e22ee commit d2fb41d

File tree

10 files changed

+496
-84
lines changed

10 files changed

+496
-84
lines changed

caps/nsScriptSecurityManager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,8 @@ nsresult nsScriptSecurityManager::CheckLoadURIFlags(
10731073
}
10741074
}
10751075
} else if (targetScheme.EqualsLiteral("moz-page-thumb") ||
1076-
targetScheme.EqualsLiteral("page-icon")) {
1076+
targetScheme.EqualsLiteral("page-icon") ||
1077+
targetScheme.EqualsLiteral("moz-newtab-wallpaper")) {
10771078
if (XRE_IsParentProcess()) {
10781079
return NS_OK;
10791080
}

netwerk/base/nsNetUtil.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
#include "mozilla/net/CookieJarSettings.h"
108108
#include "mozilla/net/MozSrcProtocolHandler.h"
109109
#include "mozilla/net/ExtensionProtocolHandler.h"
110+
#include "mozilla/net/MozNewTabWallpaperProtocolHandler.h"
110111
#include "mozilla/net/PageThumbProtocolHandler.h"
111112
#include "mozilla/net/SFVService.h"
112113
#include "nsICookieService.h"
@@ -1993,6 +1994,15 @@ nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
19931994
return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
19941995
}
19951996

1997+
if (scheme.EqualsLiteral("moz-newtab-wallpaper")) {
1998+
RefPtr<mozilla::net::MozNewTabWallpaperProtocolHandler> handler =
1999+
mozilla::net::MozNewTabWallpaperProtocolHandler::GetSingleton();
2000+
if (!handler) {
2001+
return NS_ERROR_NOT_AVAILABLE;
2002+
}
2003+
return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
2004+
}
2005+
19962006
if (scheme.EqualsLiteral("about")) {
19972007
return nsAboutProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
19982008
aURI);

netwerk/build/components.conf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,25 @@ Classes = [
434434
],
435435
},
436436
},
437+
{
438+
'cid': '{64095195-aa8a-4d17-8ec8-c470d85b609b}',
439+
'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-newtab-wallpaper'],
440+
'singleton': True,
441+
'type': 'mozilla::net::MozNewTabWallpaperProtocolHandler',
442+
'headers': ['mozilla/net/MozNewTabWallpaperProtocolHandler.h'],
443+
'constructor': 'mozilla::net::MozNewTabWallpaperProtocolHandler::GetSingleton',
444+
'protocol_config': {
445+
'scheme': 'moz-newtab-wallpaper',
446+
'flags': [
447+
'URI_STD',
448+
'URI_IS_UI_RESOURCE',
449+
'URI_IS_LOCAL_RESOURCE',
450+
'URI_NORELATIVE',
451+
'URI_NOAUTH',
452+
],
453+
'default_port': -1,
454+
},
455+
},
437456
{
438457
'cid': '{1423e739-782c-4081-b5d8-fe6fba68c0ef}',
439458
'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-safe-about'],

netwerk/ipc/NeckoParent.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "mozilla/ipc/IPCStreamUtils.h"
1414
#include "mozilla/net/ExtensionProtocolHandler.h"
1515
#include "mozilla/net/PageThumbProtocolHandler.h"
16+
#include "mozilla/net/MozNewTabWallpaperProtocolHandler.h"
1617
#include "mozilla/net/NeckoParent.h"
1718
#include "mozilla/net/HttpChannelParent.h"
1819
#include "mozilla/net/CookieServiceParent.h"
@@ -801,6 +802,52 @@ mozilla::ipc::IPCResult NeckoParent::RecvGetPageThumbStream(
801802
return IPC_OK();
802803
}
803804

805+
mozilla::ipc::IPCResult NeckoParent::RecvGetMozNewTabWallpaperStream(
806+
nsIURI* aURI, const LoadInfoArgs& aLoadInfoArgs,
807+
GetMozNewTabWallpaperStreamResolver&& aResolver) {
808+
// Only the privileged about content process is allowed to access
809+
// things over the moz-newtab-wallpaper protocol. Any other content process
810+
// that tries to send this should have been blocked via the
811+
// ScriptSecurityManager, but if somehow the process has been tricked into
812+
// sending this message, we send IPC_FAIL in order to crash that
813+
// likely-compromised content process.
814+
if (static_cast<ContentParent*>(Manager())->GetRemoteType() !=
815+
PRIVILEGEDABOUT_REMOTE_TYPE) {
816+
return IPC_FAIL(this, "Wrong process type");
817+
}
818+
819+
RefPtr<net::MozNewTabWallpaperProtocolHandler> ph(
820+
net::MozNewTabWallpaperProtocolHandler::GetSingleton());
821+
MOZ_ASSERT(ph);
822+
823+
// Ask the MozNewTabWallpaperProtocolHandler to give us a new input stream for
824+
// this URI. The request comes from a MozNewTabWallpaperProtocolHandler in the
825+
// child process, but is not guaranteed to be a valid moz-newtab-wallpaper
826+
// URI, and not guaranteed to represent a resource that the child should be
827+
// allowed to access. The MozNewTabWallpaperProtocolHandler is responsible for
828+
// validating the request.
829+
nsCOMPtr<nsIInputStream> inputStream;
830+
bool terminateSender = true;
831+
auto inputStreamPromise = ph->NewStream(aURI, &terminateSender);
832+
833+
if (terminateSender) {
834+
return IPC_FAIL(this, "Malformed moz-newtab-wallpaper request");
835+
}
836+
837+
inputStreamPromise->Then(
838+
GetMainThreadSerialEventTarget(), __func__,
839+
[aResolver](const RemoteStreamInfo& aInfo) { aResolver(Some(aInfo)); },
840+
[aResolver](nsresult aRv) {
841+
// If NewStream failed, we send back an invalid stream to the child so
842+
// it can handle the error. MozPromise rejection is reserved for channel
843+
// errors/disconnects.
844+
(void)NS_WARN_IF(NS_FAILED(aRv));
845+
aResolver(Nothing());
846+
});
847+
848+
return IPC_OK();
849+
}
850+
804851
mozilla::ipc::IPCResult NeckoParent::RecvGetPageIconStream(
805852
nsIURI* aURI, const LoadInfoArgs& aLoadInfoArgs,
806853
GetPageIconStreamResolver&& aResolver) {
@@ -853,5 +900,109 @@ mozilla::ipc::IPCResult NeckoParent::RecvGetPageIconStream(
853900
#endif
854901
}
855902

903+
/* static */
904+
RefPtr<RemoteStreamPromise> NeckoParent::CreateRemoteStreamForResolvedURI(
905+
nsIURI* aChildURI, const nsACString& aResolvedSpec,
906+
const nsACString& aDefaultMimeType) {
907+
MOZ_ASSERT(NS_IsMainThread());
908+
MOZ_ASSERT(XRE_IsParentProcess());
909+
910+
nsresult rv;
911+
912+
nsAutoCString resolvedScheme;
913+
rv = net_ExtractURLScheme(aResolvedSpec, resolvedScheme);
914+
if (NS_FAILED(rv) || !resolvedScheme.EqualsLiteral("file")) {
915+
return RemoteStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED, __func__);
916+
}
917+
918+
MOZ_ASSERT(resolvedScheme.EqualsLiteral("file"),
919+
"CreateRemoteStreamForResolvedURI requires file:// URI");
920+
921+
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
922+
if (NS_FAILED(rv)) {
923+
return RemoteStreamPromise::CreateAndReject(rv, __func__);
924+
}
925+
926+
nsCOMPtr<nsIURI> resolvedURI;
927+
rv = ioService->NewURI(aResolvedSpec, nullptr, nullptr,
928+
getter_AddRefs(resolvedURI));
929+
if (NS_FAILED(rv)) {
930+
return RemoteStreamPromise::CreateAndReject(rv, __func__);
931+
}
932+
933+
// Load local file resources for internal protocol handlers (moz-page-thumb,
934+
// moz-newtab-wallpaper). resolvedURI must be file:// scheme pointing to the
935+
// profile directory. Callers validate the original URI scheme/host and use
936+
// internal path resolution (PageThumbsStorageService, profile/wallpaper/)
937+
// before calling this method.
938+
nsCOMPtr<nsIChannel> channel;
939+
nsCOMPtr<nsIPrincipal> nullPrincipal =
940+
NullPrincipal::CreateWithoutOriginAttributes();
941+
rv = NS_NewChannel(getter_AddRefs(channel), resolvedURI, nullPrincipal,
942+
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
943+
nsIContentPolicy::TYPE_IMAGE);
944+
if (NS_FAILED(rv)) {
945+
return RemoteStreamPromise::CreateAndReject(rv, __func__);
946+
}
947+
948+
auto promiseHolder = MakeUnique<MozPromiseHolder<RemoteStreamPromise>>();
949+
RefPtr<RemoteStreamPromise> promise = promiseHolder->Ensure(__func__);
950+
951+
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1", &rv);
952+
if (NS_FAILED(rv)) {
953+
return RemoteStreamPromise::CreateAndReject(rv, __func__);
954+
}
955+
956+
nsAutoCString contentType;
957+
rv = mime->GetTypeFromURI(aChildURI, contentType);
958+
if (NS_FAILED(rv)) {
959+
if (!aDefaultMimeType.IsEmpty()) {
960+
contentType = aDefaultMimeType;
961+
} else {
962+
return RemoteStreamPromise::CreateAndReject(rv, __func__);
963+
}
964+
}
965+
966+
rv = NS_DispatchBackgroundTask(
967+
NS_NewRunnableFunction(
968+
"NeckoParent::CreateRemoteStreamForResolvedURI",
969+
[contentType, channel, holder = std::move(promiseHolder)]() {
970+
nsresult rv;
971+
972+
nsCOMPtr<nsIFileChannel> fileChannel =
973+
do_QueryInterface(channel, &rv);
974+
if (NS_FAILED(rv)) {
975+
holder->Reject(rv, __func__);
976+
return;
977+
}
978+
979+
nsCOMPtr<nsIFile> requestedFile;
980+
rv = fileChannel->GetFile(getter_AddRefs(requestedFile));
981+
if (NS_FAILED(rv)) {
982+
holder->Reject(rv, __func__);
983+
return;
984+
}
985+
986+
nsCOMPtr<nsIInputStream> inputStream;
987+
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
988+
requestedFile, PR_RDONLY, -1);
989+
if (NS_FAILED(rv)) {
990+
holder->Reject(rv, __func__);
991+
return;
992+
}
993+
994+
RemoteStreamInfo info(inputStream, contentType, -1);
995+
996+
holder->Resolve(std::move(info), __func__);
997+
}),
998+
NS_DISPATCH_EVENT_MAY_BLOCK);
999+
1000+
if (NS_FAILED(rv)) {
1001+
return RemoteStreamPromise::CreateAndReject(rv, __func__);
1002+
}
1003+
1004+
return promise;
1005+
}
1006+
8561007
} // namespace net
8571008
} // namespace mozilla

netwerk/ipc/NeckoParent.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "mozilla/BasePrincipal.h"
99
#include "mozilla/net/PNeckoParent.h"
1010
#include "mozilla/net/NeckoCommon.h"
11+
#include "mozilla/MozPromise.h"
1112
#include "nsIAuthPrompt2.h"
1213
#include "nsNetUtil.h"
1314

@@ -17,6 +18,10 @@
1718
namespace mozilla {
1819
namespace net {
1920

21+
class RemoteStreamInfo;
22+
using RemoteStreamPromise =
23+
mozilla::MozPromise<RemoteStreamInfo, nsresult, false>;
24+
2025
// Used to override channel Private Browsing status if needed.
2126
enum PBOverrideStatus {
2227
kPBOverride_Unset = 0,
@@ -55,6 +60,14 @@ class NeckoParent : public PNeckoParent {
5560
return PNeckoParent::RecvPCookieServiceConstructor(aActor);
5661
}
5762

63+
/*
64+
* Helper method to create a remote stream from a resolved file URI.
65+
* Shared by PageThumbProtocolHandler and MozNewTabWallpaperProtocolHandler.
66+
*/
67+
static RefPtr<RemoteStreamPromise> CreateRemoteStreamForResolvedURI(
68+
nsIURI* aChildURI, const nsACString& aResolvedSpec,
69+
const nsACString& aDefaultMimeType);
70+
5871
protected:
5972
virtual ~NeckoParent() = default;
6073

@@ -196,6 +209,11 @@ class NeckoParent : public PNeckoParent {
196209
nsIURI* aURI, const LoadInfoArgs& aLoadInfoArgs,
197210
GetPageIconStreamResolver&& aResolve);
198211

212+
/* New Tab wallpaper remote resource loading */
213+
mozilla::ipc::IPCResult RecvGetMozNewTabWallpaperStream(
214+
nsIURI* aURI, const LoadInfoArgs& aLoadInfoArgs,
215+
GetMozNewTabWallpaperStreamResolver&& aResolve);
216+
199217
mozilla::ipc::IPCResult RecvInitSocketProcessBridge(
200218
InitSocketProcessBridgeResolver&& aResolver);
201219
mozilla::ipc::IPCResult RecvResetSocketProcessBridge();

netwerk/ipc/PNecko.ipdl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ parent:
158158
async GetPageThumbStream(nullable nsIURI uri, LoadInfoArgs loadInfo) returns (RemoteStreamInfo? info);
159159
async GetPageIconStream(nullable nsIURI uri, LoadInfoArgs loadInfo) returns (RemoteStreamInfo? info);
160160

161+
/**
162+
* New Tab wallpaper remote resource loading
163+
*/
164+
async GetMozNewTabWallpaperStream(nullable nsIURI uri, LoadInfoArgs loadInfo) returns (RemoteStreamInfo? info);
165+
161166
child:
162167
async SpeculativeConnectRequest();
163168

0 commit comments

Comments
 (0)