Bug 1277028 - Make external protocol handlers work with e10s redirects, r=jduell

This commit is contained in:
Honza Bambas 2016-07-01 05:16:00 +02:00
Родитель 8cb77ec6fc
Коммит 2342cffea3
4 изменённых файлов: 127 добавлений и 1 удалений

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

@ -142,6 +142,7 @@
#include "nsIMutable.h" #include "nsIMutable.h"
#include "nsINSSU2FToken.h" #include "nsINSSU2FToken.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsIParentChannel.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsIRemoteWindowContext.h" #include "nsIRemoteWindowContext.h"
#include "nsIScriptError.h" #include "nsIScriptError.h"
@ -4419,6 +4420,32 @@ ContentParent::RecvLoadURIExternal(const URIParams& uri,
return true; return true;
} }
bool
ContentParent::RecvExtProtocolChannelConnectParent(const uint32_t& registrarId)
{
nsresult rv;
// First get the real channel created before redirect on the parent.
nsCOMPtr<nsIChannel> channel;
rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
NS_ENSURE_SUCCESS(rv, true);
// The channel itself is its own (faked) parent, link it.
rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, true);
// Signal the parent channel that it's a redirect-to parent. This will
// make AsyncOpen on it do nothing (what we want).
// Yes, this is a bit of a hack, but I don't think it's necessary to invent
// a new interface just to set this flag on the channel.
parent->SetParentListener(nullptr);
return true;
}
bool bool
ContentParent::HasNotificationPermission(const IPC::Principal& aPrincipal) ContentParent::HasNotificationPermission(const IPC::Principal& aPrincipal)
{ {

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

@ -1004,6 +1004,7 @@ private:
virtual bool RecvLoadURIExternal(const URIParams& uri, virtual bool RecvLoadURIExternal(const URIParams& uri,
PBrowserParent* windowContext) override; PBrowserParent* windowContext) override;
virtual bool RecvExtProtocolChannelConnectParent(const uint32_t& registrarId) override;
virtual bool RecvSyncMessage(const nsString& aMsg, virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData, const ClonedMessageData& aData,

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

@ -833,6 +833,7 @@ parent:
async SetURITitle(URIParams uri, nsString title); async SetURITitle(URIParams uri, nsString title);
async LoadURIExternal(URIParams uri, PBrowser windowContext); async LoadURIExternal(URIParams uri, PBrowser windowContext);
async ExtProtocolChannelConnectParent(uint32_t registrarId);
// PrefService message // PrefService message
sync ReadPrefsArray() returns (PrefSetting[] prefs) verify; sync ReadPrefsArray() returns (PrefSetting[] prefs) verify;

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

@ -26,6 +26,8 @@
// used to dispatch urls to default protocol handlers // used to dispatch urls to default protocol handlers
#include "nsCExternalHandlerService.h" #include "nsCExternalHandlerService.h"
#include "nsIExternalProtocolService.h" #include "nsIExternalProtocolService.h"
#include "nsIChildChannel.h"
#include "nsIParentChannel.h"
class nsILoadInfo; class nsILoadInfo;
@ -34,12 +36,18 @@ class nsILoadInfo;
// to calls in the OS for loading the url. // to calls in the OS for loading the url.
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
class nsExtProtocolChannel : public nsIChannel class nsExtProtocolChannel : public nsIChannel,
public nsIChildChannel,
public nsIParentChannel
{ {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSICHANNEL NS_DECL_NSICHANNEL
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUEST NS_DECL_NSIREQUEST
NS_DECL_NSICHILDCHANNEL
NS_DECL_NSIPARENTCHANNEL
nsExtProtocolChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo); nsExtProtocolChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo);
@ -54,6 +62,11 @@ private:
nsresult mStatus; nsresult mStatus;
nsLoadFlags mLoadFlags; nsLoadFlags mLoadFlags;
bool mWasOpened; bool mWasOpened;
// Set true (as a result of ConnectParent invoked from child process)
// when this channel is on the parent process and is being used as
// a redirect target channel. It turns AsyncOpen into a no-op since
// we do it on the child.
bool mConnectedParent;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks; nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsILoadGroup> mLoadGroup; nsCOMPtr<nsILoadGroup> mLoadGroup;
@ -67,6 +80,10 @@ NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIChannel) NS_INTERFACE_MAP_ENTRY(nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequest) NS_INTERFACE_MAP_ENTRY(nsIRequest)
NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_END_THREADSAFE NS_INTERFACE_MAP_END_THREADSAFE
nsExtProtocolChannel::nsExtProtocolChannel(nsIURI* aURI, nsExtProtocolChannel::nsExtProtocolChannel(nsIURI* aURI,
@ -75,6 +92,7 @@ nsExtProtocolChannel::nsExtProtocolChannel(nsIURI* aURI,
, mOriginalURI(aURI) , mOriginalURI(aURI)
, mStatus(NS_OK) , mStatus(NS_OK)
, mWasOpened(false) , mWasOpened(false)
, mConnectedParent(false)
, mLoadInfo(aLoadInfo) , mLoadInfo(aLoadInfo)
{ {
} }
@ -184,6 +202,10 @@ NS_IMETHODIMP nsExtProtocolChannel::Open2(nsIInputStream** aStream)
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{ {
if (mConnectedParent) {
return NS_OK;
}
MOZ_ASSERT(!mLoadInfo || MOZ_ASSERT(!mLoadInfo ||
mLoadInfo->GetSecurityMode() == 0 || mLoadInfo->GetSecurityMode() == 0 ||
mLoadInfo->GetInitialSecurityCheckDone() || mLoadInfo->GetInitialSecurityCheckDone() ||
@ -338,6 +360,81 @@ NS_IMETHODIMP nsExtProtocolChannel::Resume()
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
///////////////////////////////////////////////////////////////////////
// From nsIChildChannel
//////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsExtProtocolChannel::ConnectParent(uint32_t registrarId)
{
mozilla::dom::ContentChild::GetSingleton()->
SendExtProtocolChannelConnectParent(registrarId);
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::CompleteRedirectSetup(nsIStreamListener *listener,
nsISupports *context)
{
// For redirects to external protocols we AsyncOpen on the child
// (not the parent) because child channel has the right docshell
// (which is needed for the select dialog).
return AsyncOpen(listener, context);
}
///////////////////////////////////////////////////////////////////////
// From nsIParentChannel (derives from nsIStreamListener)
//////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsExtProtocolChannel::SetParentListener(HttpChannelParentListener* aListener)
{
// This is called as part of the connect parent operation from
// ContentParent::RecvExtProtocolChannelConnectParent. Setting
// this flag tells this channel to not proceed and makes AsyncOpen
// just no-op. Actual operation will happen from the child process
// via CompleteRedirectSetup call on the child channel.
mConnectedParent = true;
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingProtectionDisabled()
{
// nothing to do
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::Delete()
{
// nothing to do
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
// no data is expected
MOZ_CRASH("No data expected from external protocol channel");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP nsExtProtocolChannel::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)
{
// no data is expected
MOZ_CRASH("No data expected from external protocol channel");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP nsExtProtocolChannel::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
uint64_t aOffset,
uint32_t aCount)
{
// no data is expected
MOZ_CRASH("No data expected from external protocol channel");
return NS_ERROR_UNEXPECTED;
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// the default protocol handler implementation // the default protocol handler implementation
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////