mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1184701 - Make the moz-page-thumb protocol work in the privileged about content process. r=haik,valentin
Differential Revision: https://phabricator.services.mozilla.com/D68281 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
3c7916f406
commit
a98dabe6ec
@ -55,6 +55,8 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include <stdint.h>
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
@ -925,6 +927,15 @@ nsresult nsScriptSecurityManager::CheckLoadURIFlags(
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
} else if (targetScheme.EqualsLiteral("moz-page-thumb")) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto& remoteType = dom::ContentChild::GetSingleton()->GetRemoteType();
|
||||
if (remoteType.EqualsLiteral(PRIVILEGEDABOUT_REMOTE_TYPE)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,7 @@
|
||||
#include "nsAboutProtocolHandler.h"
|
||||
#include "nsResProtocolHandler.h"
|
||||
#include "mozilla/net/ExtensionProtocolHandler.h"
|
||||
#include "mozilla/net/PageThumbProtocolHandler.h"
|
||||
#include <limits>
|
||||
|
||||
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
|
||||
@ -1753,7 +1754,6 @@ nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
|
||||
if (scheme.EqualsLiteral("moz-safe-about") ||
|
||||
scheme.EqualsLiteral("page-icon") || scheme.EqualsLiteral("moz") ||
|
||||
scheme.EqualsLiteral("moz-anno") ||
|
||||
scheme.EqualsLiteral("moz-page-thumb") ||
|
||||
scheme.EqualsLiteral("moz-fonttable")) {
|
||||
return NS_MutateURI(new nsSimpleURI::Mutator())
|
||||
.SetSpec(aSpec)
|
||||
@ -1804,6 +1804,22 @@ nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
|
||||
return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("moz-page-thumb")) {
|
||||
// The moz-page-thumb service runs JS to resolve a URI to a
|
||||
// storage location, so this should only ever run on the main
|
||||
// thread.
|
||||
if (!NS_IsMainThread()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::net::PageThumbProtocolHandler> handler =
|
||||
mozilla::net::PageThumbProtocolHandler::GetSingleton();
|
||||
if (!handler) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("about")) {
|
||||
return nsAboutProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
|
||||
aURI);
|
||||
|
@ -314,6 +314,14 @@ Classes = [
|
||||
'headers': ['mozilla/net/ExtensionProtocolHandler.h'],
|
||||
'constructor': 'mozilla::net::ExtensionProtocolHandler::GetSingleton',
|
||||
},
|
||||
{
|
||||
'cid': '{450a2b55-620a-44b3-9f67-839b3b0c329c}',
|
||||
'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-page-thumb'],
|
||||
'singleton': True,
|
||||
'type': 'mozilla::net::PageThumbProtocolHandler',
|
||||
'headers': ['mozilla/net/PageThumbProtocolHandler.h'],
|
||||
'constructor': 'mozilla::net::PageThumbProtocolHandler::GetSingleton',
|
||||
},
|
||||
{
|
||||
'cid': '{1423e739-782c-4081-b5d8-fe6fba68c0ef}',
|
||||
'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-safe-about'],
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/ContentPrincipal.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/net/ExtensionProtocolHandler.h"
|
||||
#include "mozilla/net/PageThumbProtocolHandler.h"
|
||||
#include "mozilla/net/NeckoParent.h"
|
||||
#include "mozilla/net/HttpChannelParent.h"
|
||||
#include "mozilla/net/CookieServiceParent.h"
|
||||
@ -1001,5 +1002,51 @@ mozilla::ipc::IPCResult NeckoParent::RecvEnsureHSTSData(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult NeckoParent::RecvGetPageThumbStream(
|
||||
nsIURI* aURI, GetPageThumbStreamResolver&& aResolver) {
|
||||
// Only the privileged about content process is allowed to access
|
||||
// things over the moz-page-thumb protocol. Any other content process
|
||||
// that tries to send this should have been blocked via the
|
||||
// ScriptSecurityManager, but if somehow the process has been tricked into
|
||||
// sending this message, we send IPC_FAIL in order to crash that
|
||||
// likely-compromised content process.
|
||||
if (!static_cast<ContentParent*>(Manager())->GetRemoteType().EqualsLiteral(
|
||||
PRIVILEGEDABOUT_REMOTE_TYPE)) {
|
||||
return IPC_FAIL(this, "Wrong process type");
|
||||
}
|
||||
|
||||
RefPtr<PageThumbProtocolHandler> ph(PageThumbProtocolHandler::GetSingleton());
|
||||
MOZ_ASSERT(ph);
|
||||
|
||||
// Ask the PageThumbProtocolHandler to give us a new input stream for
|
||||
// this URI. The request comes from a PageThumbProtocolHandler in the
|
||||
// child process, but is not guaranteed to be a valid moz-page-thumb URI,
|
||||
// and not guaranteed to represent a resource that the child should be
|
||||
// allowed to access. The PageThumbProtocolHandler is responsible for
|
||||
// validating the request.
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
bool terminateSender = true;
|
||||
auto inputStreamPromise = ph->NewStream(aURI, &terminateSender);
|
||||
|
||||
if (terminateSender) {
|
||||
return IPC_FAIL(this, "Malformed moz-page-thumb request");
|
||||
}
|
||||
|
||||
inputStreamPromise->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[aResolver](const nsCOMPtr<nsIInputStream>& aStream) {
|
||||
aResolver(aStream);
|
||||
},
|
||||
[aResolver](nsresult aRv) {
|
||||
// If NewStream failed, we send back an invalid stream to the child so
|
||||
// it can handle the error. MozPromise rejection is reserved for channel
|
||||
// errors/disconnects.
|
||||
Unused << NS_WARN_IF(NS_FAILED(aRv));
|
||||
aResolver(nullptr);
|
||||
});
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -234,6 +234,10 @@ class NeckoParent : public PNeckoParent {
|
||||
mozilla::ipc::IPCResult RecvGetExtensionFD(nsIURI* aURI,
|
||||
GetExtensionFDResolver&& aResolve);
|
||||
|
||||
/* Page thumbnails remote resource loading */
|
||||
mozilla::ipc::IPCResult RecvGetPageThumbStream(
|
||||
nsIURI* aURI, GetPageThumbStreamResolver&& aResolve);
|
||||
|
||||
PClassifierDummyChannelParent* AllocPClassifierDummyChannelParent(
|
||||
nsIURI* aURI, nsIURI* aTopWindowURI, const nsresult& aTopWindowURIResult,
|
||||
const Maybe<LoadInfoArgs>& aLoadInfo);
|
||||
|
@ -156,6 +156,11 @@ parent:
|
||||
async EnsureHSTSData()
|
||||
returns (bool result);
|
||||
|
||||
/**
|
||||
* Page thumbnails remote resource loading
|
||||
*/
|
||||
async GetPageThumbStream(nsIURI uri) returns (nsIInputStream stream);
|
||||
|
||||
child:
|
||||
/*
|
||||
* Bring up the http auth prompt for a nested remote mozbrowser.
|
||||
|
@ -148,6 +148,9 @@ class ExtensionStreamGetter : public RefCounted<ExtensionStreamGetter> {
|
||||
// Handle file descriptor being returned from the parent
|
||||
void OnFD(const FileDescriptor& aFD);
|
||||
|
||||
static void CancelRequest(nsIStreamListener* aListener, nsIChannel* aChannel,
|
||||
nsresult aResult);
|
||||
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(ExtensionStreamGetter)
|
||||
|
||||
private:
|
||||
@ -257,8 +260,10 @@ Result<Ok, nsresult> ExtensionStreamGetter::GetAsync(
|
||||
return Ok();
|
||||
}
|
||||
|
||||
static void CancelRequest(nsIStreamListener* aListener, nsIChannel* aChannel,
|
||||
nsresult aResult) {
|
||||
// static
|
||||
void ExtensionStreamGetter::CancelRequest(nsIStreamListener* aListener,
|
||||
nsIChannel* aChannel,
|
||||
nsresult aResult) {
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
@ -464,7 +469,7 @@ void OpenWhenReady(
|
||||
nsIStreamListener* aListener) -> already_AddRefed<Promise> {
|
||||
nsresult rv = aCallback(aListener, channel);
|
||||
if (NS_FAILED(rv)) {
|
||||
CancelRequest(aListener, channel, rv);
|
||||
ExtensionStreamGetter::CancelRequest(aListener, channel, rv);
|
||||
}
|
||||
return nullptr;
|
||||
},
|
||||
@ -840,7 +845,10 @@ Result<Ok, nsresult> ExtensionProtocolHandler::NewFD(
|
||||
}
|
||||
|
||||
// Set the channel's content type using the provided URI's type
|
||||
void SetContentType(nsIURI* aURI, nsIChannel* aChannel) {
|
||||
|
||||
// static
|
||||
void ExtensionProtocolHandler::SetContentType(nsIURI* aURI,
|
||||
nsIChannel* aChannel) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -853,9 +861,11 @@ void SetContentType(nsIURI* aURI, nsIChannel* aChannel) {
|
||||
}
|
||||
|
||||
// Gets a SimpleChannel that wraps the provided ExtensionStreamGetter
|
||||
static void NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo,
|
||||
ExtensionStreamGetter* aStreamGetter,
|
||||
nsIChannel** aRetVal) {
|
||||
|
||||
// static
|
||||
void ExtensionProtocolHandler::NewSimpleChannel(
|
||||
nsIURI* aURI, nsILoadInfo* aLoadinfo, ExtensionStreamGetter* aStreamGetter,
|
||||
nsIChannel** aRetVal) {
|
||||
nsCOMPtr<nsIChannel> channel = NS_NewSimpleChannel(
|
||||
aURI, aLoadinfo, aStreamGetter,
|
||||
[](nsIStreamListener* listener, nsIChannel* simpleChannel,
|
||||
@ -869,8 +879,12 @@ static void NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo,
|
||||
}
|
||||
|
||||
// Gets a SimpleChannel that wraps the provided channel
|
||||
static void NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo,
|
||||
nsIChannel* aChannel, nsIChannel** aRetVal) {
|
||||
|
||||
// static
|
||||
void ExtensionProtocolHandler::NewSimpleChannel(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadinfo,
|
||||
nsIChannel* aChannel,
|
||||
nsIChannel** aRetVal) {
|
||||
nsCOMPtr<nsIChannel> channel = NS_NewSimpleChannel(
|
||||
aURI, aLoadinfo, aChannel,
|
||||
[](nsIStreamListener* listener, nsIChannel* simpleChannel,
|
||||
|
@ -14,6 +14,8 @@
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class ExtensionStreamGetter;
|
||||
|
||||
class ExtensionProtocolHandler final
|
||||
: public nsISubstitutingProtocolHandler,
|
||||
public nsIProtocolHandlerWithDynamicFlags,
|
||||
@ -156,6 +158,18 @@ class ExtensionProtocolHandler final
|
||||
Result<bool, nsresult> AllowExternalResource(nsIFile* aExtensionDir,
|
||||
nsIFile* aRequestedFile);
|
||||
|
||||
// Set the channel's content type using the provided URI's type
|
||||
static void SetContentType(nsIURI* aURI, nsIChannel* aChannel);
|
||||
|
||||
// Gets a SimpleChannel that wraps the provided ExtensionStreamGetter
|
||||
static void NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo,
|
||||
ExtensionStreamGetter* aStreamGetter,
|
||||
nsIChannel** aRetVal);
|
||||
|
||||
// Gets a SimpleChannel that wraps the provided channel
|
||||
static void NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo,
|
||||
nsIChannel* aChannel, nsIChannel** aRetVal);
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
/**
|
||||
* Sets the aResult outparam to true if we are a developer build with the
|
||||
|
467
netwerk/protocol/res/PageThumbProtocolHandler.cpp
Normal file
467
netwerk/protocol/res/PageThumbProtocolHandler.cpp
Normal file
@ -0,0 +1,467 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "PageThumbProtocolHandler.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/ipc/URIParams.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
|
||||
#include "LoadInfo.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIPageThumbsStorageService.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "prio.h"
|
||||
#include "SimpleChannel.h"
|
||||
|
||||
#define PAGE_THUMB_HOST "thumbnails"
|
||||
#define PAGE_THUMB_SCHEME "moz-page-thumb"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
LazyLogModule gPageThumbProtocolLog("PageThumbProtocol");
|
||||
|
||||
#undef LOG
|
||||
#define LOG(level, ...) \
|
||||
MOZ_LOG(gPageThumbProtocolLog, LogLevel::level, (__VA_ARGS__))
|
||||
|
||||
StaticRefPtr<PageThumbProtocolHandler> PageThumbProtocolHandler::sSingleton;
|
||||
|
||||
/**
|
||||
* Helper class used with SimpleChannel to asynchronously obtain an input
|
||||
* stream from the parent for a remote moz-page-thumb load from the child.
|
||||
*/
|
||||
class PageThumbStreamGetter : public RefCounted<PageThumbStreamGetter> {
|
||||
public:
|
||||
PageThumbStreamGetter(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
: mURI(aURI), mLoadInfo(aLoadInfo) {
|
||||
MOZ_ASSERT(aURI);
|
||||
MOZ_ASSERT(aLoadInfo);
|
||||
|
||||
SetupEventTarget();
|
||||
}
|
||||
|
||||
~PageThumbStreamGetter() = default;
|
||||
|
||||
void SetupEventTarget() {
|
||||
mMainThreadEventTarget = nsContentUtils::GetEventTargetByLoadInfo(
|
||||
mLoadInfo, TaskCategory::Other);
|
||||
if (!mMainThreadEventTarget) {
|
||||
mMainThreadEventTarget = GetMainThreadSerialEventTarget();
|
||||
}
|
||||
}
|
||||
|
||||
// Get an input stream from the parent asynchronously.
|
||||
Result<Ok, nsresult> GetAsync(nsIStreamListener* aListener,
|
||||
nsIChannel* aChannel);
|
||||
|
||||
// Handle an input stream being returned from the parent
|
||||
void OnStream(already_AddRefed<nsIInputStream> aStream);
|
||||
|
||||
static void CancelRequest(nsIStreamListener* aListener, nsIChannel* aChannel,
|
||||
nsresult aResult);
|
||||
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(PageThumbStreamGetter)
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsILoadInfo> mLoadInfo;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
|
||||
};
|
||||
|
||||
// Request an input stream from the parent.
|
||||
Result<Ok, nsresult> PageThumbStreamGetter::GetAsync(
|
||||
nsIStreamListener* aListener, nsIChannel* aChannel) {
|
||||
MOZ_ASSERT(IsNeckoChild());
|
||||
MOZ_ASSERT(mMainThreadEventTarget);
|
||||
|
||||
mListener = aListener;
|
||||
mChannel = aChannel;
|
||||
|
||||
RefPtr<PageThumbStreamGetter> self = this;
|
||||
|
||||
// Request an input stream for this moz-page-thumb URI.
|
||||
gNeckoChild->SendGetPageThumbStream(mURI)->Then(
|
||||
mMainThreadEventTarget, __func__,
|
||||
[self](const RefPtr<nsIInputStream>& stream) {
|
||||
self->OnStream(do_AddRef(stream));
|
||||
},
|
||||
[self](const mozilla::ipc::ResponseRejectReason) {
|
||||
self->OnStream(nullptr);
|
||||
});
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// static
|
||||
void PageThumbStreamGetter::CancelRequest(nsIStreamListener* aListener,
|
||||
nsIChannel* aChannel,
|
||||
nsresult aResult) {
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
aListener->OnStartRequest(aChannel);
|
||||
aListener->OnStopRequest(aChannel, aResult);
|
||||
aChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
// Handle an input stream sent from the parent.
|
||||
void PageThumbStreamGetter::OnStream(already_AddRefed<nsIInputStream> aStream) {
|
||||
MOZ_ASSERT(IsNeckoChild());
|
||||
MOZ_ASSERT(mListener);
|
||||
MOZ_ASSERT(mMainThreadEventTarget);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
|
||||
|
||||
// We must keep an owning reference to the listener until we pass it on
|
||||
// to AsyncRead.
|
||||
nsCOMPtr<nsIStreamListener> listener = mListener.forget();
|
||||
|
||||
MOZ_ASSERT(mChannel);
|
||||
|
||||
if (!stream) {
|
||||
// The parent didn't send us back a stream.
|
||||
CancelRequest(listener, mChannel, NS_ERROR_FILE_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamPump> pump;
|
||||
nsresult rv = NS_NewInputStreamPump(getter_AddRefs(pump), stream.forget(), 0,
|
||||
0, false, mMainThreadEventTarget);
|
||||
if (NS_FAILED(rv)) {
|
||||
CancelRequest(listener, mChannel, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = pump->AsyncRead(listener, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
CancelRequest(listener, mChannel, rv);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE(PageThumbProtocolHandler,
|
||||
nsISubstitutingProtocolHandler, nsIProtocolHandler,
|
||||
nsIProtocolHandlerWithDynamicFlags,
|
||||
nsISupportsWeakReference)
|
||||
NS_IMPL_ADDREF_INHERITED(PageThumbProtocolHandler, SubstitutingProtocolHandler)
|
||||
NS_IMPL_RELEASE_INHERITED(PageThumbProtocolHandler, SubstitutingProtocolHandler)
|
||||
|
||||
already_AddRefed<PageThumbProtocolHandler>
|
||||
PageThumbProtocolHandler::GetSingleton() {
|
||||
if (!sSingleton) {
|
||||
sSingleton = new PageThumbProtocolHandler();
|
||||
ClearOnShutdown(&sSingleton);
|
||||
}
|
||||
|
||||
return do_AddRef(sSingleton);
|
||||
}
|
||||
|
||||
PageThumbProtocolHandler::PageThumbProtocolHandler()
|
||||
: SubstitutingProtocolHandler(PAGE_THUMB_SCHEME) {}
|
||||
|
||||
nsresult PageThumbProtocolHandler::GetFlagsForURI(nsIURI* aURI,
|
||||
uint32_t* aFlags) {
|
||||
// A moz-page-thumb URI is only loadable by chrome pages in the parent
|
||||
// process, or privileged content running in the privileged about content
|
||||
// process.
|
||||
*aFlags = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE |
|
||||
URI_NORELATIVE | URI_NOAUTH;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
|
||||
nsIURI* aChildURI, bool* aTerminateSender) {
|
||||
MOZ_ASSERT(!IsNeckoChild());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aChildURI || !aTerminateSender) {
|
||||
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_INVALID_ARG,
|
||||
__func__);
|
||||
}
|
||||
|
||||
*aTerminateSender = true;
|
||||
nsresult rv;
|
||||
|
||||
// We should never receive a URI that isn't for a moz-page-thumb because
|
||||
// these requests ordinarily come from the child's PageThumbProtocolHandler.
|
||||
// Ensure this request is for a moz-page-thumb URI. A compromised child
|
||||
// process could send us any URI.
|
||||
bool isPageThumbScheme = false;
|
||||
if (NS_FAILED(aChildURI->SchemeIs(PAGE_THUMB_SCHEME, &isPageThumbScheme)) ||
|
||||
!isPageThumbScheme) {
|
||||
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_UNKNOWN_PROTOCOL,
|
||||
__func__);
|
||||
}
|
||||
|
||||
// We should never receive a URI that does not have "thumbnails" as the host.
|
||||
nsAutoCString host;
|
||||
if (NS_FAILED(aChildURI->GetAsciiHost(host)) ||
|
||||
!host.EqualsLiteral(PAGE_THUMB_HOST)) {
|
||||
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
|
||||
__func__);
|
||||
}
|
||||
|
||||
// For errors after this point, we want to propagate the error to
|
||||
// the child, but we don't force the child process to be terminated.
|
||||
*aTerminateSender = false;
|
||||
|
||||
// Make sure the child URI resolves to a file URI. We will then get a file
|
||||
// channel for the request. The resultant channel should be a file channel
|
||||
// because we only request remote streams for resource loads where the URI
|
||||
// resolves to a file.
|
||||
nsAutoCString resolvedSpec;
|
||||
rv = ResolveURI(aChildURI, resolvedSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
nsAutoCString resolvedScheme;
|
||||
rv = net_ExtractURLScheme(resolvedSpec, resolvedScheme);
|
||||
if (NS_FAILED(rv) || !resolvedScheme.EqualsLiteral("file")) {
|
||||
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
|
||||
__func__);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> resolvedURI;
|
||||
rv = ioService->NewURI(resolvedSpec, nullptr, nullptr,
|
||||
getter_AddRefs(resolvedURI));
|
||||
if (NS_FAILED(rv)) {
|
||||
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
// We use the system principal to get a file channel for the request,
|
||||
// but only after we've checked (above) that the child URI is of
|
||||
// moz-page-thumb scheme and that the URI host matches PAGE_THUMB_HOST.
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel), resolvedURI,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
||||
nsIContentPolicy::TYPE_OTHER);
|
||||
if (NS_FAILED(rv)) {
|
||||
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
auto promiseHolder = MakeUnique<MozPromiseHolder<PageThumbStreamPromise>>();
|
||||
RefPtr<PageThumbStreamPromise> promise = promiseHolder->Ensure(__func__);
|
||||
|
||||
rv = NS_DispatchBackgroundTask(
|
||||
NS_NewRunnableFunction(
|
||||
"PageThumbProtocolHandler::NewStream",
|
||||
[channel, holder = std::move(promiseHolder)]() {
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFileChannel> fileChannel =
|
||||
do_QueryInterface(channel, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
holder->Reject(rv, __func__);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> requestedFile;
|
||||
rv = fileChannel->GetFile(getter_AddRefs(requestedFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
holder->Reject(rv, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
|
||||
requestedFile, PR_RDONLY, -1);
|
||||
if (NS_FAILED(rv)) {
|
||||
holder->Reject(rv, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
holder->Resolve(inputStream, __func__);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
bool PageThumbProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
|
||||
const nsACString& aPath,
|
||||
const nsACString& aPathname,
|
||||
nsACString& aResult) {
|
||||
// This should match the scheme in PageThumbs.jsm. We will only resolve
|
||||
// URIs for thumbnails generated by PageThumbs here.
|
||||
if (!aHost.EqualsLiteral(PAGE_THUMB_HOST)) {
|
||||
// moz-page-thumb should always have a "thumbnails" host. We do not intend
|
||||
// to allow substitution rules to be created for moz-page-thumb.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Regardless of the outcome, the scheme will be resolved to file://.
|
||||
aResult.Assign("file://");
|
||||
|
||||
if (IsNeckoChild()) {
|
||||
// We will resolve the URI in the parent if load is performed in the child
|
||||
// because the child does not have access to the profile directory path.
|
||||
// Technically we could retrieve the path from dom::ContentChild, but I
|
||||
// would prefer to obtain the path from PageThumbsStorageService (which
|
||||
// depends on OS.Path). Here, we resolve to the same URI, with the file://
|
||||
// scheme. This won't ever be accessed directly by the content process,
|
||||
// and is mainly used to keep the substitution protocol handler mechanism
|
||||
// happy.
|
||||
aResult.Append(aHost);
|
||||
aResult.Append(aPath);
|
||||
} else {
|
||||
// Resolve the URI in the parent to the thumbnail file URI since we will
|
||||
// attempt to open the channel to load the file after this.
|
||||
nsAutoString thumbnailUrl;
|
||||
nsresult rv = GetThumbnailPath(aPath, thumbnailUrl);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aResult.Append(NS_ConvertUTF16toUTF8(thumbnailUrl));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult PageThumbProtocolHandler::SubstituteChannel(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** aRetVal) {
|
||||
// Check if URI resolves to a file URI.
|
||||
nsAutoCString resolvedSpec;
|
||||
MOZ_TRY(ResolveURI(aURI, resolvedSpec));
|
||||
|
||||
nsAutoCString scheme;
|
||||
MOZ_TRY(net_ExtractURLScheme(resolvedSpec, scheme));
|
||||
|
||||
if (!scheme.EqualsLiteral("file")) {
|
||||
NS_WARNING("moz-page-thumb URIs should only resolve to file URIs.");
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
// Load the URI remotely if accessed from a child.
|
||||
if (IsNeckoChild()) {
|
||||
MOZ_TRY(SubstituteRemoteChannel(aURI, aLoadInfo, aRetVal));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> PageThumbProtocolHandler::SubstituteRemoteChannel(
|
||||
nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIChannel** aRetVal) {
|
||||
MOZ_ASSERT(IsNeckoChild());
|
||||
MOZ_TRY(aURI ? NS_OK : NS_ERROR_INVALID_ARG);
|
||||
MOZ_TRY(aLoadInfo ? NS_OK : NS_ERROR_INVALID_ARG);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsAutoCString resolvedSpec;
|
||||
MOZ_TRY(ResolveURI(aURI, resolvedSpec));
|
||||
|
||||
nsAutoCString scheme;
|
||||
MOZ_TRY(net_ExtractURLScheme(resolvedSpec, scheme));
|
||||
|
||||
MOZ_ASSERT(scheme.EqualsLiteral("file"));
|
||||
#endif /* DEBUG */
|
||||
|
||||
RefPtr<PageThumbStreamGetter> streamGetter =
|
||||
new PageThumbStreamGetter(aURI, aLoadInfo);
|
||||
|
||||
NewSimpleChannel(aURI, aLoadInfo, streamGetter, aRetVal);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
nsresult PageThumbProtocolHandler::GetThumbnailPath(const nsACString& aPath,
|
||||
nsString& aThumbnailPath) {
|
||||
MOZ_ASSERT(!IsNeckoChild());
|
||||
|
||||
// Ensures that the provided path has a query string. We will start parsing
|
||||
// from there.
|
||||
int32_t queryIndex = aPath.FindChar('?');
|
||||
if (queryIndex <= 0) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIPageThumbsStorageService> pageThumbsStorage =
|
||||
do_GetService("@mozilla.org/thumbnails/pagethumbs-service;1", &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Extract URL from query string.
|
||||
nsAutoString url;
|
||||
bool found = dom::URLParams::Extract(Substring(aPath, queryIndex + 1),
|
||||
NS_LITERAL_STRING("url"), url);
|
||||
if (!found || url.IsVoid()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Use PageThumbsStorageService to get the local file path of the screenshot
|
||||
// for the given URL.
|
||||
rv = pageThumbsStorage->GetFilePathForURL(url, aThumbnailPath);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void PageThumbProtocolHandler::SetContentType(nsIURI* aURI,
|
||||
nsIChannel* aChannel) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoCString contentType;
|
||||
rv = mime->GetTypeFromURI(aURI, contentType);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
Unused << aChannel->SetContentType(contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void PageThumbProtocolHandler::NewSimpleChannel(
|
||||
nsIURI* aURI, nsILoadInfo* aLoadinfo, PageThumbStreamGetter* aStreamGetter,
|
||||
nsIChannel** aRetVal) {
|
||||
nsCOMPtr<nsIChannel> channel = NS_NewSimpleChannel(
|
||||
aURI, aLoadinfo, aStreamGetter,
|
||||
[](nsIStreamListener* listener, nsIChannel* simpleChannel,
|
||||
PageThumbStreamGetter* getter) -> RequestOrReason {
|
||||
MOZ_TRY(getter->GetAsync(listener, simpleChannel));
|
||||
return RequestOrReason(nullptr);
|
||||
});
|
||||
|
||||
SetContentType(aURI, channel);
|
||||
channel.swap(*aRetVal);
|
||||
}
|
||||
|
||||
#undef LOG
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
123
netwerk/protocol/res/PageThumbProtocolHandler.h
Normal file
123
netwerk/protocol/res/PageThumbProtocolHandler.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 PageThumbProtocolHandler_h___
|
||||
#define PageThumbProtocolHandler_h___
|
||||
|
||||
#include "mozilla/Result.h"
|
||||
#include "SubstitutingProtocolHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
using PageThumbStreamPromise =
|
||||
mozilla::MozPromise<nsCOMPtr<nsIInputStream>, nsresult, false>;
|
||||
|
||||
class PageThumbStreamGetter;
|
||||
|
||||
class PageThumbProtocolHandler final
|
||||
: public nsISubstitutingProtocolHandler,
|
||||
public nsIProtocolHandlerWithDynamicFlags,
|
||||
public SubstitutingProtocolHandler,
|
||||
public nsSupportsWeakReference {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIPROTOCOLHANDLERWITHDYNAMICFLAGS
|
||||
NS_FORWARD_NSIPROTOCOLHANDLER(SubstitutingProtocolHandler::)
|
||||
NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(SubstitutingProtocolHandler::)
|
||||
|
||||
static already_AddRefed<PageThumbProtocolHandler> GetSingleton();
|
||||
|
||||
/**
|
||||
* To be called in the parent process to obtain an input stream for the
|
||||
* given thumbnail.
|
||||
*
|
||||
* @param aChildURI a moz-page-thumb URI sent from the child.
|
||||
* @param aTerminateSender out param set to true when the params are invalid
|
||||
* and indicate the child should be terminated. If |aChildURI| is
|
||||
* not a moz-page-thumb URI, the child is in an invalid state and
|
||||
* should be terminated. This outparam will be set synchronously.
|
||||
*
|
||||
* @return PageThumbStreamPromise
|
||||
* The PageThumbStreamPromise will resolve with an nsIInputStream on
|
||||
* success, and reject with an nsresult on failure.
|
||||
*/
|
||||
RefPtr<PageThumbStreamPromise> NewStream(nsIURI* aChildURI,
|
||||
bool* aTerminateSender);
|
||||
|
||||
protected:
|
||||
~PageThumbProtocolHandler() = default;
|
||||
|
||||
private:
|
||||
explicit PageThumbProtocolHandler();
|
||||
|
||||
MOZ_MUST_USE bool ResolveSpecialCases(const nsACString& aHost,
|
||||
const nsACString& aPath,
|
||||
const nsACString& aPathname,
|
||||
nsACString& aResult) override;
|
||||
|
||||
/**
|
||||
* On entry to this function, *aRetVal is expected to be non-null and already
|
||||
* addrefed. This function may release the object stored in *aRetVal on entry
|
||||
* and write a new pointer to an already addrefed channel to *aRetVal.
|
||||
*
|
||||
* @param aURI the moz-page-thumb URI.
|
||||
* @param aLoadInfo the loadinfo for the request.
|
||||
* @param aRetVal in/out channel param referring to the channel that
|
||||
* might need to be substituted with a remote channel.
|
||||
* @return NS_OK if channel has been substituted successfully or no
|
||||
* substitution at all. Otherwise, returns an error. This function
|
||||
* will return NS_ERROR_NO_INTERFACE if the URI resolves to a
|
||||
* non file:// URI.
|
||||
*/
|
||||
virtual MOZ_MUST_USE nsresult SubstituteChannel(
|
||||
nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIChannel** aRetVal) override;
|
||||
|
||||
/**
|
||||
* This replaces the provided channel with a channel that will proxy the load
|
||||
* to the parent process.
|
||||
*
|
||||
* @param aURI the moz-page-thumb URI.
|
||||
* @param aLoadInfo the loadinfo for the request.
|
||||
* @param aRetVal in/out channel param referring to the channel that
|
||||
* might need to be substituted with a remote channel.
|
||||
* @return NS_OK if the replacement channel was created successfully.
|
||||
* Otherwise, returns an error.
|
||||
*/
|
||||
Result<Ok, nsresult> SubstituteRemoteChannel(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** aRetVal);
|
||||
|
||||
/*
|
||||
* Extracts the URL from the query string in the given moz-page-thumb URI
|
||||
* and queries PageThumbsStorageService using the extracted URL to obtain
|
||||
* the local file path of the screenshot. This should only be called from
|
||||
* the parent because PageThumbsStorageService relies on the path of the
|
||||
* profile directory, which is unavailable in the child.
|
||||
*
|
||||
* @param aPath the path of the moz-page-thumb URI.
|
||||
* @param aThumbnailPath in/out string param referring to the thumbnail path.
|
||||
* @return NS_OK if the thumbnail path was obtained successfully. Otherwise
|
||||
* returns an error.
|
||||
*/
|
||||
nsresult GetThumbnailPath(const nsACString& aPath, nsString& aThumbnailPath);
|
||||
|
||||
// To allow parent IPDL actors to invoke methods on this handler when
|
||||
// handling moz-page-thumb requests from the child.
|
||||
static StaticRefPtr<PageThumbProtocolHandler> sSingleton;
|
||||
|
||||
// Set the channel's content type using the provided URI's type.
|
||||
static void SetContentType(nsIURI* aURI, nsIChannel* aChannel);
|
||||
|
||||
// Gets a SimpleChannel that wraps the provided channel.
|
||||
static void NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo,
|
||||
PageThumbStreamGetter* aStreamGetter,
|
||||
nsIChannel** aRetVal);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* PageThumbProtocolHandler_h___ */
|
@ -13,6 +13,7 @@ XPIDL_MODULE = 'necko_res'
|
||||
|
||||
EXPORTS.mozilla.net += [
|
||||
'ExtensionProtocolHandler.h',
|
||||
'PageThumbProtocolHandler.h',
|
||||
'SubstitutingJARURI.h',
|
||||
'SubstitutingProtocolHandler.h',
|
||||
'SubstitutingURL.h',
|
||||
@ -25,6 +26,7 @@ EXPORTS += [
|
||||
UNIFIED_SOURCES += [
|
||||
'ExtensionProtocolHandler.cpp',
|
||||
'nsResProtocolHandler.cpp',
|
||||
'PageThumbProtocolHandler.cpp',
|
||||
'SubstitutingProtocolHandler.cpp',
|
||||
]
|
||||
|
||||
|
@ -100,7 +100,7 @@ var PageThumbs = {
|
||||
* The static host to use for thumbnail urls.
|
||||
*/
|
||||
get staticHost() {
|
||||
return "thumbnail";
|
||||
return "thumbnails";
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1,158 +0,0 @@
|
||||
//* -*- Mode: C++; tab-width: 8; 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/. */
|
||||
|
||||
/**
|
||||
* Implementation of moz-page-thumb protocol. This accesses and displays
|
||||
* screenshots for URLs that are stored in the profile directory.
|
||||
*/
|
||||
|
||||
#include "nsIPageThumbsStorageService.h"
|
||||
#include "PageThumbsProtocol.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "nsStandardURL.h"
|
||||
|
||||
using mozilla::dom::URLParams;
|
||||
using mozilla::net::nsStandardURL;
|
||||
|
||||
NS_IMPL_ISUPPORTS(PageThumbsProtocol, nsIProtocolHandler);
|
||||
|
||||
// PageThumbsProtocol::GetScheme
|
||||
|
||||
NS_IMETHODIMP
|
||||
PageThumbsProtocol::GetScheme(nsACString& aScheme) {
|
||||
aScheme.AssignLiteral("moz-page-thumb");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// PageThumbsProtocol::GetDefaultPort
|
||||
|
||||
NS_IMETHODIMP
|
||||
PageThumbsProtocol::GetDefaultPort(int32_t* aDefaultPort) {
|
||||
*aDefaultPort = -1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// PageThumbsProtocol::GetProtocolFlags
|
||||
|
||||
NS_IMETHODIMP
|
||||
PageThumbsProtocol::GetProtocolFlags(uint32_t* aProtocolFlags) {
|
||||
*aProtocolFlags = (URI_DANGEROUS_TO_LOAD | URI_IS_LOCAL_RESOURCE |
|
||||
URI_NORELATIVE | URI_NOAUTH);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// PageThumbsProtocol::NewChannel
|
||||
|
||||
NS_IMETHODIMP
|
||||
PageThumbsProtocol::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** _retval) {
|
||||
// Get the file path for the URL
|
||||
nsCOMPtr<nsIFile> filePath;
|
||||
nsresult rv = GetFilePathForURL(aURI, getter_AddRefs(filePath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
// Get a file URI from the local file path
|
||||
nsCOMPtr<nsIURI> fileURI;
|
||||
rv = NS_NewFileURI(getter_AddRefs(fileURI), filePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
// Create a new channel with the file URI created
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService();
|
||||
rv = ios->NewChannelFromURIWithLoadInfo(fileURI, aLoadInfo,
|
||||
getter_AddRefs(channel));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
channel->SetOriginalURI(aURI);
|
||||
channel.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// PageThumbsProtocol::AllowPort
|
||||
|
||||
NS_IMETHODIMP
|
||||
PageThumbsProtocol::AllowPort(int32_t aPort, const char* aScheme,
|
||||
bool* _retval) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// PageThumbsProtocol::ParseProtocolURL
|
||||
//
|
||||
// Extracts the URL from the query parameter. The URI is passed in in the
|
||||
// form: 'moz-page-thumb://thumbnail/?url=http%3A%2F%2Fwww.mozilla.org%2F'.
|
||||
|
||||
nsresult PageThumbsProtocol::ParseProtocolURL(nsIURI* aURI,
|
||||
nsString& aParsedURL) {
|
||||
nsAutoCString spec;
|
||||
aURI->GetSpec(spec);
|
||||
|
||||
// Check that we have the correct host
|
||||
nsAutoCString host;
|
||||
host = Substring(spec, spec.FindChar(':') + 3, 9);
|
||||
if (!host.EqualsLiteral("thumbnail")) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Get the path out of the URI
|
||||
nsAutoCString path;
|
||||
nsresult rv = aURI->GetPathQueryRef(path);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
// Since this is a protocol URI and it doesn't parse nicely, we split on where
|
||||
// the start of the query is and parse it from there
|
||||
int32_t queryBegins = path.FindChar('?');
|
||||
if (queryBegins <= 0) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
URLParams::Extract(Substring(path, queryBegins + 1), NS_LITERAL_STRING("url"),
|
||||
aParsedURL);
|
||||
|
||||
// If there's no URL as part of the query params, there will be no thumbnail
|
||||
if (aParsedURL.IsVoid()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// PageThumbsProtocol::GetFilePathForURL
|
||||
//
|
||||
// Returns the thumbnail's file path for a given URL
|
||||
|
||||
nsresult PageThumbsProtocol::GetFilePathForURL(nsIURI* aURI,
|
||||
nsIFile** _retval) {
|
||||
nsresult rv;
|
||||
|
||||
// Use PageThumbsStorageService to get the local file path of the screenshot
|
||||
// for the given URL
|
||||
nsAutoString filePathForURL;
|
||||
nsCOMPtr<nsIPageThumbsStorageService> pageThumbsStorage =
|
||||
do_GetService("@mozilla.org/thumbnails/pagethumbs-service;1", &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
// Parse the protocol URL to extract the thumbnail's URL
|
||||
nsAutoString parsedURL;
|
||||
rv = ParseProtocolURL(aURI, parsedURL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
rv = pageThumbsStorage->GetFilePathForURL(parsedURL, filePathForURL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
// Find the local file containing the screenshot
|
||||
nsCOMPtr<nsIFile> filePath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
||||
rv = filePath->InitWithPath(filePathForURL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) return rv;
|
||||
|
||||
filePath.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
//* -*- Mode: C++; tab-width: 8; 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 PageThumbsProtocol_h__
|
||||
#define PageThumbsProtocol_h__
|
||||
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsString.h"
|
||||
|
||||
// {5a4ae9b5-f475-48ae-9dce-0b4c1d347884}
|
||||
#define PAGETHUMBSPROTOCOL_CID \
|
||||
{ \
|
||||
0x5a4ae9b5, 0xf475, 0x48ae, { \
|
||||
0x9d, 0xce, 0x0b, 0x4c, 0x1d, 0x34, 0x78, 0x84 \
|
||||
} \
|
||||
}
|
||||
|
||||
class PageThumbsProtocol final : public nsIProtocolHandler {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
|
||||
private:
|
||||
~PageThumbsProtocol() = default;
|
||||
nsresult GetFilePathForURL(nsIURI* aURI, nsIFile** _retval);
|
||||
nsresult ParseProtocolURL(nsIURI* aURI, nsString& aParsedURL);
|
||||
};
|
||||
|
||||
#endif /* PageThumbsProtocol_h__ */
|
@ -5,13 +5,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{5a4ae9b5-f475-48ae-9dce-0b4c1d347884}',
|
||||
'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-page-thumb'],
|
||||
'type': 'PageThumbsProtocol',
|
||||
'headers': ['/toolkit/components/thumbnails/PageThumbsProtocol.h'],
|
||||
},
|
||||
|
||||
{
|
||||
'cid': '{97943eec-0e48-49ef-b7b7-cf4aa0109bb6}',
|
||||
'contract_ids': ['@mozilla.org/thumbnails/pagethumbs-service;1'],
|
||||
|
@ -18,10 +18,6 @@ EXTRA_JS_MODULES += [
|
||||
'PageThumbUtils.jsm',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'PageThumbsProtocol.cpp'
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIPageThumbsStorageService.idl',
|
||||
]
|
||||
|
@ -37,7 +37,7 @@ function run_test() {
|
||||
);
|
||||
Assert.throws(
|
||||
() => handler.newChannel(badQuery, dummyLoadInfo),
|
||||
/NS_ERROR_MALFORMED_URI/i,
|
||||
/NS_ERROR_NOT_AVAILABLE/i,
|
||||
"moz-page-thumb object with malformed query parameters must not resolve to a file path"
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user