MozNewTabWallpaperProtocolHandler.cpp (6131B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "MozNewTabWallpaperProtocolHandler.h" 8 9 #include "mozilla/ClearOnShutdown.h" 10 #include "mozilla/net/NeckoParent.h" 11 #include "nsContentUtils.h" 12 #include "nsIFile.h" 13 #include "nsIFileChannel.h" 14 #include "nsIFileURL.h" 15 #include "nsIMIMEService.h" 16 #include "nsDirectoryServiceUtils.h" 17 #include "nsAppDirectoryServiceDefs.h" 18 #include "nsNetUtil.h" 19 #include "nsURLHelper.h" 20 #include "prio.h" 21 #include "SimpleChannel.h" 22 23 #define NEWTAB_WALLPAPER_SCHEME "moz-newtab-wallpaper" 24 25 namespace mozilla { 26 namespace net { 27 28 StaticRefPtr<MozNewTabWallpaperProtocolHandler> 29 MozNewTabWallpaperProtocolHandler::sSingleton; 30 31 NS_IMPL_QUERY_INTERFACE(MozNewTabWallpaperProtocolHandler, 32 nsISubstitutingProtocolHandler, nsIProtocolHandler, 33 nsISupportsWeakReference) 34 NS_IMPL_ADDREF_INHERITED(MozNewTabWallpaperProtocolHandler, 35 SubstitutingProtocolHandler) 36 NS_IMPL_RELEASE_INHERITED(MozNewTabWallpaperProtocolHandler, 37 SubstitutingProtocolHandler) 38 39 already_AddRefed<MozNewTabWallpaperProtocolHandler> 40 MozNewTabWallpaperProtocolHandler::GetSingleton() { 41 if (!sSingleton) { 42 sSingleton = new MozNewTabWallpaperProtocolHandler(); 43 ClearOnShutdown(&sSingleton); 44 } 45 46 return do_AddRef(sSingleton); 47 } 48 49 // A moz-newtab-wallpaper URI is only loadable by chrome pages in the parent 50 // process, or privileged content running in the privileged about content 51 // process. 52 MozNewTabWallpaperProtocolHandler::MozNewTabWallpaperProtocolHandler() 53 : SubstitutingProtocolHandler(NEWTAB_WALLPAPER_SCHEME) {} 54 55 RefPtr<RemoteStreamPromise> MozNewTabWallpaperProtocolHandler::NewStream( 56 nsIURI* aChildURI, bool* aTerminateSender) { 57 MOZ_ASSERT(!IsNeckoChild()); 58 MOZ_ASSERT(NS_IsMainThread()); 59 60 if (!aChildURI || !aTerminateSender) { 61 return RemoteStreamPromise::CreateAndReject(NS_ERROR_INVALID_ARG, __func__); 62 } 63 64 *aTerminateSender = true; 65 nsresult rv; 66 67 bool isWallpaperScheme = false; 68 if (NS_FAILED( 69 aChildURI->SchemeIs(NEWTAB_WALLPAPER_SCHEME, &isWallpaperScheme)) || 70 !isWallpaperScheme) { 71 return RemoteStreamPromise::CreateAndReject(NS_ERROR_UNKNOWN_PROTOCOL, 72 __func__); 73 } 74 75 nsAutoCString host; 76 if (NS_FAILED(aChildURI->GetAsciiHost(host)) || host.IsEmpty()) { 77 return RemoteStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED, __func__); 78 } 79 80 *aTerminateSender = false; 81 82 nsAutoCString resolvedSpec; 83 rv = ResolveURI(aChildURI, resolvedSpec); 84 if (NS_FAILED(rv)) { 85 return RemoteStreamPromise::CreateAndReject(rv, __func__); 86 } 87 88 return mozilla::net::NeckoParent::CreateRemoteStreamForResolvedURI( 89 aChildURI, resolvedSpec, "image/jpeg"_ns); 90 } 91 92 bool MozNewTabWallpaperProtocolHandler::ResolveSpecialCases( 93 const nsACString& aHost, const nsACString& aPath, 94 const nsACString& aPathname, nsACString& aResult) { 95 if (aHost.IsEmpty()) { 96 return false; 97 } 98 99 if (IsNeckoChild()) { 100 // Child process: return placeholder file:// URI for 101 // SubstitutingProtocolHandler. SubstituteChannel will replace with a remote 102 // channel that proxies the load to the parent process. 103 aResult.Assign("file://"); 104 aResult.Append(aHost); 105 return true; 106 } else { 107 // Parent process: resolve to profile/wallpaper/{host} directory. 108 nsCOMPtr<nsIFile> file; 109 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, 110 getter_AddRefs(file)); 111 if (NS_FAILED(rv)) { 112 return false; 113 } 114 115 rv = file->AppendNative("wallpaper"_ns); 116 if (NS_FAILED(rv)) { 117 return false; 118 } 119 120 rv = file->AppendNative(nsCString(aHost)); 121 if (NS_FAILED(rv)) { 122 return false; 123 } 124 125 nsCOMPtr<nsIURI> uri; 126 rv = NS_NewFileURI(getter_AddRefs(uri), file); 127 if (NS_FAILED(rv)) { 128 return false; 129 } 130 131 return NS_SUCCEEDED(uri->GetSpec(aResult)); 132 } 133 } 134 135 nsresult MozNewTabWallpaperProtocolHandler::SubstituteChannel( 136 nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIChannel** aRetVal) { 137 // Check if URI resolves to a file URI. 138 nsAutoCString resolvedSpec; 139 MOZ_TRY(ResolveURI(aURI, resolvedSpec)); 140 141 nsAutoCString scheme; 142 MOZ_TRY(net_ExtractURLScheme(resolvedSpec, scheme)); 143 144 if (!scheme.EqualsLiteral("file")) { 145 NS_WARNING("moz-newtab-wallpaper URIs should only resolve to file URIs."); 146 return NS_ERROR_NO_INTERFACE; 147 } 148 149 if (IsNeckoChild()) { 150 MOZ_TRY(SubstituteRemoteChannel(aURI, aLoadInfo, aRetVal)); 151 } 152 153 return NS_OK; 154 } 155 156 Result<Ok, nsresult> MozNewTabWallpaperProtocolHandler::SubstituteRemoteChannel( 157 nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIChannel** aRetVal) { 158 MOZ_ASSERT(IsNeckoChild()); 159 MOZ_TRY(aURI ? NS_OK : NS_ERROR_INVALID_ARG); 160 MOZ_TRY(aLoadInfo ? NS_OK : NS_ERROR_INVALID_ARG); 161 162 #ifdef DEBUG 163 nsAutoCString resolvedSpec; 164 MOZ_TRY(ResolveURI(aURI, resolvedSpec)); 165 166 nsAutoCString scheme; 167 MOZ_TRY(net_ExtractURLScheme(resolvedSpec, scheme)); 168 169 MOZ_ASSERT(scheme.EqualsLiteral("file")); 170 #endif /* DEBUG */ 171 172 RefPtr<RemoteStreamGetter> streamGetter = 173 new RemoteStreamGetter(aURI, aLoadInfo); 174 175 NewSimpleChannel(aURI, aLoadInfo, streamGetter, aRetVal); 176 return Ok(); 177 } 178 179 // static 180 void MozNewTabWallpaperProtocolHandler::NewSimpleChannel( 181 nsIURI* aURI, nsILoadInfo* aLoadinfo, RemoteStreamGetter* aStreamGetter, 182 nsIChannel** aRetVal) { 183 nsCOMPtr<nsIChannel> channel = NS_NewSimpleChannel( 184 aURI, aLoadinfo, aStreamGetter, 185 [](nsIStreamListener* listener, nsIChannel* simpleChannel, 186 RemoteStreamGetter* getter) -> RequestOrReason { 187 return getter->GetAsync(listener, simpleChannel, 188 &NeckoChild::SendGetMozNewTabWallpaperStream); 189 }); 190 191 channel.swap(*aRetVal); 192 } 193 194 } // namespace net 195 } // namespace mozilla