|
13 | 13 | #include "mozilla/ipc/IPCStreamUtils.h" |
14 | 14 | #include "mozilla/net/ExtensionProtocolHandler.h" |
15 | 15 | #include "mozilla/net/PageThumbProtocolHandler.h" |
| 16 | +#include "mozilla/net/MozNewTabWallpaperProtocolHandler.h" |
16 | 17 | #include "mozilla/net/NeckoParent.h" |
17 | 18 | #include "mozilla/net/HttpChannelParent.h" |
18 | 19 | #include "mozilla/net/CookieServiceParent.h" |
@@ -801,6 +802,52 @@ mozilla::ipc::IPCResult NeckoParent::RecvGetPageThumbStream( |
801 | 802 | return IPC_OK(); |
802 | 803 | } |
803 | 804 |
|
| 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 | + |
804 | 851 | mozilla::ipc::IPCResult NeckoParent::RecvGetPageIconStream( |
805 | 852 | nsIURI* aURI, const LoadInfoArgs& aLoadInfoArgs, |
806 | 853 | GetPageIconStreamResolver&& aResolver) { |
@@ -853,5 +900,109 @@ mozilla::ipc::IPCResult NeckoParent::RecvGetPageIconStream( |
853 | 900 | #endif |
854 | 901 | } |
855 | 902 |
|
| 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 | + |
856 | 1007 | } // namespace net |
857 | 1008 | } // namespace mozilla |
0 commit comments