Bug 1354248 - Part 2: Abstract out the IPC message that RemoteStreamGetter uses. r=necko-reviewers,kershaw

This will allow the PageIconProtocolHandler to also use RemoteStreamGetter, using
its own IPC message.

Differential Revision: https://phabricator.services.mozilla.com/D147181
This commit is contained in:
Mike Conley 2022-06-03 15:17:33 +00:00
Родитель 2ff2484102
Коммит 9162e50177
7 изменённых файлов: 81 добавлений и 66 удалений

Просмотреть файл

@ -564,5 +564,11 @@ union GIOChannelCreationArgs
GIOChannelOpenArgs; // For AsyncOpen: the common case.
GIOChannelConnectArgs; // Used for redirected-to channels
};
struct RemoteStreamInfo {
nsIInputStream inputStream;
nsCString contentType;
int64_t contentLength;
};
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -28,6 +28,7 @@
#include "mozilla/net/DNSRequestParent.h"
#include "mozilla/net/ClassifierDummyChannelParent.h"
#include "mozilla/net/IPCTransportProvider.h"
#include "mozilla/net/RemoteStreamGetter.h"
#include "mozilla/net/RequestContextService.h"
#include "mozilla/net/SocketProcessParent.h"
#include "mozilla/net/PSocketProcessBridgeParent.h"
@ -860,15 +861,13 @@ mozilla::ipc::IPCResult NeckoParent::RecvGetPageThumbStream(
inputStreamPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[aResolver](const nsCOMPtr<nsIInputStream>& aStream) {
aResolver(aStream);
},
[aResolver](const RemoteStreamInfo& aInfo) { aResolver(Some(aInfo)); },
[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);
aResolver(Nothing());
});
return IPC_OK();

Просмотреть файл

@ -149,7 +149,7 @@ parent:
/**
* Page thumbnails remote resource loading
*/
async GetPageThumbStream(nsIURI uri) returns (nsIInputStream stream);
async GetPageThumbStream(nsIURI uri) returns (RemoteStreamInfo? info);
child:
/* Predictor Methods */

Просмотреть файл

@ -10,7 +10,6 @@
#include "mozilla/ipc/URIParams.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/RemoteStreamGetter.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ResultExtensions.h"
@ -79,18 +78,16 @@ nsresult PageThumbProtocolHandler::GetFlagsForURI(nsIURI* aURI,
// process.
*aFlags = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE |
URI_NORELATIVE | URI_NOAUTH;
return NS_OK;
}
RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
RefPtr<RemoteStreamPromise> PageThumbProtocolHandler::NewStream(
nsIURI* aChildURI, bool* aTerminateSender) {
MOZ_ASSERT(!IsNeckoChild());
MOZ_ASSERT(NS_IsMainThread());
if (!aChildURI || !aTerminateSender) {
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_INVALID_ARG,
__func__);
return RemoteStreamPromise::CreateAndReject(NS_ERROR_INVALID_ARG, __func__);
}
*aTerminateSender = true;
@ -103,8 +100,8 @@ RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
bool isPageThumbScheme = false;
if (NS_FAILED(aChildURI->SchemeIs(PAGE_THUMB_SCHEME, &isPageThumbScheme)) ||
!isPageThumbScheme) {
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_UNKNOWN_PROTOCOL,
__func__);
return RemoteStreamPromise::CreateAndReject(NS_ERROR_UNKNOWN_PROTOCOL,
__func__);
}
// We should never receive a URI that does not have "thumbnails" as the host.
@ -112,8 +109,7 @@ RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
if (NS_FAILED(aChildURI->GetAsciiHost(host)) ||
!(host.EqualsLiteral(PAGE_THUMB_HOST) ||
host.EqualsLiteral(PLACES_PREVIEWS_HOST))) {
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
__func__);
return RemoteStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED, __func__);
}
// For errors after this point, we want to propagate the error to
@ -127,26 +123,25 @@ RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
nsAutoCString resolvedSpec;
rv = ResolveURI(aChildURI, resolvedSpec);
if (NS_FAILED(rv)) {
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
nsAutoCString resolvedScheme;
rv = net_ExtractURLScheme(resolvedSpec, resolvedScheme);
if (NS_FAILED(rv) || !resolvedScheme.EqualsLiteral("file")) {
return PageThumbStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
__func__);
return RemoteStreamPromise::CreateAndReject(NS_ERROR_UNEXPECTED, __func__);
}
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
if (NS_FAILED(rv)) {
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
nsCOMPtr<nsIURI> resolvedURI;
rv = ioService->NewURI(resolvedSpec, nullptr, nullptr,
getter_AddRefs(resolvedURI));
if (NS_FAILED(rv)) {
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
// We use the system principal to get a file channel for the request,
@ -158,22 +153,34 @@ RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
nsIContentPolicy::TYPE_OTHER);
if (NS_FAILED(rv)) {
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
auto promiseHolder = MakeUnique<MozPromiseHolder<PageThumbStreamPromise>>();
RefPtr<PageThumbStreamPromise> promise = promiseHolder->Ensure(__func__);
auto promiseHolder = MakeUnique<MozPromiseHolder<RemoteStreamPromise>>();
RefPtr<RemoteStreamPromise> promise = promiseHolder->Ensure(__func__);
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1", &rv);
if (NS_FAILED(rv)) {
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
nsAutoCString contentType;
rv = mime->GetTypeFromURI(aChildURI, contentType);
if (NS_FAILED(rv)) {
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
rv = NS_DispatchBackgroundTask(
NS_NewRunnableFunction(
"PageThumbProtocolHandler::NewStream",
[channel, holder = std::move(promiseHolder)]() {
[contentType, channel, holder = std::move(promiseHolder)]() {
nsresult rv;
nsCOMPtr<nsIFileChannel> fileChannel =
do_QueryInterface(channel, &rv);
if (NS_FAILED(rv)) {
holder->Reject(rv, __func__);
return;
}
nsCOMPtr<nsIFile> requestedFile;
@ -191,12 +198,14 @@ RefPtr<PageThumbStreamPromise> PageThumbProtocolHandler::NewStream(
return;
}
holder->Resolve(inputStream, __func__);
RemoteStreamInfo info(inputStream, contentType, -1);
holder->Resolve(std::move(info), __func__);
}),
NS_DISPATCH_EVENT_MAY_BLOCK);
if (NS_FAILED(rv)) {
return PageThumbStreamPromise::CreateAndReject(rv, __func__);
return RemoteStreamPromise::CreateAndReject(rv, __func__);
}
return promise;
@ -339,20 +348,6 @@ nsresult PageThumbProtocolHandler::GetThumbnailPath(const nsACString& aPath,
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, RemoteStreamGetter* aStreamGetter,
@ -361,10 +356,10 @@ void PageThumbProtocolHandler::NewSimpleChannel(
aURI, aLoadinfo, aStreamGetter,
[](nsIStreamListener* listener, nsIChannel* simpleChannel,
RemoteStreamGetter* getter) -> RequestOrReason {
return getter->GetAsync(listener, simpleChannel);
return getter->GetAsync(listener, simpleChannel,
&NeckoChild::SendGetPageThumbStream);
});
SetContentType(aURI, channel);
channel.swap(*aRetVal);
}

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/Result.h"
#include "mozilla/MozPromise.h"
#include "mozilla/net/RemoteStreamGetter.h"
#include "SubstitutingProtocolHandler.h"
#include "nsIInputStream.h"
#include "nsWeakReference.h"
@ -15,9 +16,6 @@
namespace mozilla {
namespace net {
using PageThumbStreamPromise =
mozilla::MozPromise<nsCOMPtr<nsIInputStream>, nsresult, false>;
class RemoteStreamGetter;
class PageThumbProtocolHandler final
@ -43,12 +41,12 @@ class PageThumbProtocolHandler final
* 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
* @return RemoteStreamPromise
* The RemoteStreamPromise will resolve with an RemoteStreamInfo on
* success, and reject with an nsresult on failure.
*/
RefPtr<PageThumbStreamPromise> NewStream(nsIURI* aChildURI,
bool* aTerminateSender);
RefPtr<RemoteStreamPromise> NewStream(nsIURI* aChildURI,
bool* aTerminateSender);
protected:
~PageThumbProtocolHandler() = default;
@ -113,9 +111,6 @@ class PageThumbProtocolHandler final
// 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,
RemoteStreamGetter* aStreamGetter,

Просмотреть файл

@ -5,7 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RemoteStreamGetter.h"
#include "mozilla/MozPromise.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ResultExtensions.h"
@ -25,8 +25,10 @@ RemoteStreamGetter::RemoteStreamGetter(nsIURI* aURI, nsILoadInfo* aLoadInfo)
// Request an input stream from the parent.
RequestOrReason RemoteStreamGetter::GetAsync(nsIStreamListener* aListener,
nsIChannel* aChannel) {
nsIChannel* aChannel,
Method aMethod) {
MOZ_ASSERT(IsNeckoChild());
MOZ_ASSERT(aMethod);
mListener = aListener;
mChannel = aChannel;
@ -35,14 +37,11 @@ RequestOrReason RemoteStreamGetter::GetAsync(nsIStreamListener* aListener,
RefPtr<RemoteStreamGetter> self = this;
// Request an input stream for this moz-page-thumb URI.
gNeckoChild->SendGetPageThumbStream(mURI)->Then(
(gNeckoChild->*aMethod)(mURI)->Then(
GetMainThreadSerialEventTarget(), __func__,
[self](const RefPtr<nsIInputStream>& stream) {
self->OnStream(do_AddRef(stream));
},
[self](const Maybe<RemoteStreamInfo>& info) { self->OnStream(info); },
[self](const mozilla::ipc::ResponseRejectReason) {
self->OnStream(nullptr);
self->OnStream(Nothing());
});
return RequestOrCancelable(WrapNotNull(cancelableRequest));
}
@ -77,27 +76,33 @@ void RemoteStreamGetter::CancelRequest(nsIStreamListener* aListener,
}
// Handle an input stream sent from the parent.
void RemoteStreamGetter::OnStream(already_AddRefed<nsIInputStream> aStream) {
void RemoteStreamGetter::OnStream(const Maybe<RemoteStreamInfo>& aStreamInfo) {
MOZ_ASSERT(IsNeckoChild());
MOZ_ASSERT(mChannel);
MOZ_ASSERT(mListener);
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
nsCOMPtr<nsIChannel> channel = std::move(mChannel);
// We must keep an owning reference to the listener until we pass it on
// to AsyncRead.
nsCOMPtr<nsIStreamListener> listener = mListener.forget();
if (aStreamInfo.isNothing()) {
// The parent didn't send us back a stream.
CancelRequest(listener, channel, NS_ERROR_FILE_ACCESS_DENIED);
return;
}
if (mCanceled) {
// The channel that has created this stream getter has been canceled.
CancelRequest(listener, channel, mStatus);
return;
}
nsCOMPtr<nsIInputStream> stream = std::move(aStreamInfo.ref().inputStream());
if (!stream) {
// The parent didn't send us back a stream.
CancelRequest(listener, channel, NS_ERROR_FILE_ACCESS_DENIED);
// We somehow failed to get a stream, so just cancel the request.
CancelRequest(listener, channel, mStatus);
return;
}
@ -110,6 +115,9 @@ void RemoteStreamGetter::OnStream(already_AddRefed<nsIInputStream> aStream) {
return;
}
channel->SetContentType(aStreamInfo.ref().contentType());
channel->SetContentLength(aStreamInfo.ref().contentLength());
rv = pump->AsyncRead(listener);
if (NS_FAILED(rv)) {
CancelRequest(listener, channel, rv);

Просмотреть файл

@ -7,16 +7,27 @@
#ifndef RemoteStreamGetter_h___
#define RemoteStreamGetter_h___
#include "LoadInfo.h"
#include "nsIChannel.h"
#include "nsIInputStreamPump.h"
#include "nsIStreamListener.h"
#include "nsIInputStream.h"
#include "nsICancelable.h"
#include "SimpleChannel.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/Maybe.h"
class nsILoadInfo;
namespace mozilla {
namespace net {
using RemoteStreamPromise =
mozilla::MozPromise<RemoteStreamInfo, nsresult, false>;
using Method = RefPtr<
MozPromise<Maybe<RemoteStreamInfo>, ipc::ResponseRejectReason, true>> (
PNeckoChild::*)(nsIURI*);
/**
* Helper class used with SimpleChannel to asynchronously obtain an input
* stream and metadata from the parent for a remote protocol load from the
@ -30,10 +41,11 @@ class RemoteStreamGetter final : public nsICancelable {
RemoteStreamGetter(nsIURI* aURI, nsILoadInfo* aLoadInfo);
// Get an input stream from the parent asynchronously.
RequestOrReason GetAsync(nsIStreamListener* aListener, nsIChannel* aChannel);
RequestOrReason GetAsync(nsIStreamListener* aListener, nsIChannel* aChannel,
Method aMethod);
// Handle an input stream being returned from the parent
void OnStream(already_AddRefed<nsIInputStream> aStream);
void OnStream(const Maybe<RemoteStreamInfo>& aStreamInfo);
static void CancelRequest(nsIStreamListener* aListener, nsIChannel* aChannel,
nsresult aResult);