mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 1556489 - P18. Add DocumentChannel and hook it up. r=nika,mayhemer
DocumentChannel acts as a replacement for HttpChannel where redirects are now entirely handled in the DocumentChannelParent. The ContentChild will receive the final nsIChannel once all redirects have been handled. Differential Revision: https://phabricator.services.mozilla.com/D37490
This commit is contained in:
parent
20e71d4c8a
commit
1b5f7c772a
@ -70,6 +70,7 @@
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/LoadURIOptionsBinding.h"
|
||||
|
||||
#include "mozilla/net/DocumentChannelChild.h"
|
||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||
#include "ReferrerInfo.h"
|
||||
|
||||
@ -9760,12 +9761,27 @@ static bool IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal,
|
||||
return aTriggeringPrincipal->Equals(tmpResultPrincipal);
|
||||
}
|
||||
|
||||
static bool HasHttpScheme(nsIURI* aURI) {
|
||||
return aURI && (aURI->SchemeIs("http") || aURI->SchemeIs("https"));
|
||||
}
|
||||
|
||||
/* static */ bool nsDocShell::CreateChannelForLoadState(
|
||||
nsDocShellLoadState* aLoadState, LoadInfo* aLoadInfo,
|
||||
nsIInterfaceRequestor* aCallbacks, nsDocShell* aDocShell,
|
||||
const nsString* aInitiatorType, nsLoadFlags aLoadFlags, uint32_t aLoadType,
|
||||
uint32_t aCacheKey, bool aIsActive, bool aIsTopLevelDoc, nsresult& aRv,
|
||||
nsIChannel** aChannel) {
|
||||
if (StaticPrefs::browser_tabs_documentchannel() && XRE_IsContentProcess() &&
|
||||
HasHttpScheme(aLoadState->URI())) {
|
||||
RefPtr<DocumentChannelChild> child = new DocumentChannelChild(
|
||||
aLoadState, aLoadInfo, aInitiatorType, aLoadFlags, aLoadType, aCacheKey,
|
||||
aIsActive, aIsTopLevelDoc);
|
||||
child->SetNotificationCallbacks(aCallbacks);
|
||||
child.forget(aChannel);
|
||||
aRv = NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsAutoString srcdoc;
|
||||
bool isSrcdoc = aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC);
|
||||
|
@ -879,6 +879,12 @@
|
||||
value: 2048
|
||||
mirror: always
|
||||
|
||||
# If set, use DocumentChannel with nsDocShell in place of HttpChannel.
|
||||
- name: browser.tabs.documentchannel
|
||||
type: bool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: browser.tabs.remote.desktopbehavior
|
||||
type: bool
|
||||
value: false
|
||||
|
564
netwerk/ipc/DocumentChannelChild.cpp
Normal file
564
netwerk/ipc/DocumentChannelChild.cpp
Normal file
@ -0,0 +1,564 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 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 "DocumentChannelChild.h"
|
||||
#include "SerializedLoadContext.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/net/HttpChannelChild.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "mozilla/net/UrlClassifierCommon.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DocumentChannelChild)
|
||||
if (mWasOpened && aIID == NS_GET_IID(nsIHttpChannel)) {
|
||||
// DocumentChannelChild generally is doing an http connection
|
||||
// internally, but doesn't implement the interface. Everything
|
||||
// before AsyncOpen should be duplicated in the parent process
|
||||
// on the real http channel, but anything trying to QI to nsIHttpChannel
|
||||
// after that will be failing and get confused.
|
||||
NS_WARNING(
|
||||
"Trying to request nsIHttpChannel from DocumentChannelChild, this is "
|
||||
"likely broken");
|
||||
}
|
||||
NS_INTERFACE_MAP_ENTRY(nsIClassifiedChannel)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentChannelChild)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsBaseChannel)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(DocumentChannelChild, nsBaseChannel)
|
||||
NS_IMPL_RELEASE_INHERITED(DocumentChannelChild, nsBaseChannel)
|
||||
|
||||
DocumentChannelChild::DocumentChannelChild(
|
||||
nsDocShellLoadState* aLoadState, net::LoadInfo* aLoadInfo,
|
||||
const nsString* aInitiatorType, nsLoadFlags aLoadFlags, uint32_t aLoadType,
|
||||
uint32_t aCacheKey, bool aIsActive, bool aIsTopLevelDoc)
|
||||
: mLoadState(aLoadState),
|
||||
mInitiatorType(aInitiatorType ? Some(*aInitiatorType) : Nothing()),
|
||||
mLoadType(aLoadType),
|
||||
mCacheKey(aCacheKey),
|
||||
mIsActive(aIsActive),
|
||||
mIsTopLevelDoc(aIsTopLevelDoc) {
|
||||
mEventQueue = new ChannelEventQueue(static_cast<nsIChannel*>(this));
|
||||
SetURI(aLoadState->URI());
|
||||
SetLoadInfo(aLoadInfo);
|
||||
SetLoadFlags(aLoadFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = aListener;
|
||||
rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_TRUE(gNeckoChild, 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...
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> topWindowURI;
|
||||
nsCOMPtr<nsIURI> uriBeingLoaded =
|
||||
AntiTrackingCommon::MaybeGetDocumentURIBeingLoaded(this);
|
||||
nsCOMPtr<nsIPrincipal> contentBlockingAllowListPrincipal;
|
||||
|
||||
nsCOMPtr<mozIThirdPartyUtil> util = services::GetThirdPartyUtil();
|
||||
if (util) {
|
||||
nsCOMPtr<mozIDOMWindowProxy> win;
|
||||
rv =
|
||||
util->GetTopWindowForChannel(this, uriBeingLoaded, getter_AddRefs(win));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
util->GetURIFromWindow(win, getter_AddRefs(topWindowURI));
|
||||
|
||||
Unused << util->GetContentBlockingAllowListPrincipalFromWindow(
|
||||
win, uriBeingLoaded,
|
||||
getter_AddRefs(contentBlockingAllowListPrincipal));
|
||||
}
|
||||
}
|
||||
|
||||
// add ourselves to the load group.
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->AddRequest(this, nullptr);
|
||||
}
|
||||
|
||||
if (mCanceled) {
|
||||
// We may have been canceled already, either by on-modify-request
|
||||
// listeners or by load group observers; in that case, don't create IPDL
|
||||
// connection. See nsHttpChannel::AsyncOpen().
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
DocumentChannelCreationArgs args;
|
||||
|
||||
SerializeURI(topWindowURI, args.topWindowURI());
|
||||
args.loadState() = mLoadState->Serialize();
|
||||
Maybe<LoadInfoArgs> maybeArgs;
|
||||
rv = LoadInfoToLoadInfoArgs(mLoadInfo, &maybeArgs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_DIAGNOSTIC_ASSERT(maybeArgs);
|
||||
|
||||
if (contentBlockingAllowListPrincipal) {
|
||||
PrincipalInfo principalInfo;
|
||||
rv = PrincipalToPrincipalInfo(contentBlockingAllowListPrincipal,
|
||||
&principalInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
args.contentBlockingAllowListPrincipal() = Some(principalInfo);
|
||||
}
|
||||
|
||||
args.loadInfo() = *maybeArgs;
|
||||
GetLoadFlags(&args.loadFlags());
|
||||
args.initiatorType() = mInitiatorType;
|
||||
args.loadType() = mLoadType;
|
||||
args.cacheKey() = mCacheKey;
|
||||
args.isActive() = mIsActive;
|
||||
args.isTopLevelDoc() = mIsTopLevelDoc;
|
||||
args.channelId() = mChannelId;
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(this, loadContext);
|
||||
if (loadContext) {
|
||||
nsCOMPtr<mozIDOMWindowProxy> domWindow;
|
||||
loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
|
||||
if (domWindow) {
|
||||
auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow);
|
||||
nsIDocShell* docshell = pDomWindow->GetDocShell();
|
||||
if (docshell) {
|
||||
docshell->GetCustomUserAgent(args.customUserAgent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBrowserChild> iBrowserChild;
|
||||
GetCallback(iBrowserChild);
|
||||
BrowserChild* browserChild = static_cast<BrowserChild*>(iBrowserChild.get());
|
||||
if (MissingRequiredBrowserChild(browserChild, "ftp")) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
// TODO: What happens if the caller has called other methods on the
|
||||
// nsIChannel after the ctor, but before this?
|
||||
|
||||
gNeckoChild->SendPDocumentChannelConstructor(
|
||||
this, browserChild, IPC::SerializedLoadContext(this), args);
|
||||
|
||||
mIsPending = true;
|
||||
mWasOpened = true;
|
||||
mListener = listener;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class DocumentFailedAsyncOpenEvent
|
||||
: public NeckoTargetChannelEvent<DocumentChannelChild> {
|
||||
public:
|
||||
DocumentFailedAsyncOpenEvent(DocumentChannelChild* aChild,
|
||||
nsresult aStatusCode)
|
||||
: NeckoTargetChannelEvent<DocumentChannelChild>(aChild),
|
||||
mStatus(aStatusCode) {}
|
||||
|
||||
void Run() override { mChild->DoFailedAsyncOpen(mStatus); }
|
||||
|
||||
private:
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
IPCResult DocumentChannelChild::RecvFailedAsyncOpen(
|
||||
const nsresult& aStatusCode) {
|
||||
mEventQueue->RunOrEnqueue(
|
||||
new DocumentFailedAsyncOpenEvent(this, aStatusCode));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void DocumentChannelChild::DoFailedAsyncOpen(const nsresult& aStatusCode) {
|
||||
ShutdownListeners(aStatusCode);
|
||||
}
|
||||
|
||||
void DocumentChannelChild::ShutdownListeners(nsresult aStatusCode) {
|
||||
mStatus = aStatusCode;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> l = mListener;
|
||||
if (l) {
|
||||
l->OnStartRequest(this);
|
||||
}
|
||||
|
||||
mIsPending = false;
|
||||
|
||||
l = mListener; // it might have changed!
|
||||
if (l) {
|
||||
l->OnStopRequest(this, aStatusCode);
|
||||
}
|
||||
mListener = nullptr;
|
||||
mCallbacks = nullptr;
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aStatusCode);
|
||||
mLoadGroup = nullptr;
|
||||
}
|
||||
|
||||
if (CanSend()) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvCancelForProcessSwitch() {
|
||||
ShutdownListeners(NS_BINDING_ABORTED);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvDeleteSelf() {
|
||||
// This calls NeckoChild::DeallocPGenericChannel(), which deletes |this| if
|
||||
// IPDL holds the last reference. Don't rely on |this| existing after here!
|
||||
Send__delete__(this);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvRedirectToRealChannel(
|
||||
const uint32_t& aRegistrarId, nsIURI* aURI, const uint32_t& aNewLoadFlags,
|
||||
const Maybe<ReplacementChannelConfigInit>& aInit,
|
||||
const Maybe<LoadInfoArgs>& aLoadInfo, const uint64_t& aChannelId,
|
||||
nsIURI* aOriginalURI, const uint32_t& aRedirectMode,
|
||||
const uint32_t& aRedirectFlags, const Maybe<uint32_t>& aContentDisposition,
|
||||
const Maybe<nsString>& aContentDispositionFilename,
|
||||
RedirectToRealChannelResolver&& aResolve) {
|
||||
nsCOMPtr<nsILoadInfo> originalLoadInfo;
|
||||
RefPtr<dom::Document> loadingDocument;
|
||||
GetLoadInfo(getter_AddRefs(originalLoadInfo));
|
||||
if (originalLoadInfo) {
|
||||
originalLoadInfo->GetLoadingDocument(getter_AddRefs(loadingDocument));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
nsresult rv = LoadInfoArgsToLoadInfo(aLoadInfo, loadingDocument,
|
||||
getter_AddRefs(loadInfo));
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mRedirectResolver = std::move(aResolve);
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = NS_NewChannelInternal(getter_AddRefs(newChannel), aURI, loadInfo,
|
||||
nullptr, // PerformanceStorage
|
||||
mLoadGroup, // aLoadGroup
|
||||
nullptr, // aCallbacks
|
||||
aNewLoadFlags);
|
||||
|
||||
RefPtr<HttpChannelChild> httpChild = do_QueryObject(newChannel);
|
||||
RefPtr<nsIChildChannel> childChannel = do_QueryObject(newChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "NS_NewChannelInternal failed");
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// This is used to report any errors back to the parent by calling
|
||||
// CrossProcessRedirectFinished.
|
||||
auto scopeExit = MakeScopeExit([&]() {
|
||||
mRedirectResolver(rv);
|
||||
mRedirectResolver = nullptr;
|
||||
});
|
||||
|
||||
if (httpChild) {
|
||||
rv = httpChild->SetChannelId(aChannelId);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
rv = newChannel->SetOriginalURI(aOriginalURI);
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (httpChild) {
|
||||
rv = httpChild->SetRedirectMode(aRedirectMode);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
newChannel->SetNotificationCallbacks(mCallbacks);
|
||||
|
||||
if (aInit) {
|
||||
HttpBaseChannel::ReplacementChannelConfig config(*aInit);
|
||||
HttpBaseChannel::ConfigureReplacementChannel(newChannel, config);
|
||||
}
|
||||
|
||||
if (aContentDisposition) {
|
||||
newChannel->SetContentDisposition(*aContentDisposition);
|
||||
}
|
||||
|
||||
if (aContentDispositionFilename) {
|
||||
newChannel->SetContentDispositionFilename(*aContentDispositionFilename);
|
||||
}
|
||||
|
||||
// transfer any properties. This appears to be entirely a content-side
|
||||
// interface and isn't copied across to the parent. Copying the values
|
||||
// for this from this into the new actor will work, since the parent
|
||||
// won't have the right details anyway.
|
||||
// TODO: What about the process switch equivalent
|
||||
// (ContentChild::RecvCrossProcessRedirect)? In that case there is no local
|
||||
// existing actor in the destination process... We really need all information
|
||||
// to go up to the parent, and then come down to the new child actor.
|
||||
nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
|
||||
if (bag) {
|
||||
for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
bag->SetProperty(iter.Key(), iter.UserData());
|
||||
}
|
||||
}
|
||||
|
||||
// connect parent.
|
||||
if (childChannel) {
|
||||
rv = childChannel->ConnectParent(aRegistrarId); // creates parent channel
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mRedirectChannel = childChannel;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
|
||||
MOZ_ASSERT(target);
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, aRedirectFlags,
|
||||
target);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
scopeExit.release();
|
||||
}
|
||||
|
||||
// scopeExit will call CrossProcessRedirectFinished(rv) here
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::OnRedirectVerifyCallback(nsresult aStatusCode) {
|
||||
if (mRedirectChannel) {
|
||||
if (NS_SUCCEEDED(aStatusCode) && NS_SUCCEEDED(mStatus)) {
|
||||
mRedirectChannel->CompleteRedirectSetup(mListener, nullptr);
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRedirectChannel);
|
||||
channel->SetNotificationCallbacks(nullptr);
|
||||
}
|
||||
}
|
||||
mRedirectChannel = nullptr;
|
||||
|
||||
mRedirectResolver(aStatusCode);
|
||||
mRedirectResolver = nullptr;
|
||||
|
||||
if (NS_FAILED(aStatusCode)) {
|
||||
ShutdownListeners(aStatusCode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_REDIRECTED);
|
||||
}
|
||||
mCallbacks = nullptr;
|
||||
mListener = nullptr;
|
||||
|
||||
// This calls NeckoChild::DeallocPDocumentChannel(), which deletes |this| if
|
||||
// IPDL holds the last reference. Don't rely on |this| existing after here!
|
||||
if (CanSend()) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvConfirmRedirect(
|
||||
nsIURI* aNewUri, ConfirmRedirectResolver&& aResolve) {
|
||||
// This is effectively the same as AsyncOnChannelRedirect, except since we're
|
||||
// not propagating the redirect into this process, we don't have an nsIChannel
|
||||
// for the redirection and we have to do the checks manually.
|
||||
// This just checks CSP thus far, hopefully there's not much else needed.
|
||||
nsCOMPtr<nsIURI> originalUri;
|
||||
nsresult rv = GetOriginalURI(getter_AddRefs(originalUri));
|
||||
if (NS_FAILED(rv)) {
|
||||
aResolve(rv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
int16_t decision = nsIContentPolicy::ACCEPT;
|
||||
rv = CSPService::ConsultCSPForRedirect(originalUri, aNewUri, mLoadInfo,
|
||||
&decision);
|
||||
if (NS_FAILED(rv)) {
|
||||
aResolve(rv);
|
||||
return IPC_OK();
|
||||
}
|
||||
if (NS_CP_REJECTED(decision)) {
|
||||
aResolve(NS_BINDING_FAILED);
|
||||
} else {
|
||||
aResolve(NS_OK);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvNotifyChannelClassifierProtectionDisabled(
|
||||
const uint32_t& aAcceptedReason) {
|
||||
UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
|
||||
this, aAcceptedReason);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvNotifyCookieAllowed() {
|
||||
AntiTrackingCommon::NotifyBlockingDecision(
|
||||
this, AntiTrackingCommon::BlockingDecision::eAllow, 0);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvNotifyCookieBlocked(
|
||||
const uint32_t& aRejectedReason) {
|
||||
AntiTrackingCommon::NotifyBlockingDecision(
|
||||
this, AntiTrackingCommon::BlockingDecision::eBlock, aRejectedReason);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvSetClassifierMatchedInfo(
|
||||
const nsCString& aList, const nsCString& aProvider,
|
||||
const nsCString& aFullHash) {
|
||||
SetMatchedInfo(aList, aProvider, aFullHash);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvSetClassifierMatchedTrackingInfo(
|
||||
const nsCString& aLists, const nsCString& aFullHash) {
|
||||
nsTArray<nsCString> lists, fullhashes;
|
||||
for (const nsACString& token : aLists.Split(',')) {
|
||||
lists.AppendElement(token);
|
||||
}
|
||||
for (const nsACString& token : aFullHash.Split(',')) {
|
||||
fullhashes.AppendElement(token);
|
||||
}
|
||||
|
||||
SetMatchedTrackingInfo(lists, fullhashes);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DocumentChannelChild::nsIClassifiedChannel
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::GetMatchedList(nsACString& aList) {
|
||||
aList = mMatchedList;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::GetMatchedProvider(nsACString& aProvider) {
|
||||
aProvider = mMatchedProvider;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::GetMatchedFullHash(nsACString& aFullHash) {
|
||||
aFullHash = mMatchedFullHash;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::SetMatchedInfo(const nsACString& aList,
|
||||
const nsACString& aProvider,
|
||||
const nsACString& aFullHash) {
|
||||
NS_ENSURE_ARG(!aList.IsEmpty());
|
||||
|
||||
mMatchedList = aList;
|
||||
mMatchedProvider = aProvider;
|
||||
mMatchedFullHash = aFullHash;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::GetMatchedTrackingLists(nsTArray<nsCString>& aLists) {
|
||||
aLists = mMatchedTrackingLists;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::GetMatchedTrackingFullHashes(
|
||||
nsTArray<nsCString>& aFullHashes) {
|
||||
aFullHashes = mMatchedTrackingFullHashes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::SetMatchedTrackingInfo(
|
||||
const nsTArray<nsCString>& aLists, const nsTArray<nsCString>& aFullHashes) {
|
||||
NS_ENSURE_ARG(!aLists.IsEmpty());
|
||||
// aFullHashes can be empty for non hash-matching algorithm, for example,
|
||||
// host based test entries in preference.
|
||||
|
||||
mMatchedTrackingLists = aLists;
|
||||
mMatchedTrackingFullHashes = aFullHashes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::Cancel(nsresult aStatusCode) {
|
||||
if (mCanceled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCanceled = true;
|
||||
if (CanSend()) {
|
||||
SendCancel(aStatusCode);
|
||||
}
|
||||
|
||||
ShutdownListeners(aStatusCode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::Suspend() {
|
||||
NS_ENSURE_TRUE(CanSend(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
if (!mSuspendCount++) {
|
||||
SendSuspend();
|
||||
}
|
||||
|
||||
mEventQueue->Suspend();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelChild::Resume() {
|
||||
NS_ENSURE_TRUE(CanSend(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
MOZ_ASSERT(mSuspendCount);
|
||||
if (!--mSuspendCount) {
|
||||
SendResume();
|
||||
}
|
||||
|
||||
mEventQueue->Resume();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
125
netwerk/ipc/DocumentChannelChild.h
Normal file
125
netwerk/ipc/DocumentChannelChild.h
Normal file
@ -0,0 +1,125 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 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 mozilla_net_DocumentChannelChild_h
|
||||
#define mozilla_net_DocumentChannelChild_h
|
||||
|
||||
#include "mozilla/net/ChannelEventQueue.h"
|
||||
#include "mozilla/net/PDocumentChannelChild.h"
|
||||
#include "nsBaseChannel.h"
|
||||
#include "nsIChildChannel.h"
|
||||
#include "nsIClassifiedChannel.h"
|
||||
|
||||
#define DOCUMENT_CHANNEL_CHILD_IID \
|
||||
{ \
|
||||
0x6977bc44, 0xb1db, 0x41b7, { \
|
||||
0xb5, 0xc5, 0xe2, 0x13, 0x68, 0x22, 0xc9, 0x8f \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class DocumentChannelChild final : public PDocumentChannelChild,
|
||||
public nsBaseChannel,
|
||||
public nsIClassifiedChannel {
|
||||
public:
|
||||
DocumentChannelChild(nsDocShellLoadState* aLoadState,
|
||||
class LoadInfo* aLoadInfo,
|
||||
const nsString* aInitiatorType, nsLoadFlags aLoadFlags,
|
||||
uint32_t aLoadType, uint32_t aCacheKey, bool aIsActive,
|
||||
bool aIsTopLevelDoc);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED;
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
NS_DECL_NSICLASSIFIEDCHANNEL
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOCUMENT_CHANNEL_CHILD_IID)
|
||||
|
||||
// nsIRequest
|
||||
NS_IMETHOD Cancel(nsresult status) override;
|
||||
NS_IMETHOD Suspend() override;
|
||||
NS_IMETHOD Resume() override;
|
||||
// nsIChannel
|
||||
NS_IMETHOD AsyncOpen(nsIStreamListener* aListener) override;
|
||||
|
||||
nsresult OpenContentStream(bool aAsync, nsIInputStream** aStream,
|
||||
nsIChannel** aChannel) override {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& aStatusCode);
|
||||
|
||||
mozilla::ipc::IPCResult RecvCancelForProcessSwitch();
|
||||
|
||||
mozilla::ipc::IPCResult RecvDeleteSelf();
|
||||
|
||||
mozilla::ipc::IPCResult RecvRedirectToRealChannel(
|
||||
const uint32_t& aRegistrarId, nsIURI* aURI, const uint32_t& aNewLoadFlags,
|
||||
const Maybe<ReplacementChannelConfigInit>& aInit,
|
||||
const Maybe<LoadInfoArgs>& aLoadInfo, const uint64_t& aChannelId,
|
||||
nsIURI* aOriginalURI, const uint32_t& aRedirectMode,
|
||||
const uint32_t& aRedirectFlags,
|
||||
const Maybe<uint32_t>& aContentDisposition,
|
||||
const Maybe<nsString>& aContentDispositionFilename,
|
||||
RedirectToRealChannelResolver&& aResolve);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotifyChannelClassifierProtectionDisabled(
|
||||
const uint32_t& aAcceptedReason);
|
||||
mozilla::ipc::IPCResult RecvNotifyCookieAllowed();
|
||||
mozilla::ipc::IPCResult RecvNotifyCookieBlocked(
|
||||
const uint32_t& aRejectedReason);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetClassifierMatchedInfo(
|
||||
const nsCString& aList, const nsCString& aProvider,
|
||||
const nsCString& aFullHash);
|
||||
mozilla::ipc::IPCResult RecvSetClassifierMatchedTrackingInfo(
|
||||
const nsCString& aLists, const nsCString& aFullHash);
|
||||
|
||||
mozilla::ipc::IPCResult RecvConfirmRedirect(
|
||||
nsIURI* aNewUri, ConfirmRedirectResolver&& aResolve);
|
||||
|
||||
void DoFailedAsyncOpen(const nsresult& aStatusCode);
|
||||
|
||||
friend class NeckoTargetChannelEvent<DocumentChannelChild>;
|
||||
|
||||
private:
|
||||
void ShutdownListeners(nsresult aStatusCode);
|
||||
|
||||
~DocumentChannelChild() = default;
|
||||
|
||||
RefPtr<ChannelEventQueue> mEventQueue;
|
||||
nsCOMPtr<nsIChildChannel> mRedirectChannel;
|
||||
|
||||
// Classified channel's matched information
|
||||
nsCString mMatchedList;
|
||||
nsCString mMatchedProvider;
|
||||
nsCString mMatchedFullHash;
|
||||
nsTArray<nsCString> mMatchedTrackingLists;
|
||||
nsTArray<nsCString> mMatchedTrackingFullHashes;
|
||||
|
||||
RedirectToRealChannelResolver mRedirectResolver;
|
||||
|
||||
const RefPtr<nsDocShellLoadState> mLoadState;
|
||||
const Maybe<nsString> mInitiatorType;
|
||||
const uint32_t mLoadType;
|
||||
const uint32_t mCacheKey;
|
||||
const bool mIsActive;
|
||||
const bool mIsTopLevelDoc;
|
||||
|
||||
bool mCanceled = false;
|
||||
uint32_t mSuspendCount = 0;
|
||||
bool mIsPending = false;
|
||||
bool mWasOpened = false;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DocumentChannelChild, DOCUMENT_CHANNEL_CHILD_IID)
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_DocumentChannelChild_h
|
808
netwerk/ipc/DocumentChannelParent.cpp
Normal file
808
netwerk/ipc/DocumentChannelParent.cpp
Normal file
@ -0,0 +1,808 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 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 "DocumentChannelParent.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/ClientChannelHelper.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/net/HttpChannelParent.h"
|
||||
#include "mozilla/net/RedirectChannelRegistrar.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsIHttpProtocolHandler.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsRedirectHistoryEntry.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ADDREF(DocumentChannelParent)
|
||||
NS_IMPL_RELEASE(DocumentChannelParent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DocumentChannelParent)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICrossProcessSwitchChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentChannelParent)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
DocumentChannelParent::DocumentChannelParent(
|
||||
const PBrowserOrId& iframeEmbedding, nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus)
|
||||
: mLoadContext(aLoadContext), mPBOverride(aOverrideStatus) {
|
||||
if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
|
||||
mBrowserParent =
|
||||
static_cast<dom::BrowserParent*>(iframeEmbedding.get_PBrowserParent());
|
||||
}
|
||||
}
|
||||
|
||||
bool DocumentChannelParent::Init(const DocumentChannelCreationArgs& aArgs) {
|
||||
RefPtr<nsDocShellLoadState> loadState =
|
||||
new nsDocShellLoadState(aArgs.loadState());
|
||||
|
||||
RefPtr<LoadInfo> loadInfo;
|
||||
nsresult rv = mozilla::ipc::LoadInfoArgsToLoadInfo(Some(aArgs.loadInfo()),
|
||||
getter_AddRefs(loadInfo));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
mListener = new ParentChannelListener(this);
|
||||
|
||||
bool result = nsDocShell::CreateChannelForLoadState(
|
||||
loadState, loadInfo, mListener, nullptr,
|
||||
aArgs.initiatorType().ptrOr(nullptr), aArgs.loadFlags(), aArgs.loadType(),
|
||||
aArgs.cacheKey(), aArgs.isActive(), aArgs.isTopLevelDoc(), rv,
|
||||
getter_AddRefs(mChannel));
|
||||
if (!result) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
nsDocShell::ConfigureChannel(mChannel, loadState,
|
||||
aArgs.initiatorType().ptrOr(nullptr),
|
||||
aArgs.loadType(), aArgs.cacheKey());
|
||||
|
||||
// Computation of the top window uses the docshell tree, so only
|
||||
// works in the source process. We compute it manually and override
|
||||
// it so that it gets the right value.
|
||||
// This probably isn't fission compatible.
|
||||
RefPtr<HttpBaseChannel> httpBaseChannel = do_QueryObject(mChannel, &rv);
|
||||
if (httpBaseChannel) {
|
||||
nsCOMPtr<nsIURI> topWindowURI = DeserializeURI(aArgs.topWindowURI());
|
||||
rv = httpBaseChannel->SetTopWindowURI(topWindowURI);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
if (aArgs.contentBlockingAllowListPrincipal()) {
|
||||
nsCOMPtr<nsIPrincipal> contentBlockingAllowListPrincipal =
|
||||
PrincipalInfoToPrincipal(*aArgs.contentBlockingAllowListPrincipal());
|
||||
httpBaseChannel->SetContentBlockingAllowListPrincipal(
|
||||
contentBlockingAllowListPrincipal);
|
||||
}
|
||||
|
||||
// The content process docshell can specify a custom override
|
||||
// for the user agent value. If we had one, then add it to
|
||||
// the header now.
|
||||
if (!aArgs.customUserAgent().IsEmpty()) {
|
||||
NS_ConvertUTF16toUTF8 utf8CustomUserAgent(aArgs.customUserAgent());
|
||||
rv = httpBaseChannel->SetRequestHeader(NS_LITERAL_CSTRING("User-Agent"),
|
||||
utf8CustomUserAgent, false);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrivateBrowsingChannel> privateChannel =
|
||||
do_QueryInterface(mChannel);
|
||||
if (mPBOverride != kPBOverride_Unset) {
|
||||
privateChannel->SetPrivate(mPBOverride == kPBOverride_Private);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIIdentChannel> identChannel = do_QueryInterface(mChannel);
|
||||
if (identChannel) {
|
||||
Unused << identChannel->SetChannelId(aArgs.channelId());
|
||||
}
|
||||
|
||||
RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
|
||||
if (httpChannelImpl) {
|
||||
httpChannelImpl->SetWarningReporter(this);
|
||||
}
|
||||
|
||||
// Setup a ClientChannelHelper to watch for redirects, and copy
|
||||
// across any serviceworker related data between channels as needed.
|
||||
AddClientChannelHelperInParent(mChannel, GetMainThreadSerialEventTarget());
|
||||
|
||||
rv = mChannel->AsyncOpen(mListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
mChannelCreationURI = loadState->URI();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DocumentChannelParent::ActorDestroy(ActorDestroyReason why) {
|
||||
// The nsHttpChannel may have a reference to this parent, release it
|
||||
// to avoid circular references.
|
||||
RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
|
||||
if (httpChannelImpl) {
|
||||
httpChannelImpl->SetWarningReporter(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentChannelParent::CancelChildForProcessSwitch() {
|
||||
MOZ_ASSERT(!mDoingProcessSwitch, "Already in the middle of switching?");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDoingProcessSwitch = true;
|
||||
if (CanSend()) {
|
||||
Unused << SendCancelForProcessSwitch();
|
||||
}
|
||||
}
|
||||
|
||||
bool DocumentChannelParent::RecvCancel(const nsresult& aStatusCode) {
|
||||
if (mDoingProcessSwitch) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (mChannel) {
|
||||
mChannel->Cancel(aStatusCode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DocumentChannelParent::RecvSuspend() {
|
||||
if (mChannel) {
|
||||
mChannel->Suspend();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DocumentChannelParent::RecvResume() {
|
||||
if (mChannel) {
|
||||
mChannel->Resume();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DocumentChannelParent::RedirectToRealChannelFinished(nsresult aRv) {
|
||||
if (NS_FAILED(aRv)) {
|
||||
FinishReplacementChannelSetup(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for background channel ready on target channel
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
MOZ_ASSERT(redirectReg);
|
||||
|
||||
nsCOMPtr<nsIParentChannel> redirectParentChannel;
|
||||
redirectReg->GetParentChannel(mRedirectChannelId,
|
||||
getter_AddRefs(redirectParentChannel));
|
||||
if (!redirectParentChannel) {
|
||||
FinishReplacementChannelSetup(false);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIParentRedirectingChannel> redirectingParent =
|
||||
do_QueryInterface(redirectParentChannel);
|
||||
if (!redirectingParent) {
|
||||
// Continue verification procedure if redirecting to non-Http protocol
|
||||
FinishReplacementChannelSetup(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask redirected channel if verification can proceed.
|
||||
// ReadyToVerify will be invoked when redirected channel is ready.
|
||||
redirectingParent->ContinueVerification(this);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::ReadyToVerify(nsresult aResultCode) {
|
||||
FinishReplacementChannelSetup(NS_SUCCEEDED(aResultCode));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void DocumentChannelParent::FinishReplacementChannelSetup(bool aSucceeded) {
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIParentChannel> redirectChannel;
|
||||
if (mRedirectChannelId) {
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
MOZ_ASSERT(registrar);
|
||||
|
||||
rv = registrar->GetParentChannel(mRedirectChannelId,
|
||||
getter_AddRefs(redirectChannel));
|
||||
if (NS_FAILED(rv) || !redirectChannel) {
|
||||
// Redirect might get canceled before we got AsyncOnChannelRedirect
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = registrar->GetRegisteredChannel(mRedirectChannelId,
|
||||
getter_AddRefs(newChannel));
|
||||
MOZ_ASSERT(newChannel, "Already registered channel not found");
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
newChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
}
|
||||
// Release all previously registered channels, they are no longer need to be
|
||||
// kept in the registrar from this moment.
|
||||
registrar->DeregisterChannels(mRedirectChannelId);
|
||||
|
||||
mRedirectChannelId = 0;
|
||||
}
|
||||
|
||||
if (!redirectChannel) {
|
||||
aSucceeded = false;
|
||||
}
|
||||
|
||||
if (!aSucceeded) {
|
||||
if (redirectChannel) {
|
||||
redirectChannel->Delete();
|
||||
}
|
||||
if (mSuspendedChannel) {
|
||||
mChannel->Resume();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
!SameCOMIdentity(redirectChannel, static_cast<nsIParentChannel*>(this)));
|
||||
|
||||
Delete();
|
||||
if (!mStopRequestValue) {
|
||||
mListener->SetListenerAfterRedirect(redirectChannel);
|
||||
}
|
||||
redirectChannel->SetParentListener(mListener);
|
||||
|
||||
// We stored the values from all nsIParentChannel functions called since we
|
||||
// couldn't handle them. Copy them across to the real channel since it should
|
||||
// know what to do.
|
||||
for (auto& variant : mIParentChannelFunctions) {
|
||||
variant.match(
|
||||
[redirectChannel](const nsIHttpChannel::FlashPluginState& aState) {
|
||||
redirectChannel->NotifyFlashPluginStateChanged(aState);
|
||||
},
|
||||
[redirectChannel](const ClassifierMatchedInfoParams& aParams) {
|
||||
redirectChannel->SetClassifierMatchedInfo(
|
||||
aParams.mList, aParams.mProvider, aParams.mFullHash);
|
||||
},
|
||||
[redirectChannel](const ClassifierMatchedTrackingInfoParams& aParams) {
|
||||
redirectChannel->SetClassifierMatchedTrackingInfo(
|
||||
aParams.mLists, aParams.mFullHashes);
|
||||
},
|
||||
[redirectChannel](const ClassificationFlagsParams& aParams) {
|
||||
redirectChannel->NotifyClassificationFlags(
|
||||
aParams.mClassificationFlags, aParams.mIsThirdParty);
|
||||
});
|
||||
}
|
||||
|
||||
RefPtr<HttpChannelParent> httpParent = do_QueryObject(redirectChannel);
|
||||
if (httpParent) {
|
||||
RefPtr<HttpChannelSecurityWarningReporter> reporter = httpParent;
|
||||
for (auto& variant : mSecurityWarningFunctions) {
|
||||
variant.match(
|
||||
[reporter](const ReportSecurityMessageParams& aParams) {
|
||||
Unused << reporter->ReportSecurityMessage(aParams.mMessageTag,
|
||||
aParams.mMessageCategory);
|
||||
},
|
||||
[reporter](const LogBlockedCORSRequestParams& aParams) {
|
||||
Unused << reporter->LogBlockedCORSRequest(aParams.mMessage,
|
||||
aParams.mCategory);
|
||||
},
|
||||
[reporter](const LogMimeTypeMismatchParams& aParams) {
|
||||
Unused << reporter->LogMimeTypeMismatch(
|
||||
aParams.mMessageName, aParams.mWarning, aParams.mURL,
|
||||
aParams.mContentType);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (mSuspendedChannel) {
|
||||
nsTArray<OnDataAvailableRequest> pendingRequests =
|
||||
std::move(mPendingRequests);
|
||||
MOZ_ASSERT(mPendingRequests.IsEmpty());
|
||||
|
||||
nsCOMPtr<nsHttpChannel> httpChannel = do_QueryInterface(mChannel);
|
||||
if (httpChannel) {
|
||||
httpChannel->SetApplyConversion(mOldApplyConversion);
|
||||
}
|
||||
rv = redirectChannel->OnStartRequest(mChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
mChannel->Cancel(rv);
|
||||
}
|
||||
|
||||
// If we failed to suspend the channel, then we might have received
|
||||
// some messages while the redirected was being handled.
|
||||
// Manually send them on now.
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
(!mStopRequestValue || NS_SUCCEEDED(*mStopRequestValue))) {
|
||||
for (auto& request : pendingRequests) {
|
||||
nsCOMPtr<nsIInputStream> stringStream;
|
||||
rv = NS_NewByteInputStream(
|
||||
getter_AddRefs(stringStream),
|
||||
Span<const char>(request.data.get(), request.count),
|
||||
NS_ASSIGNMENT_DEPEND);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = redirectChannel->OnDataAvailable(mChannel, stringStream,
|
||||
request.offset, request.count);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
mChannel->Cancel(rv);
|
||||
mStopRequestValue = Some(rv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mStopRequestValue) {
|
||||
redirectChannel->OnStopRequest(mChannel, *mStopRequestValue);
|
||||
}
|
||||
|
||||
mChannel->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::FinishCrossProcessSwitch(
|
||||
nsIAsyncVerifyRedirectCallback* aCallback, nsresult aStatusCode) {
|
||||
// We only manually Suspend mChannel when we initiate the redirect
|
||||
// from OnStartRequest, which is currently only in the same-process
|
||||
// case.
|
||||
MOZ_ASSERT(!mSuspendedChannel);
|
||||
|
||||
if (NS_SUCCEEDED(aStatusCode)) {
|
||||
// This updates ParentChannelListener to point to this parent and at
|
||||
// the same time cancels the old channel.
|
||||
FinishReplacementChannelSetup(true);
|
||||
}
|
||||
|
||||
aCallback->OnRedirectVerifyCallback(aStatusCode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult DocumentChannelParent::TriggerCrossProcessSwitch(
|
||||
nsIHttpChannel* aChannel, uint64_t aIdentifier) {
|
||||
CancelChildForProcessSwitch();
|
||||
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(aChannel);
|
||||
MOZ_DIAGNOSTIC_ASSERT(httpChannel,
|
||||
"Must be called with nsHttpChannel object");
|
||||
RefPtr<nsHttpChannel::ContentProcessIdPromise> p =
|
||||
httpChannel->TakeRedirectContentProcessIdPromise();
|
||||
|
||||
p->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self = RefPtr<DocumentChannelParent>(this),
|
||||
channel = nsCOMPtr<nsIChannel>(aChannel), aIdentifier](uint64_t aCpId) {
|
||||
self->TriggerRedirectToRealChannel(channel, Some(aCpId), aIdentifier);
|
||||
},
|
||||
[httpChannel](nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||
httpChannel->OnRedirectVerifyCallback(aStatusCode);
|
||||
});
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void DocumentChannelParent::TriggerRedirectToRealChannel(
|
||||
nsIChannel* aChannel, const Maybe<uint64_t>& aDestinationProcess,
|
||||
uint64_t aIdentifier) {
|
||||
// This initiates replacing the current DocumentChannel with a
|
||||
// protocol specific 'real' channel, maybe in a different process than
|
||||
// the current DocumentChannelChild, if aDestinationProces is set.
|
||||
// It registers the current mChannel with the registrar to get an ID
|
||||
// so that the remote end can setup a new IPDL channel and lookup
|
||||
// the same underlying channel.
|
||||
// We expect this process to finish with FinishReplacementChannelSetup
|
||||
// (for both in-process and process switch cases), where we cleanup
|
||||
// the registrar and copy across any needed state to the replacing
|
||||
// IPDL parent object.
|
||||
|
||||
// Use the original URI of the current channel, as this is what
|
||||
// we'll use to construct the channel in the content process.
|
||||
nsCOMPtr<nsIURI> uri = mChannelCreationURI;
|
||||
if (!uri) {
|
||||
aChannel->GetOriginalURI(getter_AddRefs(uri));
|
||||
}
|
||||
|
||||
// I previously used HttpBaseChannel::CloneLoadInfoForRedirect, but that
|
||||
// clears the principal to inherit, which fails tests (probably because this
|
||||
// 'redirect' is usually just an implementation detail). It's also http only,
|
||||
// and aChannel can be anything that we redirected to.
|
||||
nsCOMPtr<nsILoadInfo> redirectLoadInfo;
|
||||
aChannel->GetLoadInfo(getter_AddRefs(redirectLoadInfo));
|
||||
nsCOMPtr<nsIPrincipal> principalToInherit;
|
||||
redirectLoadInfo->GetPrincipalToInherit(getter_AddRefs(principalToInherit));
|
||||
|
||||
RefPtr<nsHttpChannel> baseChannel = do_QueryObject(aChannel);
|
||||
if (baseChannel) {
|
||||
redirectLoadInfo = baseChannel->CloneLoadInfoForRedirect(
|
||||
uri, nsIChannelEventSink::REDIRECT_INTERNAL);
|
||||
redirectLoadInfo->SetResultPrincipalURI(uri);
|
||||
|
||||
// The clone process clears this, and then we fail tests..
|
||||
// docshell/test/mochitest/test_forceinheritprincipal_overrule_owner.html
|
||||
if (principalToInherit) {
|
||||
redirectLoadInfo->SetPrincipalToInherit(principalToInherit);
|
||||
}
|
||||
} else {
|
||||
redirectLoadInfo =
|
||||
static_cast<mozilla::net::LoadInfo*>(redirectLoadInfo.get())->Clone();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> uriPrincipal;
|
||||
nsIScriptSecurityManager* sm = nsContentUtils::GetSecurityManager();
|
||||
sm->GetChannelURIPrincipal(aChannel, getter_AddRefs(uriPrincipal));
|
||||
|
||||
nsCOMPtr<nsIRedirectHistoryEntry> entry =
|
||||
new nsRedirectHistoryEntry(uriPrincipal, nullptr, EmptyCString());
|
||||
|
||||
redirectLoadInfo->AppendRedirectHistoryEntry(entry, true);
|
||||
}
|
||||
|
||||
// Register the new channel and obtain id for it
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
MOZ_ASSERT(registrar);
|
||||
nsresult rv = registrar->RegisterChannel(aChannel, &mRedirectChannelId);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
Maybe<LoadInfoArgs> loadInfoArgs;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
ipc::LoadInfoToLoadInfoArgs(redirectLoadInfo, &loadInfoArgs));
|
||||
|
||||
uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL;
|
||||
MOZ_ALWAYS_SUCCEEDS(aChannel->GetLoadFlags(&newLoadFlags));
|
||||
if (!aDestinationProcess) {
|
||||
newLoadFlags |= nsIChannel::LOAD_REPLACE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
aChannel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
|
||||
uint64_t channelId = 0;
|
||||
// aChannel can be a nsHttpChannel as well as InterceptedHttpChannel so we
|
||||
// can't use baseChannel here.
|
||||
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
|
||||
MOZ_ALWAYS_SUCCEEDS(httpChannel->GetChannelId(&channelId));
|
||||
}
|
||||
|
||||
uint32_t redirectMode = nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW;
|
||||
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
|
||||
do_QueryInterface(aChannel);
|
||||
if (httpChannelInternal) {
|
||||
MOZ_ALWAYS_SUCCEEDS(httpChannelInternal->GetRedirectMode(&redirectMode));
|
||||
}
|
||||
|
||||
// If we didn't have any redirects, then we pass the REDIRECT_INTERNAL flag
|
||||
// for this channel switch so that it isn't recorded in session history etc.
|
||||
// If there were redirect(s), then we want this switch to be recorded as a
|
||||
// real one, since we have a new URI.
|
||||
uint32_t redirectFlags = 0;
|
||||
if (!mDidUpstreamRedirect) {
|
||||
redirectFlags = nsIChannelEventSink::REDIRECT_INTERNAL;
|
||||
}
|
||||
|
||||
Maybe<ReplacementChannelConfigInit> config;
|
||||
|
||||
if (baseChannel) {
|
||||
uint32_t loadFlags = 0;
|
||||
if (!aDestinationProcess) {
|
||||
loadFlags |= nsIChannel::LOAD_REPLACE;
|
||||
}
|
||||
|
||||
config =
|
||||
Some(baseChannel
|
||||
->CloneReplacementChannelConfig(true, redirectFlags, loadFlags)
|
||||
.Serialize());
|
||||
}
|
||||
|
||||
Maybe<uint32_t> contentDisposition;
|
||||
uint32_t contentDispositionTemp;
|
||||
rv = aChannel->GetContentDisposition(&contentDispositionTemp);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
contentDisposition = Some(contentDispositionTemp);
|
||||
}
|
||||
|
||||
Maybe<nsString> contentDispositionFilename;
|
||||
nsString contentDispositionFilenameTemp;
|
||||
rv = aChannel->GetContentDispositionFilename(contentDispositionFilenameTemp);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
contentDispositionFilename = Some(contentDispositionFilenameTemp);
|
||||
}
|
||||
|
||||
if (aDestinationProcess) {
|
||||
dom::ContentParent* cp =
|
||||
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
|
||||
ContentParentId{*aDestinationProcess});
|
||||
if (!cp) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(config);
|
||||
|
||||
auto result = cp->SendCrossProcessRedirect(
|
||||
mRedirectChannelId, uri, *config, loadInfoArgs, channelId, originalURI,
|
||||
aIdentifier, redirectMode);
|
||||
MOZ_ASSERT(result, "SendCrossProcessRedirect failed");
|
||||
Unused << result;
|
||||
} else {
|
||||
RefPtr<DocumentChannelParent> channel = this;
|
||||
SendRedirectToRealChannel(mRedirectChannelId, uri, newLoadFlags, config,
|
||||
loadInfoArgs, channelId, originalURI,
|
||||
redirectMode, redirectFlags, contentDisposition,
|
||||
contentDispositionFilename)
|
||||
->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[channel](nsresult aRv) {
|
||||
channel->RedirectToRealChannelFinished(aRv);
|
||||
},
|
||||
[channel](const mozilla::ipc::ResponseRejectReason) {
|
||||
channel->RedirectToRealChannelFinished(NS_ERROR_FAILURE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::OnStartRequest(nsIRequest* aRequest) {
|
||||
nsCOMPtr<nsHttpChannel> channel = do_QueryInterface(aRequest);
|
||||
mChannel = do_QueryInterface(aRequest);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mChannel);
|
||||
|
||||
// If this is a download, then redirect entirely within the parent.
|
||||
// TODO, see bug 1574372.
|
||||
|
||||
if (!CanSend()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Once we initiate a process switch, we ask the child to notify the listeners
|
||||
// that we have completed. If the switch promise then gets rejected we also
|
||||
// cancel the parent, which results in this being called. We don't need
|
||||
// to forward it on though, since the child side is already completed.
|
||||
if (mDoingProcessSwitch) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mChannel->Suspend();
|
||||
mSuspendedChannel = true;
|
||||
|
||||
// The caller of this OnStartRequest will install a conversion
|
||||
// helper after we return if we haven't disabled conversion. Normally
|
||||
// HttpChannelParent::OnStartRequest would disable conversion, but we're
|
||||
// defering calling that until later. Manually disable it now to prevent the
|
||||
// converter from being installed (since we want the child to do it), and
|
||||
// also save the value so that when we do call
|
||||
// HttpChannelParent::OnStartRequest, we can have the value as it originally
|
||||
// was.
|
||||
if (channel) {
|
||||
Unused << channel->GetApplyConversion(&mOldApplyConversion);
|
||||
channel->SetApplyConversion(false);
|
||||
}
|
||||
|
||||
TriggerRedirectToRealChannel(mChannel);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::OnStopRequest(nsIRequest* aRequest,
|
||||
nsresult aStatusCode) {
|
||||
mStopRequestValue = Some(aStatusCode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::OnDataAvailable(nsIRequest* aRequest,
|
||||
nsIInputStream* aInputStream,
|
||||
uint64_t aOffset, uint32_t aCount) {
|
||||
// This isn't supposed to happen, since we suspended the channel, but
|
||||
// sometimes Suspend just doesn't work. This can happen when we're routing
|
||||
// through nsUnknownDecoder to sniff the content type, and it doesn't handle
|
||||
// being suspended. Let's just store the data and manually forward it to our
|
||||
// redirected channel when it's ready.
|
||||
nsCString data;
|
||||
nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mPendingRequests.AppendElement(
|
||||
OnDataAvailableRequest({data, aOffset, aCount}));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::SetParentListener(
|
||||
mozilla::net::ParentChannelListener* listener) {
|
||||
// We don't need this (do we?)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::GetInterface(const nsIID& aIID, void** result) {
|
||||
// Only support nsILoadContext if child channel's callbacks did too
|
||||
if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
|
||||
nsCOMPtr<nsILoadContext> copy = mLoadContext;
|
||||
copy.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
|
||||
aIID.Equals(NS_GET_IID(nsISecureBrowserUI)) ||
|
||||
aIID.Equals(NS_GET_IID(nsIRemoteTab))) {
|
||||
if (mBrowserParent) {
|
||||
return mBrowserParent->QueryInterface(aIID, result);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = QueryInterface(aIID, result);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Rather than forwarding all these nsIParentChannel functions to the child, we
|
||||
// cache a list of them, and then ask the 'real' channel to forward them for us
|
||||
// after it's created.
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::NotifyChannelClassifierProtectionDisabled(
|
||||
uint32_t aAcceptedReason) {
|
||||
if (CanSend()) {
|
||||
Unused << SendNotifyChannelClassifierProtectionDisabled(aAcceptedReason);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::NotifyCookieAllowed() {
|
||||
if (CanSend()) {
|
||||
Unused << SendNotifyCookieAllowed();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::NotifyCookieBlocked(uint32_t aRejectedReason) {
|
||||
if (CanSend()) {
|
||||
Unused << SendNotifyCookieBlocked(aRejectedReason);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::NotifyFlashPluginStateChanged(
|
||||
nsIHttpChannel::FlashPluginState aState) {
|
||||
mIParentChannelFunctions.AppendElement(
|
||||
IParentChannelFunction{VariantIndex<0>{}, aState});
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
|
||||
const nsACString& aProvider,
|
||||
const nsACString& aFullHash) {
|
||||
ClassifierMatchedInfoParams params;
|
||||
params.mList = aList;
|
||||
params.mProvider = aProvider;
|
||||
params.mFullHash = aFullHash;
|
||||
|
||||
if (CanSend()) {
|
||||
Unused << SendSetClassifierMatchedInfo(params.mList, params.mProvider,
|
||||
params.mFullHash);
|
||||
}
|
||||
|
||||
mIParentChannelFunctions.AppendElement(
|
||||
IParentChannelFunction{VariantIndex<1>{}, std::move(params)});
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::SetClassifierMatchedTrackingInfo(
|
||||
const nsACString& aLists, const nsACString& aFullHash) {
|
||||
ClassifierMatchedTrackingInfoParams params;
|
||||
params.mLists = aLists;
|
||||
params.mFullHashes = aFullHash;
|
||||
|
||||
if (CanSend()) {
|
||||
Unused << SendSetClassifierMatchedTrackingInfo(params.mLists,
|
||||
params.mFullHashes);
|
||||
}
|
||||
|
||||
mIParentChannelFunctions.AppendElement(
|
||||
IParentChannelFunction{VariantIndex<2>{}, std::move(params)});
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
|
||||
bool aIsThirdParty) {
|
||||
mIParentChannelFunctions.AppendElement(IParentChannelFunction{
|
||||
VariantIndex<3>{},
|
||||
ClassificationFlagsParams{aClassificationFlags, aIsThirdParty}});
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::Delete() {
|
||||
// TODO - not sure we need it, but should delete the child or call on the
|
||||
// child to release the parent.
|
||||
if (!CanSend()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
Unused << SendDeleteSelf();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentChannelParent::AsyncOnChannelRedirect(
|
||||
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
|
||||
nsIAsyncVerifyRedirectCallback* aCallback) {
|
||||
// We generally don't want to notify the content process about redirects,
|
||||
// so just update our channel and tell the callback that we're good to go.
|
||||
mChannel = aNewChannel;
|
||||
|
||||
// We need the original URI of the current channel to use to open the real
|
||||
// channel in the content process. Unfortunately we overwrite the original
|
||||
// uri of the new channel with the original pre-redirect URI, so grab
|
||||
// a copy of it now.
|
||||
aNewChannel->GetOriginalURI(getter_AddRefs(mChannelCreationURI));
|
||||
|
||||
// We don't need to confirm internal redirects or record any
|
||||
// history for them, so just immediately verify and return.
|
||||
if (aFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
|
||||
aCallback->OnRedirectVerifyCallback(NS_OK);
|
||||
return NS_OK;
|
||||
} else {
|
||||
mDidUpstreamRedirect = true;
|
||||
}
|
||||
|
||||
if (!CanSend()) {
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
// Currently the CSP code expects to run in the content
|
||||
// process so that it can send events. Send a message to
|
||||
// our content process to ask CSP if we should allow this
|
||||
// redirect, and wait for confirmation.
|
||||
nsCOMPtr<nsIURI> newUri;
|
||||
nsresult rv = aNewChannel->GetURI(getter_AddRefs(newUri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> callback(aCallback);
|
||||
nsCOMPtr<nsIChannel> oldChannel(aOldChannel);
|
||||
SendConfirmRedirect(newUri)->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[callback, oldChannel](nsresult aRv) {
|
||||
if (NS_FAILED(aRv)) {
|
||||
oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
|
||||
}
|
||||
callback->OnRedirectVerifyCallback(aRv);
|
||||
},
|
||||
[callback, oldChannel](const mozilla::ipc::ResponseRejectReason) {
|
||||
oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
|
||||
callback->OnRedirectVerifyCallback(NS_BINDING_ABORTED);
|
||||
});
|
||||
|
||||
// Clear out our nsIParentChannel functions, since a normal parent
|
||||
// channel would actually redirect and not have those values on the new one.
|
||||
// We expect the URI classifier to run on the redirected channel with
|
||||
// the new URI and set these again.
|
||||
mIParentChannelFunctions.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
220
netwerk/ipc/DocumentChannelParent.h
Normal file
220
netwerk/ipc/DocumentChannelParent.h
Normal file
@ -0,0 +1,220 @@
|
||||
/* vim: set sw=2 ts=8 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 mozilla_net_DocumentChannelParent_h
|
||||
#define mozilla_net_DocumentChannelParent_h
|
||||
|
||||
#include "mozilla/Variant.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "mozilla/net/NeckoParent.h"
|
||||
#include "mozilla/net/PDocumentChannelParent.h"
|
||||
#include "mozilla/net/ParentChannelListener.h"
|
||||
#include "nsICrossProcessSwitchChannel.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIParentChannel.h"
|
||||
#include "nsIParentRedirectingChannel.h"
|
||||
#include "nsIRedirectResultListener.h"
|
||||
|
||||
#define DOCUMENT_CHANNEL_PARENT_IID \
|
||||
{ \
|
||||
0x3b393c56, 0x9e01, 0x11e9, { \
|
||||
0xa2, 0xa3, 0x2a, 0x2a, 0xe2, 0xdb, 0xcc, 0xe4 \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// TODO: We currently don't implement nsIProgressEventSink and forward those
|
||||
// to the child. Should we? We get the interface requested.
|
||||
class DocumentChannelParent : public nsIInterfaceRequestor,
|
||||
public PDocumentChannelParent,
|
||||
public nsIAsyncVerifyRedirectReadyCallback,
|
||||
public nsIParentChannel,
|
||||
public nsIChannelEventSink,
|
||||
public nsICrossProcessSwitchChannel,
|
||||
public HttpChannelSecurityWarningReporter {
|
||||
public:
|
||||
explicit DocumentChannelParent(const dom::PBrowserOrId& iframeEmbedding,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus);
|
||||
|
||||
bool Init(const DocumentChannelCreationArgs& aArgs);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPARENTCHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSICROSSPROCESSSWITCHCHANNEL
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOCUMENT_CHANNEL_PARENT_IID)
|
||||
|
||||
bool RecvCancel(const nsresult& status);
|
||||
bool RecvSuspend();
|
||||
bool RecvResume();
|
||||
|
||||
nsresult ReportSecurityMessage(const nsAString& aMessageTag,
|
||||
const nsAString& aMessageCategory) override {
|
||||
ReportSecurityMessageParams params;
|
||||
params.mMessageTag = aMessageTag;
|
||||
params.mMessageCategory = aMessageCategory;
|
||||
mSecurityWarningFunctions.AppendElement(
|
||||
SecurityWarningFunction{VariantIndex<0>{}, std::move(params)});
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult LogBlockedCORSRequest(const nsAString& aMessage,
|
||||
const nsACString& aCategory) override {
|
||||
LogBlockedCORSRequestParams params;
|
||||
params.mMessage = aMessage;
|
||||
params.mCategory = aCategory;
|
||||
mSecurityWarningFunctions.AppendElement(
|
||||
SecurityWarningFunction{VariantIndex<1>{}, std::move(params)});
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult LogMimeTypeMismatch(const nsACString& aMessageName, bool aWarning,
|
||||
const nsAString& aURL,
|
||||
const nsAString& aContentType) override {
|
||||
LogMimeTypeMismatchParams params;
|
||||
params.mMessageName = aMessageName;
|
||||
params.mWarning = aWarning;
|
||||
params.mURL = aURL;
|
||||
params.mContentType = aContentType;
|
||||
mSecurityWarningFunctions.AppendElement(
|
||||
SecurityWarningFunction{VariantIndex<2>{}, std::move(params)});
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
// Notify the DocumentChannelChild that we're switching
|
||||
// to a different process and that it can notify listeners
|
||||
// that it's finished.
|
||||
void CancelChildForProcessSwitch();
|
||||
|
||||
private:
|
||||
virtual ~DocumentChannelParent() = default;
|
||||
|
||||
void TriggerRedirectToRealChannel(
|
||||
nsIChannel* aChannel,
|
||||
const Maybe<uint64_t>& aDestinationProcess = Nothing(),
|
||||
uint64_t aIdentifier = 0);
|
||||
|
||||
void RedirectToRealChannelFinished(nsresult aRv);
|
||||
|
||||
void FinishReplacementChannelSetup(bool aSucceeded);
|
||||
|
||||
// This defines a variant that describes all the attribute setters (and their
|
||||
// parameters) from nsIParentChannel
|
||||
//
|
||||
// NotifyFlashPluginStateChanged(nsIHttpChannel::FlashPluginState aState) = 0;
|
||||
// SetClassifierMatchedInfo(const nsACString& aList, const nsACString&
|
||||
// aProvider, const nsACString& aFullHash) = 0;
|
||||
// SetClassifierMatchedTrackingInfo(const nsACString& aLists, const
|
||||
// nsACString& aFullHashes) = 0; NotifyClassificationFlags(uint32_t
|
||||
// aClassificationFlags, bool aIsThirdParty) = 0;
|
||||
struct ClassifierMatchedInfoParams {
|
||||
nsCString mList;
|
||||
nsCString mProvider;
|
||||
nsCString mFullHash;
|
||||
};
|
||||
struct ClassifierMatchedTrackingInfoParams {
|
||||
nsCString mLists;
|
||||
nsCString mFullHashes;
|
||||
};
|
||||
struct ClassificationFlagsParams {
|
||||
uint32_t mClassificationFlags;
|
||||
bool mIsThirdParty;
|
||||
};
|
||||
typedef mozilla::Variant<
|
||||
nsIHttpChannel::FlashPluginState, ClassifierMatchedInfoParams,
|
||||
ClassifierMatchedTrackingInfoParams, ClassificationFlagsParams>
|
||||
IParentChannelFunction;
|
||||
|
||||
// Store a list of all the attribute setters that have been called on this
|
||||
// channel, so that we can repeat them on the real channel that we redirect
|
||||
// to.
|
||||
nsTArray<IParentChannelFunction> mIParentChannelFunctions;
|
||||
|
||||
// This defines a variant this describes all the functions
|
||||
// from HttpChannelSecurityWarningReporter so that we can forward
|
||||
// them on to the real channel.
|
||||
|
||||
struct ReportSecurityMessageParams {
|
||||
nsString mMessageTag;
|
||||
nsString mMessageCategory;
|
||||
};
|
||||
struct LogBlockedCORSRequestParams {
|
||||
nsString mMessage;
|
||||
nsCString mCategory;
|
||||
};
|
||||
struct LogMimeTypeMismatchParams {
|
||||
nsCString mMessageName;
|
||||
bool mWarning;
|
||||
nsString mURL;
|
||||
nsString mContentType;
|
||||
};
|
||||
|
||||
typedef mozilla::Variant<ReportSecurityMessageParams,
|
||||
LogBlockedCORSRequestParams,
|
||||
LogMimeTypeMismatchParams>
|
||||
SecurityWarningFunction;
|
||||
nsTArray<SecurityWarningFunction> mSecurityWarningFunctions;
|
||||
|
||||
struct OnDataAvailableRequest {
|
||||
nsCString data;
|
||||
uint64_t offset;
|
||||
uint32_t count;
|
||||
};
|
||||
// TODO Backtrack this.
|
||||
nsTArray<OnDataAvailableRequest> mPendingRequests;
|
||||
Maybe<nsresult> mStopRequestValue;
|
||||
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
RefPtr<ParentChannelListener> mListener;
|
||||
|
||||
nsCOMPtr<nsILoadContext> mLoadContext;
|
||||
|
||||
PBOverrideStatus mPBOverride;
|
||||
|
||||
// The original URI of the current channel. If there are redirects,
|
||||
// then the value on the channel gets overwritten with the original
|
||||
// URI of the first channel in the redirect chain, so we cache the
|
||||
// value we need here.
|
||||
nsCOMPtr<nsIURI> mChannelCreationURI;
|
||||
|
||||
RefPtr<mozilla::dom::BrowserParent> mBrowserParent;
|
||||
|
||||
// Corresponding redirect channel registrar Id for the final channel that
|
||||
// we want to use when redirecting the child, or doing a process switch.
|
||||
// 0 means redirection is not started.
|
||||
uint32_t mRedirectChannelId = 0;
|
||||
// Set to true if we called Suspend on mChannel to initiate our redirect.
|
||||
// This isn't currently set when we do a process swap, since that gets
|
||||
// initiated in nsHttpChannel.
|
||||
bool mSuspendedChannel = false;
|
||||
// Set to true if we're currently in the middle of replacing this with
|
||||
// a new channel connected a different process.
|
||||
bool mDoingProcessSwitch = false;
|
||||
// The value of GetApplyConversion on mChannel when OnStartRequest
|
||||
// was called. We override it to false to prevent a conversion
|
||||
// helper from being installed, but we need to restore the value
|
||||
// later.
|
||||
bool mOldApplyConversion = false;
|
||||
// Set to true if we went through a redirect.
|
||||
bool mDidUpstreamRedirect = false;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DocumentChannelParent,
|
||||
DOCUMENT_CHANNEL_PARENT_IID)
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_DocumentChannelParent_h
|
@ -348,5 +348,21 @@ struct CookieStruct
|
||||
int32_t rawSameSite;
|
||||
};
|
||||
|
||||
struct DocumentChannelCreationArgs {
|
||||
URIParams? topWindowURI;
|
||||
DocShellLoadStateInit loadState;
|
||||
LoadInfoArgs loadInfo;
|
||||
PrincipalInfo? contentBlockingAllowListPrincipal;
|
||||
nsString? initiatorType;
|
||||
nsString customUserAgent;
|
||||
uint64_t channelId;
|
||||
uint32_t loadFlags;
|
||||
uint32_t loadType;
|
||||
uint32_t cacheKey;
|
||||
bool isActive;
|
||||
bool isTopLevelDoc;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
@ -131,6 +131,13 @@ bool NeckoChild::DeallocPAltDataOutputStreamChild(
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<PDocumentChannelChild> NeckoChild::AllocPDocumentChannelChild(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& args) {
|
||||
MOZ_ASSERT_UNREACHABLE("AllocPDocumentChannelChild should not be called");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PFTPChannelChild* NeckoChild::AllocPFTPChannelChild(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const FTPChannelCreationArgs& aOpenArgs) {
|
||||
|
@ -36,6 +36,10 @@ class NeckoChild : public PNeckoChild {
|
||||
PHttpChannelChild* channel);
|
||||
bool DeallocPAltDataOutputStreamChild(PAltDataOutputStreamChild* aActor);
|
||||
|
||||
already_AddRefed<PDocumentChannelChild> AllocPDocumentChannelChild(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& args);
|
||||
|
||||
PCookieServiceChild* AllocPCookieServiceChild();
|
||||
bool DeallocPCookieServiceChild(PCookieServiceChild*);
|
||||
PFTPChannelChild* AllocPFTPChannelChild(
|
||||
|
@ -124,6 +124,17 @@ inline bool MissingRequiredBrowserChild(
|
||||
return false;
|
||||
}
|
||||
|
||||
class HttpChannelSecurityWarningReporter : public nsISupports {
|
||||
public:
|
||||
virtual MOZ_MUST_USE nsresult ReportSecurityMessage(
|
||||
const nsAString& aMessageTag, const nsAString& aMessageCategory) = 0;
|
||||
virtual MOZ_MUST_USE nsresult LogBlockedCORSRequest(
|
||||
const nsAString& aMessage, const nsACString& aCategory) = 0;
|
||||
virtual MOZ_MUST_USE nsresult
|
||||
LogMimeTypeMismatch(const nsACString& aMessageName, bool aWarning,
|
||||
const nsAString& aURL, const nsAString& aContentType) = 0;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/net/WebSocketChannelParent.h"
|
||||
#include "mozilla/net/WebSocketEventListenerParent.h"
|
||||
#include "mozilla/net/DataChannelParent.h"
|
||||
#include "mozilla/net/DocumentChannelParent.h"
|
||||
#include "mozilla/net/SimpleChannelParent.h"
|
||||
#include "mozilla/net/AltDataOutputStreamParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@ -408,6 +409,37 @@ mozilla::ipc::IPCResult NeckoParent::RecvPFTPChannelConstructor(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<PDocumentChannelParent>
|
||||
NeckoParent::AllocPDocumentChannelParent(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& args) {
|
||||
nsCOMPtr<nsIPrincipal> requestingPrincipal =
|
||||
GetRequestingPrincipal(Some(args.loadInfo()));
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
const char* error = CreateChannelLoadContext(
|
||||
aBrowser, Manager(), aSerialized, requestingPrincipal, loadContext);
|
||||
if (error) {
|
||||
return nullptr;
|
||||
}
|
||||
PBOverrideStatus overrideStatus =
|
||||
PBOverrideStatusFromLoadContext(aSerialized);
|
||||
RefPtr<DocumentChannelParent> p =
|
||||
new DocumentChannelParent(aBrowser, loadContext, overrideStatus);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult NeckoParent::RecvPDocumentChannelConstructor(
|
||||
PDocumentChannelParent* aActor, const PBrowserOrId& aBrowser,
|
||||
const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& aArgs) {
|
||||
DocumentChannelParent* p = static_cast<DocumentChannelParent*>(aActor);
|
||||
if (!p->Init(aArgs)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PCookieServiceParent* NeckoParent::AllocPCookieServiceParent() {
|
||||
return new CookieServiceParent();
|
||||
}
|
||||
|
@ -127,6 +127,15 @@ class NeckoParent : public PNeckoParent {
|
||||
PTCPSocketParent* AllocPTCPSocketParent(const nsString& host,
|
||||
const uint16_t& port);
|
||||
|
||||
already_AddRefed<PDocumentChannelParent> AllocPDocumentChannelParent(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& args);
|
||||
virtual mozilla::ipc::IPCResult RecvPDocumentChannelConstructor(
|
||||
PDocumentChannelParent* aActor, const PBrowserOrId& aBrowser,
|
||||
const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& aArgs) override;
|
||||
bool DeallocPDocumentChannelParent(PDocumentChannelParent* channel);
|
||||
|
||||
bool DeallocPTCPSocketParent(PTCPSocketParent*);
|
||||
PTCPServerSocketParent* AllocPTCPServerSocketParent(
|
||||
const uint16_t& aLocalPort, const uint16_t& aBacklog,
|
||||
|
80
netwerk/ipc/PDocumentChannel.ipdl
Normal file
80
netwerk/ipc/PDocumentChannel.ipdl
Normal file
@ -0,0 +1,80 @@
|
||||
/* -*- 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 protocol PStreamFilter;
|
||||
include InputStreamParams;
|
||||
include URIParams;
|
||||
include PBackgroundSharedTypes;
|
||||
include NeckoChannelParams;
|
||||
include IPCServiceWorkerDescriptor;
|
||||
include IPCStream;
|
||||
include DOMTypes;
|
||||
|
||||
include "mozilla/net/NeckoMessageUtils.h";
|
||||
|
||||
using class nsHttpHeaderArray from "nsHttpHeaderArray.h";
|
||||
using mozilla::net::NetAddr from "mozilla/net/DNS.h";
|
||||
using struct mozilla::net::ResourceTimingStruct from "mozilla/net/TimingStruct.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
refcounted protocol PDocumentChannel
|
||||
{
|
||||
manager PNecko;
|
||||
|
||||
parent:
|
||||
|
||||
async Suspend();
|
||||
async Resume();
|
||||
|
||||
async Cancel(nsresult status);
|
||||
|
||||
async __delete__();
|
||||
|
||||
child:
|
||||
|
||||
// Used to cancel child channel if we hit errors during creating and
|
||||
// AsyncOpen of nsHttpChannel on the parent.
|
||||
async FailedAsyncOpen(nsresult status);
|
||||
|
||||
async NotifyChannelClassifierProtectionDisabled(uint32_t acceptedReason);
|
||||
async NotifyCookieAllowed();
|
||||
async NotifyCookieBlocked(uint32_t rejectedReason);
|
||||
|
||||
async SetClassifierMatchedInfo(nsCString list, nsCString provider, nsCString fullHash);
|
||||
async SetClassifierMatchedTrackingInfo(nsCString lists, nsCString fullHash);
|
||||
|
||||
// This message is sent to a child that has been redirected to another process.
|
||||
// As a consequence, it should cleanup the channel listeners and remove the
|
||||
// request from the loadGroup.
|
||||
async CancelForProcessSwitch();
|
||||
|
||||
async RedirectToRealChannel(uint32_t aRegistrarId,
|
||||
nsIURI aURI,
|
||||
uint32_t aNewLoadFlags,
|
||||
ReplacementChannelConfigInit? aInit,
|
||||
LoadInfoArgs? aLoadInfo,
|
||||
uint64_t aChannelId,
|
||||
nsIURI aOriginalURI,
|
||||
uint32_t aRedirectMode,
|
||||
uint32_t aRedirectFlags,
|
||||
uint32_t? aContentDisposition,
|
||||
nsString? aContentDispositionFilename) returns(nsresult rv);
|
||||
|
||||
async ConfirmRedirect(nsIURI aNewURI) returns(nsresult rv);
|
||||
|
||||
// Tell child to delete channel (all IPDL deletes must be done from child to
|
||||
// avoid races: see bug 591708).
|
||||
async DeleteSelf();
|
||||
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -29,6 +29,7 @@ include protocol PClassifierDummyChannel;
|
||||
include protocol PWebrtcProxyChannel;
|
||||
include protocol PSocketProcessBridge;
|
||||
include protocol PProxyConfigLookup;
|
||||
include protocol PDocumentChannel;
|
||||
|
||||
include IPCStream;
|
||||
include URIParams;
|
||||
@ -69,6 +70,7 @@ nested(upto inside_cpow) sync protocol PNecko
|
||||
manages PClassifierDummyChannel;
|
||||
manages PWebrtcProxyChannel;
|
||||
manages PProxyConfigLookup;
|
||||
manages PDocumentChannel;
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
@ -88,6 +90,10 @@ parent:
|
||||
async PDNSRequest(nsCString hostName, OriginAttributes originAttributes,
|
||||
uint32_t flags);
|
||||
|
||||
async PDocumentChannel(PBrowserOrId browser,
|
||||
SerializedLoadContext loadContext,
|
||||
DocumentChannelCreationArgs args);
|
||||
|
||||
async PWebSocketEventListener(uint64_t aInnerWindowID);
|
||||
|
||||
/* Predictor Methods */
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
EXPORTS.mozilla.net += [
|
||||
'ChannelEventQueue.h',
|
||||
'DocumentChannelChild.h',
|
||||
'DocumentChannelParent.h',
|
||||
'NeckoChild.h',
|
||||
'NeckoCommon.h',
|
||||
'NeckoMessageUtils.h',
|
||||
@ -21,6 +23,8 @@ EXPORTS.mozilla.net += [
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ChannelEventQueue.cpp',
|
||||
'DocumentChannelChild.cpp',
|
||||
'DocumentChannelParent.cpp',
|
||||
'NeckoChild.cpp',
|
||||
'NeckoCommon.cpp',
|
||||
'NeckoParent.cpp',
|
||||
@ -37,6 +41,7 @@ IPDL_SOURCES = [
|
||||
'NeckoChannelParams.ipdlh',
|
||||
'PChannelDiverter.ipdl',
|
||||
'PDataChannel.ipdl',
|
||||
'PDocumentChannel.ipdl',
|
||||
'PFileChannel.ipdl',
|
||||
'PNecko.ipdl',
|
||||
'PSimpleChannel.ipdl',
|
||||
|
@ -753,8 +753,14 @@ bool HttpChannelParent::ConnectChannel(const uint32_t& registrarId,
|
||||
nsCOMPtr<nsINetworkInterceptController> controller;
|
||||
NS_QueryNotificationCallbacks(channel, controller);
|
||||
RefPtr<ParentChannelListener> parentListener = do_QueryObject(controller);
|
||||
MOZ_ASSERT(parentListener);
|
||||
parentListener->SetupInterceptionAfterRedirect(shouldIntercept);
|
||||
if (parentListener) {
|
||||
// It's possible with DocumentChannel redirects that we failed to Suspend
|
||||
// the nsHttpChannel, so it has delivered OnDataAvailable/OnStopRequest
|
||||
// to the DocumentChannelParent, and then cleared the listener pointer.
|
||||
// In that case the DocumentChannelParent will handle forwarding
|
||||
// those messages to us so we don't need to add the listener again.
|
||||
parentListener->SetupInterceptionAfterRedirect(shouldIntercept);
|
||||
}
|
||||
|
||||
if (mPBOverride != kPBOverride_Unset) {
|
||||
// redirected-to channel may not support PB
|
||||
|
@ -51,6 +51,7 @@ EXPORTS.mozilla.net += [
|
||||
'HttpInfo.h',
|
||||
'nsServerTiming.h',
|
||||
'NullHttpChannel.h',
|
||||
'ParentChannelListener.h',
|
||||
'PHttpChannelParams.h',
|
||||
'PSpdyPush.h',
|
||||
'TimingStruct.h',
|
||||
|
@ -46,17 +46,7 @@ namespace net {
|
||||
|
||||
class nsChannelClassifier;
|
||||
class Http2PushedStream;
|
||||
|
||||
class HttpChannelSecurityWarningReporter : public nsISupports {
|
||||
public:
|
||||
virtual MOZ_MUST_USE nsresult ReportSecurityMessage(
|
||||
const nsAString& aMessageTag, const nsAString& aMessageCategory) = 0;
|
||||
virtual MOZ_MUST_USE nsresult LogBlockedCORSRequest(
|
||||
const nsAString& aMessage, const nsACString& aCategory) = 0;
|
||||
virtual MOZ_MUST_USE nsresult
|
||||
LogMimeTypeMismatch(const nsACString& aMessageName, bool aWarning,
|
||||
const nsAString& aURL, const nsAString& aContentType) = 0;
|
||||
};
|
||||
class HttpChannelSecurityWarningReporter;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel
|
||||
|
@ -247,7 +247,11 @@ add_task(async function() {
|
||||
}
|
||||
);
|
||||
|
||||
let browser1LoadHasStopped = BrowserTestUtils.browserStopped(browser1);
|
||||
let browser1LoadHasStopped = BrowserTestUtils.browserStopped(
|
||||
browser1,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
await BrowserTestUtils.loadURI(
|
||||
browser1,
|
||||
@ -267,7 +271,11 @@ add_task(async function() {
|
||||
"example.org",
|
||||
true
|
||||
);
|
||||
let browser1LoadHasStoppedAgain = BrowserTestUtils.browserStopped(browser1);
|
||||
let browser1LoadHasStoppedAgain = BrowserTestUtils.browserStopped(
|
||||
browser1,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
await BrowserTestUtils.loadURI(
|
||||
browser1,
|
||||
kRoot1 + "redirect.sjs?" + kRoot2 + "dummy.html"
|
||||
|
Loading…
Reference in New Issue
Block a user