mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 1666725 - Make gvfs e10s compatible r=valentin,necko-reviewers
Split channel into parent/child to be able to use dbus in the content sandbox Differential Revision: https://phabricator.services.mozilla.com/D92206
This commit is contained in:
parent
f3afaa1ce8
commit
86e1612919
@ -666,6 +666,8 @@ VIRTUAL_CALL_CLASSES = set(
|
||||
("PColorPicker", "child"),
|
||||
("PColorPicker", "parent"),
|
||||
("PDataChannel", "child"),
|
||||
("PGIOChannel", "child"),
|
||||
("PGIOChannel", "parent"),
|
||||
("PFileChannel", "child"),
|
||||
("PFilePicker", "child"),
|
||||
("PFunctionBroker", "child"),
|
||||
|
@ -543,5 +543,29 @@ struct SpeculativeConnectionOverriderArgs {
|
||||
bool allow1918;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIO IPDL structs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct GIOChannelOpenArgs
|
||||
{
|
||||
URIParams uri;
|
||||
uint64_t startPos;
|
||||
nsCString entityID;
|
||||
IPCStream? uploadStream;
|
||||
LoadInfoArgs? loadInfo;
|
||||
uint32_t loadFlags;
|
||||
};
|
||||
|
||||
struct GIOChannelConnectArgs
|
||||
{
|
||||
uint32_t channelId;
|
||||
};
|
||||
|
||||
union GIOChannelCreationArgs
|
||||
{
|
||||
GIOChannelOpenArgs; // For AsyncOpen: the common case.
|
||||
GIOChannelConnectArgs; // Used for redirected-to channels
|
||||
};
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/net/CookieServiceChild.h"
|
||||
#include "mozilla/net/FTPChannelChild.h"
|
||||
#include "mozilla/net/DataChannelChild.h"
|
||||
#include "mozilla/net/GIOChannelChild.h"
|
||||
#include "mozilla/net/FileChannelChild.h"
|
||||
#include "mozilla/net/WebSocketChannelChild.h"
|
||||
#include "mozilla/net/WebSocketEventListenerChild.h"
|
||||
@ -141,6 +142,22 @@ bool NeckoChild::DeallocPFTPChannelChild(PFTPChannelChild* channel) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PGIOChannelChild* NeckoChild::AllocPGIOChannelChild(
|
||||
PBrowserChild* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const GIOChannelCreationArgs& aOpenArgs) {
|
||||
// We don't allocate here: see GIOChannelChild::AsyncOpen()
|
||||
MOZ_CRASH("AllocPGIOChannelChild should not be called");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NeckoChild::DeallocPGIOChannelChild(PGIOChannelChild* channel) {
|
||||
MOZ_ASSERT(IsNeckoChild(), "DeallocPGIOChannelChild called by non-child!");
|
||||
|
||||
GIOChannelChild* child = static_cast<GIOChannelChild*>(channel);
|
||||
child->ReleaseIPDLReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
PCookieServiceChild* NeckoChild::AllocPCookieServiceChild() {
|
||||
// We don't allocate here: see CookieService::GetSingleton()
|
||||
MOZ_ASSERT_UNREACHABLE("AllocPCookieServiceChild should not be called");
|
||||
|
@ -42,6 +42,12 @@ class NeckoChild : public PNeckoChild {
|
||||
PBrowserChild* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const FTPChannelCreationArgs& aOpenArgs);
|
||||
bool DeallocPFTPChannelChild(PFTPChannelChild*);
|
||||
|
||||
PGIOChannelChild* AllocPGIOChannelChild(
|
||||
PBrowserChild* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const GIOChannelCreationArgs& aOpenArgs);
|
||||
bool DeallocPGIOChannelChild(PGIOChannelChild*);
|
||||
|
||||
PWebSocketChild* AllocPWebSocketChild(PBrowserChild*,
|
||||
const SerializedLoadContext&,
|
||||
const uint32_t&);
|
||||
@ -81,7 +87,7 @@ class NeckoChild : public PNeckoChild {
|
||||
const Maybe<LoadInfoArgs>& aLoadInfo);
|
||||
|
||||
bool DeallocPClassifierDummyChannelChild(
|
||||
PClassifierDummyChannelChild* aChannel);
|
||||
PClassifierDummyChannelChild* aActor);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/net/WebSocketChannelParent.h"
|
||||
#include "mozilla/net/WebSocketEventListenerParent.h"
|
||||
#include "mozilla/net/DataChannelParent.h"
|
||||
#include "mozilla/net/GIOChannelParent.h"
|
||||
#include "mozilla/net/DocumentChannelParent.h"
|
||||
#include "mozilla/net/SimpleChannelParent.h"
|
||||
#include "mozilla/net/AltDataOutputStreamParent.h"
|
||||
@ -408,6 +409,56 @@ mozilla::ipc::IPCResult NeckoParent::RecvPDataChannelConstructor(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
|
||||
const GIOChannelCreationArgs& aArgs) {
|
||||
if (aArgs.type() != GIOChannelCreationArgs::TGIOChannelOpenArgs) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GIOChannelOpenArgs& args = aArgs.get_GIOChannelOpenArgs();
|
||||
return GetRequestingPrincipal(args.loadInfo());
|
||||
}
|
||||
|
||||
PGIOChannelParent* NeckoParent::AllocPGIOChannelParent(
|
||||
PBrowserParent* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const GIOChannelCreationArgs& aOpenArgs) {
|
||||
nsCOMPtr<nsIPrincipal> requestingPrincipal =
|
||||
GetRequestingPrincipal(aOpenArgs);
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
const char* error = CreateChannelLoadContext(
|
||||
aBrowser, Manager(), aSerialized, requestingPrincipal, loadContext);
|
||||
if (error) {
|
||||
printf_stderr(
|
||||
"NeckoParent::AllocPGIOChannelParent: "
|
||||
"FATAL error: %s: KILLING CHILD PROCESS\n",
|
||||
error);
|
||||
return nullptr;
|
||||
}
|
||||
PBOverrideStatus overrideStatus =
|
||||
PBOverrideStatusFromLoadContext(aSerialized);
|
||||
GIOChannelParent* p = new GIOChannelParent(BrowserParent::GetFrom(aBrowser),
|
||||
loadContext, overrideStatus);
|
||||
p->AddRef();
|
||||
return p;
|
||||
}
|
||||
|
||||
bool NeckoParent::DeallocPGIOChannelParent(PGIOChannelParent* channel) {
|
||||
GIOChannelParent* p = static_cast<GIOChannelParent*>(channel);
|
||||
p->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult NeckoParent::RecvPGIOChannelConstructor(
|
||||
PGIOChannelParent* actor, PBrowserParent* aBrowser,
|
||||
const SerializedLoadContext& aSerialized,
|
||||
const GIOChannelCreationArgs& aOpenArgs) {
|
||||
GIOChannelParent* p = static_cast<GIOChannelParent*>(actor);
|
||||
DebugOnly<bool> rv = p->Init(aOpenArgs);
|
||||
MOZ_ASSERT(rv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PSimpleChannelParent* NeckoParent::AllocPSimpleChannelParent(
|
||||
const uint32_t& channelId) {
|
||||
RefPtr<SimpleChannelParent> p = new SimpleChannelParent();
|
||||
|
@ -153,7 +153,7 @@ class NeckoParent : public PNeckoParent {
|
||||
const uint16_t& aType, const OriginAttributes& aOriginAttributes,
|
||||
const uint32_t& aFlags);
|
||||
virtual mozilla::ipc::IPCResult RecvPDNSRequestConstructor(
|
||||
PDNSRequestParent* actor, const nsCString& hostName,
|
||||
PDNSRequestParent* actor, const nsCString& aHost,
|
||||
const nsCString& trrServer, const uint16_t& type,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const uint32_t& flags) override;
|
||||
@ -177,8 +177,18 @@ class NeckoParent : public PNeckoParent {
|
||||
virtual mozilla::ipc::IPCResult RecvPDataChannelConstructor(
|
||||
PDataChannelParent* aActor, const uint32_t& channelId) override;
|
||||
|
||||
PGIOChannelParent* AllocPGIOChannelParent(
|
||||
PBrowserParent* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const GIOChannelCreationArgs& aOpenArgs);
|
||||
bool DeallocPGIOChannelParent(PGIOChannelParent* channel);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPGIOChannelConstructor(
|
||||
PGIOChannelParent* aActor, PBrowserParent* aBrowser,
|
||||
const SerializedLoadContext& aSerialized,
|
||||
const GIOChannelCreationArgs& aOpenArgs) override;
|
||||
|
||||
PSimpleChannelParent* AllocPSimpleChannelParent(const uint32_t& channelId);
|
||||
bool DeallocPSimpleChannelParent(PSimpleChannelParent* parent);
|
||||
bool DeallocPSimpleChannelParent(PSimpleChannelParent* actor);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPSimpleChannelConstructor(
|
||||
PSimpleChannelParent* aActor, const uint32_t& channelId) override;
|
||||
@ -232,7 +242,7 @@ class NeckoParent : public PNeckoParent {
|
||||
const Maybe<LoadInfoArgs>& aLoadInfo);
|
||||
|
||||
bool DeallocPClassifierDummyChannelParent(
|
||||
PClassifierDummyChannelParent* aParent);
|
||||
PClassifierDummyChannelParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPClassifierDummyChannelConstructor(
|
||||
PClassifierDummyChannelParent* aActor, nsIURI* aURI,
|
||||
|
@ -10,6 +10,7 @@ include protocol PHttpChannel;
|
||||
include protocol PCookieService;
|
||||
include protocol PBrowser;
|
||||
include protocol PFTPChannel;
|
||||
include protocol PGIOChannel;
|
||||
include protocol PWebSocket;
|
||||
include protocol PWebSocketEventListener;
|
||||
include protocol PTCPSocket;
|
||||
@ -60,6 +61,7 @@ nested(upto inside_cpow) sync protocol PNecko
|
||||
manages PUDPSocket;
|
||||
manages PDNSRequest;
|
||||
manages PDataChannel;
|
||||
manages PGIOChannel;
|
||||
manages PSimpleChannel;
|
||||
manages PFileChannel;
|
||||
manages PTransportProvider;
|
||||
@ -112,6 +114,7 @@ parent:
|
||||
* the parent and the child when we're redirecting to a data: URI.
|
||||
*/
|
||||
async PDataChannel(uint32_t channelId);
|
||||
async PGIOChannel(nullable PBrowser browser, SerializedLoadContext loadContext, GIOChannelCreationArgs args);
|
||||
async PSimpleChannel(uint32_t channelId);
|
||||
async PFileChannel(uint32_t channelId);
|
||||
|
||||
|
468
netwerk/protocol/gio/GIOChannelChild.cpp
Normal file
468
netwerk/protocol/gio/GIOChannelChild.cpp
Normal file
@ -0,0 +1,468 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=4 sw=2 sts=2 et 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 "mozilla/net/NeckoChild.h"
|
||||
#include "GIOChannelChild.h"
|
||||
#include "nsGIOProtocolHandler.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIBrowserChild.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "SerializedLoadContext.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "nsIURIMutator.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "SerializedLoadContext.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
using mozilla::dom::ContentChild;
|
||||
|
||||
namespace mozilla {
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gGIOLog, mozilla::LogLevel::Debug, args)
|
||||
namespace net {
|
||||
|
||||
GIOChannelChild::GIOChannelChild(nsIURI* aUri)
|
||||
: mIPCOpen(false),
|
||||
mEventQ(new ChannelEventQueue(static_cast<nsIChildChannel*>(this))),
|
||||
mCanceled(false),
|
||||
mSuspendCount(0),
|
||||
mIsPending(false),
|
||||
mStartPos(0),
|
||||
mSuspendSent(false) {
|
||||
SetURI(aUri);
|
||||
// We could support thread retargeting, but as long as we're being driven by
|
||||
// IPDL on the main thread it doesn't buy us anything.
|
||||
DisallowThreadRetargeting();
|
||||
}
|
||||
|
||||
void GIOChannelChild::AddIPDLReference() {
|
||||
MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
|
||||
mIPCOpen = true;
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void GIOChannelChild::ReleaseIPDLReference() {
|
||||
MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
|
||||
mIPCOpen = false;
|
||||
Release();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelChild::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(GIOChannelChild, nsBaseChannel, nsIChildChannel)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::AsyncOpen(nsIStreamListener* aListener) {
|
||||
nsCOMPtr<nsIStreamListener> listener = aListener;
|
||||
nsresult rv =
|
||||
nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
LOG(("GIOChannelChild::AsyncOpen [this=%p]\n", this));
|
||||
|
||||
NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(
|
||||
!static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown(),
|
||||
NS_ERROR_FAILURE);
|
||||
NS_ENSURE_ARG_POINTER(listener);
|
||||
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
|
||||
// Port checked in parent, but duplicate here so we can return with error
|
||||
// immediately, as we've done since before e10s.
|
||||
rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
|
||||
// because in the child ipdl,
|
||||
// a typedef URI is defined...
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mozilla::dom::BrowserChild* browserChild = nullptr;
|
||||
nsCOMPtr<nsIBrowserChild> iBrowserChild;
|
||||
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
|
||||
NS_GET_IID(nsIBrowserChild),
|
||||
getter_AddRefs(iBrowserChild));
|
||||
GetCallback(iBrowserChild);
|
||||
if (iBrowserChild) {
|
||||
browserChild =
|
||||
static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
|
||||
}
|
||||
|
||||
mListener = listener;
|
||||
|
||||
// add ourselves to the load group.
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->AddRequest(this, nullptr);
|
||||
}
|
||||
|
||||
mozilla::ipc::AutoIPCStream autoStream;
|
||||
autoStream.Serialize(mUploadStream,
|
||||
static_cast<ContentChild*>(gNeckoChild->Manager()));
|
||||
|
||||
uint32_t loadFlags = 0;
|
||||
GetLoadFlags(&loadFlags);
|
||||
|
||||
GIOChannelOpenArgs openArgs;
|
||||
SerializeURI(nsBaseChannel::URI(), openArgs.uri());
|
||||
openArgs.startPos() = mStartPos;
|
||||
openArgs.entityID() = mEntityID;
|
||||
openArgs.uploadStream() = autoStream.TakeOptionalValue();
|
||||
openArgs.loadFlags() = loadFlags;
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = LoadInfo();
|
||||
rv = mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &openArgs.loadInfo());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This must happen before the constructor message is sent.
|
||||
SetupNeckoTarget();
|
||||
|
||||
gNeckoChild->SendPGIOChannelConstructor(
|
||||
this, browserChild, IPC::SerializedLoadContext(this), openArgs);
|
||||
|
||||
// The socket transport layer in the chrome process now has a logical ref to
|
||||
// us until OnStopRequest is called.
|
||||
AddIPDLReference();
|
||||
|
||||
mIsPending = true;
|
||||
mWasOpened = true;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::IsPending(bool* aResult) {
|
||||
*aResult = mIsPending;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GIOChannelChild::OpenContentStream(bool aAsync,
|
||||
nsIInputStream** aStream,
|
||||
nsIChannel** aChannel) {
|
||||
MOZ_CRASH("GIOChannel*Child* should never have OpenContentStream called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelChild::RecvOnStartRequest(
|
||||
const nsresult& aChannelStatus, const int64_t& aContentLength,
|
||||
const nsCString& aContentType, const nsCString& aEntityID,
|
||||
const URIParams& aURI) {
|
||||
LOG(("GIOChannelChild::RecvOnStartRequest [this=%p]\n", this));
|
||||
mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
|
||||
this, [self = UnsafePtr<GIOChannelChild>(this), aChannelStatus,
|
||||
aContentLength, aContentType, aEntityID, aURI]() {
|
||||
self->DoOnStartRequest(aChannelStatus, aContentLength, aContentType,
|
||||
aEntityID, aURI);
|
||||
}));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void GIOChannelChild::DoOnStartRequest(const nsresult& aChannelStatus,
|
||||
const int64_t& aContentLength,
|
||||
const nsCString& aContentType,
|
||||
const nsCString& aEntityID,
|
||||
const URIParams& aURI) {
|
||||
LOG(("GIOChannelChild::DoOnStartRequest [this=%p]\n", this));
|
||||
if (!mCanceled && NS_SUCCEEDED(mStatus)) {
|
||||
mStatus = aChannelStatus;
|
||||
}
|
||||
|
||||
mContentLength = aContentLength;
|
||||
SetContentType(aContentType);
|
||||
mEntityID = aEntityID;
|
||||
|
||||
nsCString spec;
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
nsresult rv = uri->GetSpec(spec);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Changes nsBaseChannel::URI()
|
||||
rv = NS_MutateURI(mURI).SetSpec(spec).Finalize(mURI);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
}
|
||||
|
||||
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
|
||||
rv = mListener->OnStartRequest(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelChild::RecvOnDataAvailable(
|
||||
const nsresult& aChannelStatus, const nsCString& aData,
|
||||
const uint64_t& aOffset, const uint32_t& aCount) {
|
||||
LOG(("GIOChannelChild::RecvOnDataAvailable [this=%p]\n", this));
|
||||
mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
|
||||
this, [self = UnsafePtr<GIOChannelChild>(this), aChannelStatus, aData,
|
||||
aOffset, aCount]() {
|
||||
self->DoOnDataAvailable(aChannelStatus, aData, aOffset, aCount);
|
||||
}));
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void GIOChannelChild::DoOnDataAvailable(const nsresult& aChannelStatus,
|
||||
const nsCString& aData,
|
||||
const uint64_t& aOffset,
|
||||
const uint32_t& aCount) {
|
||||
LOG(("GIOChannelChild::DoOnDataAvailable [this=%p]\n", this));
|
||||
|
||||
if (!mCanceled && NS_SUCCEEDED(mStatus)) {
|
||||
mStatus = aChannelStatus;
|
||||
}
|
||||
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: the OnDataAvailable contract requires the client to read all the data
|
||||
// in the inputstream. This code relies on that ('data' will go away after
|
||||
// this function). Apparently the previous, non-e10s behavior was to actually
|
||||
// support only reading part of the data, allowing later calls to read the
|
||||
// rest.
|
||||
nsCOMPtr<nsIInputStream> stringStream;
|
||||
nsresult rv =
|
||||
NS_NewByteInputStream(getter_AddRefs(stringStream),
|
||||
Span(aData).To(aCount), NS_ASSIGNMENT_DEPEND);
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
|
||||
rv = mListener->OnDataAvailable(this, stringStream, aOffset, aCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
}
|
||||
stringStream->Close();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelChild::RecvOnStopRequest(
|
||||
const nsresult& aChannelStatus) {
|
||||
LOG(("GIOChannelChild::RecvOnStopRequest [this=%p status=%" PRIx32 "]\n",
|
||||
this, static_cast<uint32_t>(aChannelStatus)));
|
||||
|
||||
mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
|
||||
this, [self = UnsafePtr<GIOChannelChild>(this), aChannelStatus]() {
|
||||
self->DoOnStopRequest(aChannelStatus);
|
||||
}));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void GIOChannelChild::DoOnStopRequest(const nsresult& aChannelStatus) {
|
||||
LOG(("GIOChannelChild::DoOnStopRequest [this=%p status=%" PRIx32 "]\n", this,
|
||||
static_cast<uint32_t>(aChannelStatus)));
|
||||
|
||||
if (!mCanceled) {
|
||||
mStatus = aChannelStatus;
|
||||
}
|
||||
|
||||
{ // Ensure that all queued ipdl events are dispatched before
|
||||
// we initiate protocol deletion below.
|
||||
mIsPending = false;
|
||||
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
|
||||
(void)mListener->OnStopRequest(this, aChannelStatus);
|
||||
|
||||
mListener = nullptr;
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
|
||||
}
|
||||
}
|
||||
|
||||
// This calls NeckoChild::DeallocPGIOChannelChild(), which deletes |this| if
|
||||
// IPDL holds the last reference. Don't rely on |this| existing after here!
|
||||
Send__delete__(this);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelChild::RecvFailedAsyncOpen(
|
||||
const nsresult& aStatusCode) {
|
||||
LOG(("GIOChannelChild::RecvFailedAsyncOpen [this=%p status=%" PRIx32 "]\n",
|
||||
this, static_cast<uint32_t>(aStatusCode)));
|
||||
mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
|
||||
this, [self = UnsafePtr<GIOChannelChild>(this), aStatusCode]() {
|
||||
self->DoFailedAsyncOpen(aStatusCode);
|
||||
}));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void GIOChannelChild::DoFailedAsyncOpen(const nsresult& aStatusCode) {
|
||||
LOG(("GIOChannelChild::DoFailedAsyncOpen [this=%p status=%" PRIx32 "]\n",
|
||||
this, static_cast<uint32_t>(aStatusCode)));
|
||||
mStatus = aStatusCode;
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aStatusCode);
|
||||
}
|
||||
|
||||
if (mListener) {
|
||||
mListener->OnStartRequest(this);
|
||||
mIsPending = false;
|
||||
mListener->OnStopRequest(this, aStatusCode);
|
||||
} else {
|
||||
mIsPending = false;
|
||||
}
|
||||
|
||||
mListener = nullptr;
|
||||
|
||||
if (mIPCOpen) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelChild::RecvDeleteSelf() {
|
||||
mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
|
||||
this,
|
||||
[self = UnsafePtr<GIOChannelChild>(this)]() { self->DoDeleteSelf(); }));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void GIOChannelChild::DoDeleteSelf() {
|
||||
if (mIPCOpen) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelChild::nsIResumableChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::Cancel(nsresult aStatus) {
|
||||
LOG(("GIOChannelChild::Cancel [this=%p]\n", this));
|
||||
|
||||
if (mCanceled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCanceled = true;
|
||||
mStatus = aStatus;
|
||||
if (mIPCOpen) {
|
||||
SendCancel(aStatus);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::Suspend() {
|
||||
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
LOG(("GIOChannelChild::Suspend [this=%p]\n", this));
|
||||
|
||||
// SendSuspend only once, when suspend goes from 0 to 1.
|
||||
if (!mSuspendCount++) {
|
||||
SendSuspend();
|
||||
mSuspendSent = true;
|
||||
}
|
||||
mEventQ->Suspend();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::Resume() {
|
||||
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
LOG(("GIOChannelChild::Resume [this=%p]\n", this));
|
||||
|
||||
// SendResume only once, when suspend count drops to 0.
|
||||
if (!--mSuspendCount && mSuspendSent) {
|
||||
SendResume();
|
||||
}
|
||||
mEventQ->Resume();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelChild::nsIChildChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::ConnectParent(uint32_t aId) {
|
||||
NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(
|
||||
!static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown(),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
LOG(("GIOChannelChild::ConnectParent [this=%p]\n", this));
|
||||
|
||||
mozilla::dom::BrowserChild* browserChild = nullptr;
|
||||
nsCOMPtr<nsIBrowserChild> iBrowserChild;
|
||||
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
|
||||
NS_GET_IID(nsIBrowserChild),
|
||||
getter_AddRefs(iBrowserChild));
|
||||
GetCallback(iBrowserChild);
|
||||
if (iBrowserChild) {
|
||||
browserChild =
|
||||
static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
|
||||
}
|
||||
|
||||
// This must happen before the constructor message is sent.
|
||||
SetupNeckoTarget();
|
||||
|
||||
// The socket transport in the chrome process now holds a logical ref to us
|
||||
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
|
||||
AddIPDLReference();
|
||||
|
||||
GIOChannelConnectArgs connectArgs(aId);
|
||||
|
||||
if (!gNeckoChild->SendPGIOChannelConstructor(
|
||||
this, browserChild, IPC::SerializedLoadContext(this), connectArgs)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelChild::CompleteRedirectSetup(nsIStreamListener* aListener) {
|
||||
LOG(("GIOChannelChild::CompleteRedirectSetup [this=%p]\n", this));
|
||||
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
|
||||
mIsPending = true;
|
||||
mWasOpened = true;
|
||||
mListener = aListener;
|
||||
|
||||
// add ourselves to the load group.
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->AddRequest(this, nullptr);
|
||||
}
|
||||
|
||||
// We already have an open IPDL connection to the parent. If on-modify-request
|
||||
// listeners or load group observers canceled us, let the parent handle it
|
||||
// and send it back to us naturally.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void GIOChannelChild::SetupNeckoTarget() {
|
||||
if (mNeckoTarget) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = LoadInfo();
|
||||
mNeckoTarget =
|
||||
nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Network);
|
||||
if (!mNeckoTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
gNeckoChild->SetEventTargetForActor(this, mNeckoTarget);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
109
netwerk/protocol/gio/GIOChannelChild.h
Normal file
109
netwerk/protocol/gio/GIOChannelChild.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=4 sw=2 sts=2 et 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/. */
|
||||
|
||||
#ifndef NS_GIOCHANNELCHILD_H
|
||||
#define NS_GIOCHANNELCHILD_H
|
||||
|
||||
#include "mozilla/net/PGIOChannelChild.h"
|
||||
#include "mozilla/net/ChannelEventQueue.h"
|
||||
#include "nsBaseChannel.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIProxiedChannel.h"
|
||||
#include "nsIResumableChannel.h"
|
||||
#include "nsIChildChannel.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
class nsIEventTarget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class GIOChannelChild final : public PGIOChannelChild,
|
||||
public nsBaseChannel,
|
||||
public nsIChildChannel {
|
||||
public:
|
||||
using nsIStreamListener = ::nsIStreamListener;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICHILDCHANNEL
|
||||
|
||||
NS_IMETHOD Cancel(nsresult aStatus) override;
|
||||
NS_IMETHOD Suspend() override;
|
||||
NS_IMETHOD Resume() override;
|
||||
|
||||
explicit GIOChannelChild(nsIURI* uri);
|
||||
|
||||
void AddIPDLReference();
|
||||
void ReleaseIPDLReference();
|
||||
|
||||
NS_IMETHOD AsyncOpen(nsIStreamListener* aListener) override;
|
||||
|
||||
// Note that we handle this ourselves, overriding the nsBaseChannel
|
||||
// default behavior, in order to be e10s-friendly.
|
||||
NS_IMETHOD IsPending(bool* aResult) override;
|
||||
|
||||
nsresult OpenContentStream(bool aAsync, nsIInputStream** aStream,
|
||||
nsIChannel** aChannel) override;
|
||||
|
||||
bool IsSuspended() const;
|
||||
|
||||
protected:
|
||||
virtual ~GIOChannelChild() = default;
|
||||
|
||||
mozilla::ipc::IPCResult RecvOnStartRequest(const nsresult& aChannelStatus,
|
||||
const int64_t& aContentLength,
|
||||
const nsCString& aContentType,
|
||||
const nsCString& aEntityID,
|
||||
const URIParams& aURI) override;
|
||||
mozilla::ipc::IPCResult RecvOnDataAvailable(const nsresult& aChannelStatus,
|
||||
const nsCString& aData,
|
||||
const uint64_t& aOffset,
|
||||
const uint32_t& aCount) override;
|
||||
mozilla::ipc::IPCResult RecvOnStopRequest(
|
||||
const nsresult& aChannelStatus) override;
|
||||
mozilla::ipc::IPCResult RecvFailedAsyncOpen(
|
||||
const nsresult& aStatusCode) override;
|
||||
mozilla::ipc::IPCResult RecvDeleteSelf() override;
|
||||
|
||||
void DoOnStartRequest(const nsresult& aChannelStatus,
|
||||
const int64_t& aContentLength,
|
||||
const nsCString& aContentType,
|
||||
const nsCString& aEntityID, const URIParams& aURI);
|
||||
void DoOnDataAvailable(const nsresult& aChannelStatus, const nsCString& aData,
|
||||
const uint64_t& aOffset, const uint32_t& aCount);
|
||||
void DoOnStopRequest(const nsresult& aChannelStatus);
|
||||
void DoFailedAsyncOpen(const nsresult& aStatusCode);
|
||||
void DoDeleteSelf();
|
||||
|
||||
void SetupNeckoTarget() override;
|
||||
|
||||
friend class NeckoTargetChannelFunctionEvent;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIInputStream> mUploadStream;
|
||||
|
||||
bool mIPCOpen;
|
||||
const RefPtr<ChannelEventQueue> mEventQ;
|
||||
|
||||
bool mCanceled = false;
|
||||
uint32_t mSuspendCount;
|
||||
bool mIsPending = false;
|
||||
|
||||
uint64_t mStartPos;
|
||||
nsCString mEntityID;
|
||||
|
||||
// Set if SendSuspend is called. Determines if SendResume is needed when
|
||||
// diverting callbacks to parent.
|
||||
bool mSuspendSent;
|
||||
};
|
||||
|
||||
inline bool GIOChannelChild::IsSuspended() const { return mSuspendCount != 0; }
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* NS_GIOCHANNELCHILD_H */
|
323
netwerk/protocol/gio/GIOChannelParent.cpp
Normal file
323
netwerk/protocol/gio/GIOChannelParent.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=4 sw=2 sts=2 et 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 "GIOChannelParent.h"
|
||||
#include "nsGIOProtocolHandler.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/net/NeckoParent.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "nsIAuthPrompt.h"
|
||||
#include "nsIAuthPromptProvider.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gGIOLog, mozilla::LogLevel::Debug, args)
|
||||
namespace net {
|
||||
|
||||
GIOChannelParent::GIOChannelParent(dom::BrowserParent* aIframeEmbedding,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus)
|
||||
: mLoadContext(aLoadContext),
|
||||
mPBOverride(aOverrideStatus),
|
||||
mBrowserParent(aIframeEmbedding) {
|
||||
mEventQ = new ChannelEventQueue(static_cast<nsIParentChannel*>(this));
|
||||
}
|
||||
|
||||
void GIOChannelParent::ActorDestroy(ActorDestroyReason why) {
|
||||
// We may still have refcount>0 if the channel hasn't called OnStopRequest
|
||||
// yet, but we must not send any more msgs to child.
|
||||
mIPCClosed = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelParent::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMPL_ISUPPORTS(GIOChannelParent, nsIStreamListener, nsIParentChannel,
|
||||
nsIInterfaceRequestor, nsIRequestObserver)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelParent methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool GIOChannelParent::Init(const GIOChannelCreationArgs& aOpenArgs) {
|
||||
switch (aOpenArgs.type()) {
|
||||
case GIOChannelCreationArgs::TGIOChannelOpenArgs: {
|
||||
const GIOChannelOpenArgs& a = aOpenArgs.get_GIOChannelOpenArgs();
|
||||
return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream(),
|
||||
a.loadInfo(), a.loadFlags());
|
||||
}
|
||||
case GIOChannelCreationArgs::TGIOChannelConnectArgs: {
|
||||
const GIOChannelConnectArgs& cArgs =
|
||||
aOpenArgs.get_GIOChannelConnectArgs();
|
||||
return ConnectChannel(cArgs.channelId());
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unknown open type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GIOChannelParent::DoAsyncOpen(const URIParams& aURI,
|
||||
const uint64_t& aStartPos,
|
||||
const nsCString& aEntityID,
|
||||
const Maybe<IPCStream>& aUploadStream,
|
||||
const Maybe<LoadInfoArgs>& aLoadInfoArgs,
|
||||
const uint32_t& aLoadFlags) {
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
if (!uri) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
LOG(("GIOChannelParent DoAsyncOpen [this=%p uri=%s]\n", this,
|
||||
uri->GetSpecOrDefault().get()));
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs,
|
||||
getter_AddRefs(loadInfo));
|
||||
if (NS_FAILED(rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
OriginAttributes attrs;
|
||||
rv = loadInfo->GetOriginAttributes(&attrs);
|
||||
if (NS_FAILED(rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> chan;
|
||||
rv = NS_NewChannelInternal(getter_AddRefs(chan), uri, loadInfo, nullptr,
|
||||
nullptr, nullptr, aLoadFlags, ios);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
mChannel = chan;
|
||||
|
||||
nsIChannel* gioChan = static_cast<nsIChannel*>(mChannel.get());
|
||||
|
||||
rv = gioChan->AsyncOpen(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GIOChannelParent::ConnectChannel(const uint64_t& channelId) {
|
||||
nsresult rv;
|
||||
|
||||
LOG(("Looking for a registered channel [this=%p, id=%" PRIx64 "]", this,
|
||||
channelId));
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mChannel = channel;
|
||||
}
|
||||
|
||||
LOG((" found channel %p, rv=%08" PRIx32, mChannel.get(),
|
||||
static_cast<uint32_t>(rv)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelParent::RecvCancel(const nsresult& status) {
|
||||
if (mChannel) {
|
||||
mChannel->Cancel(status);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelParent::RecvSuspend() {
|
||||
if (mChannel) {
|
||||
mChannel->Suspend();
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GIOChannelParent::RecvResume() {
|
||||
if (mChannel) {
|
||||
mChannel->Resume();
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelParent::nsIRequestObserver
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::OnStartRequest(nsIRequest* aRequest) {
|
||||
LOG(("GIOChannelParent::OnStartRequest [this=%p]\n", this));
|
||||
nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest);
|
||||
MOZ_ASSERT(chan);
|
||||
NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
|
||||
|
||||
int64_t contentLength;
|
||||
chan->GetContentLength(&contentLength);
|
||||
nsCString contentType;
|
||||
chan->GetContentType(contentType);
|
||||
nsresult channelStatus = NS_OK;
|
||||
chan->GetStatus(&channelStatus);
|
||||
|
||||
nsCString entityID;
|
||||
URIParams uriparam;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
chan->GetURI(getter_AddRefs(uri));
|
||||
SerializeURI(uri, uriparam);
|
||||
|
||||
if (mIPCClosed || !SendOnStartRequest(channelStatus, contentLength,
|
||||
contentType, entityID, uriparam)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
|
||||
LOG(("GIOChannelParent::OnStopRequest: [this=%p status=%" PRIu32 "]\n", this,
|
||||
static_cast<uint32_t>(aStatusCode)));
|
||||
|
||||
if (mIPCClosed || !SendOnStopRequest(aStatusCode)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelParent::nsIStreamListener
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::OnDataAvailable(nsIRequest* aRequest,
|
||||
nsIInputStream* aInputStream,
|
||||
uint64_t aOffset, uint32_t aCount) {
|
||||
LOG(("GIOChannelParent::OnDataAvailable [this=%p]\n", this));
|
||||
|
||||
nsCString data;
|
||||
nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult channelStatus = NS_OK;
|
||||
mChannel->GetStatus(&channelStatus);
|
||||
|
||||
if (mIPCClosed ||
|
||||
!SendOnDataAvailable(channelStatus, data, aOffset, aCount)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelParent::nsIParentChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::SetParentListener(ParentChannelListener* aListener) {
|
||||
// Do not need ptr to ParentChannelListener.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
|
||||
bool aIsThirdParty) {
|
||||
// Nothing to do.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::NotifyFlashPluginStateChanged(
|
||||
nsIHttpChannel::FlashPluginState aState) {
|
||||
// Nothing to do.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
|
||||
const nsACString& aProvider,
|
||||
const nsACString& aFullHash) {
|
||||
// nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::SetClassifierMatchedTrackingInfo(
|
||||
const nsACString& aLists, const nsACString& aFullHashes) {
|
||||
// nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::Delete() {
|
||||
if (mIPCClosed || !SendDeleteSelf()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::GetRemoteType(nsACString& aRemoteType) {
|
||||
if (!CanSend()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
dom::PContentParent* pcp = Manager()->Manager();
|
||||
aRemoteType = static_cast<dom::ContentParent*>(pcp)->GetRemoteType();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GIOChannelParent::nsIInterfaceRequestor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
GIOChannelParent::GetInterface(const nsIID& uuid, void** result) {
|
||||
if (uuid.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
|
||||
uuid.Equals(NS_GET_IID(nsISecureBrowserUI))) {
|
||||
if (mBrowserParent) {
|
||||
return mBrowserParent->QueryInterface(uuid, result);
|
||||
}
|
||||
}
|
||||
|
||||
// Only support nsILoadContext if child channel's callbacks did too
|
||||
if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
|
||||
nsCOMPtr<nsILoadContext> copy = mLoadContext;
|
||||
copy.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return QueryInterface(uuid, result);
|
||||
}
|
||||
|
||||
//---------------------
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
80
netwerk/protocol/gio/GIOChannelParent.h
Normal file
80
netwerk/protocol/gio/GIOChannelParent.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=4 sw=2 sts=2 et 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/. */
|
||||
|
||||
#ifndef NS_GIOCHANNELPARENT_H
|
||||
#define NS_GIOCHANNELPARENT_H
|
||||
|
||||
#include "mozilla/net/PGIOChannelParent.h"
|
||||
#include "mozilla/net/NeckoParent.h"
|
||||
#include "nsIParentChannel.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
|
||||
class nsILoadContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class BrowserParent;
|
||||
} // namespace dom
|
||||
|
||||
namespace net {
|
||||
class ChannelEventQueue;
|
||||
|
||||
class GIOChannelParent final : public PGIOChannelParent,
|
||||
public nsIParentChannel,
|
||||
public nsIInterfaceRequestor {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPARENTCHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
|
||||
GIOChannelParent(dom::BrowserParent* aIframeEmbedding,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus);
|
||||
|
||||
bool Init(const GIOChannelCreationArgs& aOpenArgs);
|
||||
|
||||
protected:
|
||||
virtual ~GIOChannelParent() = default;
|
||||
|
||||
bool DoAsyncOpen(const URIParams& aURI, const uint64_t& aStartPos,
|
||||
const nsCString& aEntityID,
|
||||
const Maybe<IPCStream>& aUploadStream,
|
||||
const Maybe<LoadInfoArgs>& aLoadInfoArgs,
|
||||
const uint32_t& aLoadFlags);
|
||||
|
||||
// used to connect redirected-to channel in parent with just created
|
||||
// ChildChannel. Used during HTTP->FTP redirects.
|
||||
bool ConnectChannel(const uint64_t& channelId);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvCancel(const nsresult& status) override;
|
||||
virtual mozilla::ipc::IPCResult RecvSuspend() override;
|
||||
virtual mozilla::ipc::IPCResult RecvResume() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
|
||||
bool mIPCClosed = false;
|
||||
|
||||
nsCOMPtr<nsILoadContext> mLoadContext;
|
||||
|
||||
PBOverrideStatus mPBOverride;
|
||||
|
||||
// Set to the canceled status value if the main channel was canceled.
|
||||
nsresult mStatus = NS_OK;
|
||||
|
||||
RefPtr<mozilla::dom::BrowserParent> mBrowserParent;
|
||||
|
||||
RefPtr<ChannelEventQueue> mEventQ;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* NS_GIOCHANNELPARENT_H */
|
50
netwerk/protocol/gio/PGIOChannel.ipdl
Normal file
50
netwerk/protocol/gio/PGIOChannel.ipdl
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
|
||||
/* 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 protocol PNecko;
|
||||
include URIParams;
|
||||
|
||||
//FIXME: bug #792908 (NeckoChannelParams already included by PNecko)
|
||||
include NeckoChannelParams;
|
||||
|
||||
using PRTime from "prtime.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
async protocol PGIOChannel
|
||||
{
|
||||
manager PNecko;
|
||||
|
||||
parent:
|
||||
// Note: channels are opened during construction, so no open method here:
|
||||
// see PNecko.ipdl
|
||||
|
||||
async __delete__();
|
||||
|
||||
async Cancel(nsresult status);
|
||||
async Suspend();
|
||||
async Resume();
|
||||
|
||||
child:
|
||||
async OnStartRequest(nsresult aChannelStatus,
|
||||
int64_t aContentLength,
|
||||
nsCString aContentType,
|
||||
nsCString aEntityID,
|
||||
URIParams aURI);
|
||||
async OnDataAvailable(nsresult channelStatus,
|
||||
nsCString data,
|
||||
uint64_t offset,
|
||||
uint32_t count);
|
||||
async OnStopRequest(nsresult channelStatus);
|
||||
async FailedAsyncOpen(nsresult statusCode);
|
||||
|
||||
async DeleteSelf();
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
@ -4,10 +4,6 @@
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
"nsGIOProtocolHandler.cpp",
|
||||
]
|
||||
|
||||
XPCOM_MANIFESTS += [
|
||||
"components.conf",
|
||||
]
|
||||
@ -16,6 +12,27 @@ EXPORTS += [
|
||||
"nsGIOProtocolHandler.h",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.net += [
|
||||
"GIOChannelChild.h",
|
||||
"GIOChannelParent.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"GIOChannelChild.cpp",
|
||||
"GIOChannelParent.cpp",
|
||||
"nsGIOProtocolHandler.cpp",
|
||||
]
|
||||
|
||||
IPDL_SOURCES = [
|
||||
"PGIOChannel.ipdl",
|
||||
]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"/netwerk/base",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
CXXFLAGS += CONFIG["TK_CFLAGS"]
|
||||
|
@ -8,9 +8,11 @@
|
||||
* input stream provided by GVFS/GIO.
|
||||
*/
|
||||
#include "nsGIOProtocolHandler.h"
|
||||
#include "GIOChannelChild.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
@ -41,8 +43,9 @@ using namespace mozilla;
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// NSPR_LOG_MODULES=gio:5
|
||||
static mozilla::LazyLogModule sGIOLog("gio");
|
||||
#define LOG(args) MOZ_LOG(sGIOLog, mozilla::LogLevel::Debug, args)
|
||||
LazyLogModule gGIOLog("gio");
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gGIOLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static nsresult MapGIOResult(gint code) {
|
||||
@ -108,17 +111,21 @@ static nsresult MapGIOResult(gint code) {
|
||||
}
|
||||
|
||||
static nsresult MapGIOResult(GError* result) {
|
||||
if (!result) return NS_OK;
|
||||
if (!result) {
|
||||
return NS_OK;
|
||||
}
|
||||
return MapGIOResult(result->code);
|
||||
}
|
||||
|
||||
/** Return values for mount operation.
|
||||
* These enums are used as mount operation return values.
|
||||
*/
|
||||
typedef enum {
|
||||
enum class MountOperationResult {
|
||||
MOUNT_OPERATION_IN_PROGRESS, /** \enum operation in progress */
|
||||
MOUNT_OPERATION_SUCCESS, /** \enum operation successful */
|
||||
MOUNT_OPERATION_FAILED /** \enum operation not successful */
|
||||
} MountOperationResult;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Sort function compares according to file type (directory/file)
|
||||
@ -132,11 +139,13 @@ static gint FileInfoComparator(gconstpointer a, gconstpointer b) {
|
||||
GFileInfo* ia = (GFileInfo*)a;
|
||||
GFileInfo* ib = (GFileInfo*)b;
|
||||
if (g_file_info_get_file_type(ia) == G_FILE_TYPE_DIRECTORY &&
|
||||
g_file_info_get_file_type(ib) != G_FILE_TYPE_DIRECTORY)
|
||||
g_file_info_get_file_type(ib) != G_FILE_TYPE_DIRECTORY) {
|
||||
return -1;
|
||||
}
|
||||
if (g_file_info_get_file_type(ib) == G_FILE_TYPE_DIRECTORY &&
|
||||
g_file_info_get_file_type(ia) != G_FILE_TYPE_DIRECTORY)
|
||||
g_file_info_get_file_type(ia) != G_FILE_TYPE_DIRECTORY) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return strcasecmp(g_file_info_get_name(ia), g_file_info_get_name(ib));
|
||||
}
|
||||
@ -149,10 +158,7 @@ static void mount_operation_ask_password(
|
||||
GMountOperation* mount_op, const char* message, const char* default_user,
|
||||
const char* default_domain, GAskPasswordFlags flags, gpointer user_data);
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsGIOInputStream final : public nsIInputStream {
|
||||
~nsGIOInputStream() { Close(); }
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
@ -189,6 +195,7 @@ class nsGIOInputStream final : public nsIInputStream {
|
||||
void SetMountResult(MountOperationResult result, gint error_code);
|
||||
|
||||
private:
|
||||
~nsGIOInputStream() { Close(); }
|
||||
nsresult DoOpen();
|
||||
nsresult DoRead(char* aBuf, uint32_t aCount, uint32_t* aCountRead);
|
||||
nsresult SetContentTypeOfChannel(const char* contentType);
|
||||
@ -206,10 +213,12 @@ class nsGIOInputStream final : public nsIInputStream {
|
||||
nsCString mDirBuf;
|
||||
uint32_t mDirBufCursor;
|
||||
bool mDirOpen;
|
||||
MountOperationResult mMountRes;
|
||||
MountOperationResult mMountRes =
|
||||
MountOperationResult::MOUNT_OPERATION_SUCCESS;
|
||||
mozilla::Monitor mMonitorMountInProgress;
|
||||
gint mMountErrorCode;
|
||||
gint mMountErrorCode{};
|
||||
};
|
||||
|
||||
/**
|
||||
* Set result of mount operation and notify monitor waiting for results.
|
||||
* This method is called in main thread as long as it is used only
|
||||
@ -232,7 +241,7 @@ nsresult nsGIOInputStream::MountVolume() {
|
||||
GMountOperation* mount_op = g_mount_operation_new();
|
||||
g_signal_connect(mount_op, "ask-password",
|
||||
G_CALLBACK(mount_operation_ask_password), mChannel);
|
||||
mMountRes = MOUNT_OPERATION_IN_PROGRESS;
|
||||
mMountRes = MountOperationResult::MOUNT_OPERATION_IN_PROGRESS;
|
||||
/* g_file_mount_enclosing_volume uses a dbus request to mount the volume.
|
||||
Callback mount_enclosing_volume_finished is called in main thread
|
||||
(not this thread on which this method is called). */
|
||||
@ -240,11 +249,13 @@ nsresult nsGIOInputStream::MountVolume() {
|
||||
mount_enclosing_volume_finished, this);
|
||||
mozilla::MonitorAutoLock mon(mMonitorMountInProgress);
|
||||
/* Waiting for finish of mount operation thread */
|
||||
while (mMountRes == MOUNT_OPERATION_IN_PROGRESS) mon.Wait();
|
||||
while (mMountRes == MountOperationResult::MOUNT_OPERATION_IN_PROGRESS) {
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
g_object_unref(mount_op);
|
||||
|
||||
if (mMountRes == MOUNT_OPERATION_FAILED) {
|
||||
if (mMountRes == MountOperationResult::MOUNT_OPERATION_FAILED) {
|
||||
return MapGIOResult(mMountErrorCode);
|
||||
}
|
||||
return NS_OK;
|
||||
@ -288,7 +299,9 @@ nsresult nsGIOInputStream::DoOpenDirectory() {
|
||||
// Write base URL (make sure it ends with a '/')
|
||||
mDirBuf.AppendLiteral("300: ");
|
||||
mDirBuf.Append(mSpec);
|
||||
if (mSpec.get()[mSpec.Length() - 1] != '/') mDirBuf.Append('/');
|
||||
if (mSpec.get()[mSpec.Length() - 1] != '/') {
|
||||
mDirBuf.Append('/');
|
||||
}
|
||||
mDirBuf.Append('\n');
|
||||
|
||||
// Write column names
|
||||
@ -360,7 +373,9 @@ nsresult nsGIOInputStream::DoOpen() {
|
||||
if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED) {
|
||||
// location is not yet mounted, try to mount
|
||||
g_error_free(error);
|
||||
if (NS_IsMainThread()) return NS_ERROR_NOT_CONNECTED;
|
||||
if (NS_IsMainThread()) {
|
||||
return NS_ERROR_NOT_CONNECTED;
|
||||
}
|
||||
error = nullptr;
|
||||
rv = MountVolume();
|
||||
if (rv != NS_OK) {
|
||||
@ -395,7 +410,9 @@ nsresult nsGIOInputStream::DoOpen() {
|
||||
g_warning("Unable to get file type.");
|
||||
rv = NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
if (info) g_object_unref(info);
|
||||
if (info) {
|
||||
g_object_unref(info);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -590,7 +607,9 @@ nsGIOInputStream::Close() {
|
||||
mSpec.Truncate(); // free memory
|
||||
|
||||
// Prevent future reads from re-opening the handle.
|
||||
if (NS_SUCCEEDED(mStatus)) mStatus = NS_BASE_STREAM_CLOSED;
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
mStatus = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -601,7 +620,9 @@ nsGIOInputStream::Close() {
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsGIOInputStream::Available(uint64_t* aResult) {
|
||||
if (NS_FAILED(mStatus)) return mStatus;
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
*aResult = mBytesRemaining;
|
||||
|
||||
@ -628,7 +649,9 @@ nsGIOInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aCountRead) {
|
||||
|
||||
mStatus = DoRead(aBuf, aCount, aCountRead);
|
||||
// Check if all data has been read
|
||||
if (mStatus == NS_BASE_STREAM_CLOSED) return NS_OK;
|
||||
if (mStatus == NS_BASE_STREAM_CLOSED) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check whenever any error appears while reading
|
||||
return mStatus;
|
||||
@ -671,10 +694,11 @@ static void mount_enclosing_volume_finished(GObject* source_object,
|
||||
|
||||
if (error) {
|
||||
g_warning("Mount failed: %s %d", error->message, error->code);
|
||||
istream->SetMountResult(MOUNT_OPERATION_FAILED, error->code);
|
||||
istream->SetMountResult(MountOperationResult::MOUNT_OPERATION_FAILED,
|
||||
error->code);
|
||||
g_error_free(error);
|
||||
} else {
|
||||
istream->SetMountResult(MOUNT_OPERATION_SUCCESS, 0);
|
||||
istream->SetMountResult(MountOperationResult::MOUNT_OPERATION_SUCCESS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -840,6 +864,9 @@ already_AddRefed<nsGIOProtocolHandler> nsGIOProtocolHandler::GetSingleton() {
|
||||
NS_IMPL_ISUPPORTS(nsGIOProtocolHandler, nsIProtocolHandler, nsIObserver)
|
||||
|
||||
nsresult nsGIOProtocolHandler::Init() {
|
||||
if (net::IsNeckoChild()) {
|
||||
net::NeckoChild::InitNeckoChild();
|
||||
}
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs) {
|
||||
InitSupportedProtocolsPref(prefs);
|
||||
@ -865,29 +892,21 @@ void nsGIOProtocolHandler::InitSupportedProtocolsPref(nsIPrefBranch* prefs) {
|
||||
#ifdef MOZ_PROXY_BYPASS_PROTECTION
|
||||
"" // use none
|
||||
#else
|
||||
"smb:,sftp:" // use defaults
|
||||
"sftp:" // use defaults (comma separated list)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
LOG(("gio: supported protocols \"%s\"\n", mSupportedProtocols.get()));
|
||||
}
|
||||
|
||||
bool nsGIOProtocolHandler::IsSupportedProtocol(const nsCString& aSpec) {
|
||||
const char* specString = aSpec.get();
|
||||
const char* colon = strchr(specString, ':');
|
||||
if (!colon) return false;
|
||||
|
||||
uint32_t length = colon - specString + 1;
|
||||
|
||||
// <scheme> + ':'
|
||||
nsCString scheme(specString, length);
|
||||
|
||||
char* found = PL_strcasestr(mSupportedProtocols.get(), scheme.get());
|
||||
if (!found) return false;
|
||||
|
||||
if (found[length] != ',' && found[length] != '\0') return false;
|
||||
|
||||
return true;
|
||||
bool nsGIOProtocolHandler::IsSupportedProtocol(const nsCString& aScheme) {
|
||||
nsAutoCString schemeWithColon = aScheme + ":"_ns;
|
||||
for (const auto& protocol : mSupportedProtocols.Split(',')) {
|
||||
if (schemeWithColon.Equals(protocol, nsCaseInsensitiveCStringComparator)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -940,10 +959,8 @@ nsGIOProtocolHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = aURI->GetSpec(spec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!IsSupportedProtocol(spec)) {
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString scheme;
|
||||
@ -952,10 +969,29 @@ nsGIOProtocolHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!IsValidGIOScheme(scheme)) {
|
||||
if (!IsSupportedProtocol(scheme)) {
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
}
|
||||
|
||||
// g_vfs_get_supported_uri_schemes() returns a very limited list in the
|
||||
// child due to the sandbox, so we only check if its valid for the parent.
|
||||
if (XRE_IsParentProcess() && !IsValidGIOScheme(scheme)) {
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
}
|
||||
|
||||
RefPtr<nsBaseChannel> channel;
|
||||
if (net::IsNeckoChild()) {
|
||||
channel = new mozilla::net::GIOChannelChild(aURI);
|
||||
// set the loadInfo on the new channel
|
||||
channel->SetLoadInfo(aLoadInfo);
|
||||
|
||||
rv = channel->SetContentType(nsLiteralCString(UNKNOWN_CONTENT_TYPE));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
channel.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsGIOInputStream> stream = new nsGIOInputStream(spec);
|
||||
if (!stream) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -969,6 +1005,7 @@ nsGIOProtocolHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
stream->SetChannel(*aResult);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
extern mozilla::LazyLogModule gGIOLog;
|
||||
|
||||
class nsGIOProtocolHandler final : public nsIProtocolHandler,
|
||||
public nsIObserver {
|
||||
public:
|
||||
@ -18,11 +21,13 @@ class nsGIOProtocolHandler final : public nsIProtocolHandler,
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static already_AddRefed<nsGIOProtocolHandler> GetSingleton();
|
||||
bool IsSupportedProtocol(const nsCString& spec);
|
||||
bool IsSupportedProtocol(const nsCString& aScheme);
|
||||
|
||||
protected:
|
||||
~nsGIOProtocolHandler() = default;
|
||||
|
||||
private:
|
||||
nsresult Init();
|
||||
~nsGIOProtocolHandler() = default;
|
||||
|
||||
void InitSupportedProtocolsPref(nsIPrefBranch* prefs);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user