--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8364,20 +8364,18 @@ nsContentUtils::SetFetchReferrerURIWithP
referrerURI = docCurURI;
}
}
if (!referrerURI) {
referrerURI = principalURI;
}
- net::ReferrerPolicy referrerPolicy = aReferrerPolicy;
- if (referrerPolicy == net::RP_Default) {
- referrerPolicy = aDoc->GetReferrerPolicy();
- }
+ net::ReferrerPolicy referrerPolicy = (aReferrerPolicy != net::RP_Unset) ?
+ aReferrerPolicy : net::RP_Default;
return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
}
// static
net::ReferrerPolicy
nsContentUtils::GetReferrerPolicyFromHeader(const nsAString& aHeader)
{
// Multiple headers could be concatenated into one comma-separated
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -29,16 +29,17 @@
#include "nsStringStream.h"
#include "nsHttpChannel.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/workers/Workers.h"
#include "mozilla/Unused.h"
#include "Fetch.h"
+#include "FetchUtil.h"
#include "InternalRequest.h"
#include "InternalResponse.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS(FetchDriver,
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
@@ -244,72 +245,55 @@ FetchDriver::HttpFetch()
nsAutoCString method;
mRequest->GetMethod(method);
rv = httpChan->SetRequestMethod(method);
NS_ENSURE_SUCCESS(rv, rv);
// Set the same headers.
SetRequestHeaders(httpChan);
- // Step 2. Set the referrer.
- nsAutoString referrer;
- mRequest->GetReferrer(referrer);
-
- // The Referrer Policy in Request can be used to override a referrer policy
- // associated with an environment settings object.
- // If there's no Referrer Policy in the request, it should be inherited
- // from environment.
+ // If request's referrer policy is the empty string and request's client is
+ // non-null, then set request's referrer policy to request's client's
+ // associated referrer policy.
+ // If request's referrer policy is the empty string, then set request's
+ // referrer policy to "no-referrer-when-downgrade".
+ // If request's referrer is not "no-referrer", set request's referrer to the
+ // result of invoking determine request's referrer.
ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
net::ReferrerPolicy net_referrerPolicy = mRequest->GetEnvironmentReferrerPolicy();
switch (referrerPolicy) {
- case ReferrerPolicy::_empty:
- break;
- case ReferrerPolicy::No_referrer:
- net_referrerPolicy = net::RP_No_Referrer;
- break;
- case ReferrerPolicy::No_referrer_when_downgrade:
- net_referrerPolicy = net::RP_No_Referrer_When_Downgrade;
- break;
- case ReferrerPolicy::Origin:
- net_referrerPolicy = net::RP_Origin;
- break;
- case ReferrerPolicy::Origin_when_cross_origin:
- net_referrerPolicy = net::RP_Origin_When_Crossorigin;
- break;
- case ReferrerPolicy::Unsafe_url:
- net_referrerPolicy = net::RP_Unsafe_URL;
- break;
- default:
- MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
- break;
+ case ReferrerPolicy::_empty:
+ break;
+ case ReferrerPolicy::No_referrer:
+ net_referrerPolicy = net::RP_No_Referrer;
+ break;
+ case ReferrerPolicy::No_referrer_when_downgrade:
+ net_referrerPolicy = net::RP_No_Referrer_When_Downgrade;
+ break;
+ case ReferrerPolicy::Origin:
+ net_referrerPolicy = net::RP_Origin;
+ break;
+ case ReferrerPolicy::Origin_when_cross_origin:
+ net_referrerPolicy = net::RP_Origin_When_Crossorigin;
+ break;
+ case ReferrerPolicy::Unsafe_url:
+ net_referrerPolicy = net::RP_Unsafe_URL;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
+ break;
}
- if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
- rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal,
- mDocument,
- httpChan,
- net_referrerPolicy);
- NS_ENSURE_SUCCESS(rv, rv);
- } else if (referrer.IsEmpty()) {
- rv = httpChan->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- // From "Determine request's Referrer" step 3
- // "If request's referrer is a URL, let referrerSource be request's
- // referrer."
- nsCOMPtr<nsIURI> referrerURI;
- rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
- NS_ENSURE_SUCCESS(rv, rv);
- rv =
- httpChan->SetReferrerWithPolicy(referrerURI,
- referrerPolicy == ReferrerPolicy::_empty ?
- mRequest->GetEnvironmentReferrerPolicy() :
- net_referrerPolicy);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ // Set request's referrer
+ rv = FetchUtil::SetRequestReferrer(mPrincipal,
+ mDocument,
+ httpChan,
+ mRequest,
+ net_referrerPolicy);
+ NS_ENSURE_SUCCESS(rv, rv);
// Bug 1120722 - Authorization will be handled later.
// Auth may require prompting, we don't support it yet.
// The next patch in this same bug prevents this from aborting the request.
// Credentials checks for CORS are handled by nsCORSListenerProxy,
nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
@@ -725,20 +709,31 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
referrerPolicy = ReferrerPolicy::Unsafe_url;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
break;
}
mRequest->SetReferrerPolicy(referrerPolicy);
+ // Should update channel's referrer policy
+ if (httpChannel) {
+ rv = FetchUtil::SetRequestReferrer(mPrincipal,
+ mDocument,
+ httpChannel,
+ mRequest,
+ net_referrerPolicy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
}
}
- aCallback->OnRedirectVerifyCallback(NS_OK);
+ if (NS_SUCCEEDED(rv)) {
+ aCallback->OnRedirectVerifyCallback(NS_OK);
+ }
return NS_OK;
}
NS_IMETHODIMP
FetchDriver::CheckListenerChain()
{
return NS_OK;
}
--- a/dom/fetch/FetchUtil.cpp
+++ b/dom/fetch/FetchUtil.cpp
@@ -1,15 +1,17 @@
#include "FetchUtil.h"
#include "nsError.h"
#include "nsIUnicodeDecoder.h"
#include "nsString.h"
+#include "nsIDocument.h"
#include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/InternalRequest.h"
namespace mozilla {
namespace dom {
// static
nsresult
FetchUtil::GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod)
{
@@ -103,10 +105,62 @@ FetchUtil::ExtractHeader(nsACString::con
if (!NS_IsReasonableHTTPHeaderValue(aHeaderValue)) {
return false;
}
aHeaderValue.CompressWhitespace();
return PushOverLine(aStart);
}
+// static
+nsresult
+FetchUtil::SetRequestReferrer(nsIPrincipal* aPrincipal,
+ nsIDocument* aDoc,
+ nsIHttpChannel* aChannel,
+ InternalRequest* aRequest,
+ net::ReferrerPolicy aPolicy) {
+ nsAutoString referrer;
+ aRequest->GetReferrer(referrer);
+
+ nsresult rv = NS_OK;
+ if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
+ rv = nsContentUtils::SetFetchReferrerURIWithPolicy(aPrincipal,
+ aDoc,
+ aChannel,
+ aPolicy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (referrer.IsEmpty()) {
+ rv = aChannel->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ // From "Determine request's Referrer" step 3
+ // "If request's referrer is a URL, let referrerSource be request's
+ // referrer."
+ nsCOMPtr<nsIURI> referrerURI;
+ rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aChannel->SetReferrerWithPolicy(referrerURI, aPolicy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr<nsIURI> referrerURI;
+ aChannel->GetReferrer(getter_AddRefs(referrerURI));
+
+ // Step 2. Set the referrer.
+ if (referrerURI) {
+ nsAutoString referrerURL;
+ nsAutoCString spec;
+
+ rv = referrerURI->GetSpec(spec);
+ CopyUTF8toUTF16(spec, referrerURL);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ aRequest->SetReferrer(referrerURL);
+ } else {
+ aRequest->SetReferrer(EmptyString());
+ }
+
+ return NS_OK;
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/fetch/FetchUtil.h
+++ b/dom/fetch/FetchUtil.h
@@ -3,19 +3,25 @@
#include "nsString.h"
#include "nsError.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FormData.h"
+class nsIPrincipal;
+class nsIDocument;
+class nsIHttpChannel;
+
namespace mozilla {
namespace dom {
+class InternalRequest;
+
class FetchUtil final
{
private:
FetchUtil() = delete;
public:
/**
* Sets outMethod to a valid HTTP request method string based on an input method.
@@ -30,13 +36,20 @@ public:
* Extracts an HTTP header from a substring range.
*/
static bool
ExtractHeader(nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd,
nsCString& aHeaderName,
nsCString& aHeaderValue,
bool* aWasEmptyHeader);
+
+ static nsresult
+ SetRequestReferrer(nsIPrincipal* aPrincipal,
+ nsIDocument* aDoc,
+ nsIHttpChannel* aChannel,
+ InternalRequest* aRequest,
+ net::ReferrerPolicy aPolicy);
};
} // namespace dom
} // namespace mozilla
#endif
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -199,18 +199,20 @@ ChannelFromScriptURL(nsIPrincipal* princ
nullptr, // aCallbacks
aLoadFlags,
ios);
}
NS_ENSURE_SUCCESS(rv, rv);
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
+ mozilla::net::ReferrerPolicy referrerPolicy = parentDoc ?
+ parentDoc->GetReferrerPolicy() : mozilla::net::RP_Default;
rv = nsContentUtils::SetFetchReferrerURIWithPolicy(principal, parentDoc,
- httpChannel, mozilla::net::RP_Default);
+ httpChannel, referrerPolicy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
channel.forget(aChannel);
return rv;
}
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -2467,19 +2467,20 @@ XMLHttpRequestMainThread::InitiateFetch(
mAuthorRequestHeaders.Set("accept", NS_LITERAL_CSTRING("*/*"));
}
mAuthorRequestHeaders.ApplyToChannel(httpChannel);
if (!IsSystemXHR()) {
nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
nsCOMPtr<nsIDocument> doc = owner ? owner->GetExtantDoc() : nullptr;
+ mozilla::net::ReferrerPolicy referrerPolicy = doc ?
+ doc->GetReferrerPolicy() : mozilla::net::RP_Default;
nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc,
- httpChannel,
- mozilla::net::RP_Default);
+ httpChannel, referrerPolicy);
}
// Some extensions override the http protocol handler and provide their own
// implementation. The channels returned from that implementation don't
// always seem to implement the nsIUploadChannel2 interface, presumably
// because it's a new interface. Eventually we should remove this and simply
// require that http channels implement the new interface (see bug 529041).
nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(httpChannel);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1276,25 +1276,24 @@ HttpBaseChannel::SetReferrerWithPolicy(n
ENSURE_CALLED_BEFORE_CONNECT();
// clear existing referrer, if any
mReferrer = nullptr;
nsresult rv = mRequestHead.ClearHeader(nsHttp::Referer);
if(NS_FAILED(rv)) {
return rv;
}
- mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
+ mReferrerPolicy = referrerPolicy;
if (!referrer) {
return NS_OK;
}
// Don't send referrer at all when the meta referrer setting is "no-referrer"
if (referrerPolicy == REFERRER_POLICY_NO_REFERRER) {
- mReferrerPolicy = REFERRER_POLICY_NO_REFERRER;
return NS_OK;
}
// 0: never send referer
// 1: send referer for direct user action
// 2: always send referer
uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel();
@@ -1562,17 +1561,16 @@ HttpBaseChannel::SetReferrerWithPolicy(n
if (NS_FAILED(rv)) return rv;
}
// finally, remember the referrer URI and set the Referer header.
rv = SetRequestHeader(NS_LITERAL_CSTRING("Referer"), spec, false);
if (NS_FAILED(rv)) return rv;
mReferrer = clone;
- mReferrerPolicy = referrerPolicy;
return NS_OK;
}
// Return the channel's proxy URI, or if it doesn't exist, the
// channel's main URI.
NS_IMETHODIMP
HttpBaseChannel::GetProxyURI(nsIURI **aOut)
{
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1561,16 +1561,21 @@ public:
}
};
NS_IMETHODIMP
HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
{
LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
OptionalURIParams redirectURI;
+
+ uint32_t referrerPolicy;
+ OptionalURIParams referrerURI;
+ SerializeURI(nullptr, referrerURI);
+
nsCOMPtr<nsIHttpChannel> newHttpChannel =
do_QueryInterface(mRedirectChannelChild);
if (NS_SUCCEEDED(result) && !mRedirectChannelChild) {
// mRedirectChannelChild doesn't exist means we're redirecting to a protocol
// that doesn't implement nsIChildChannel. The redirect result should be set
// as failed by veto listeners and shouldn't enter this condition. As the
// last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here
@@ -1578,16 +1583,21 @@ HttpChannelChild::OnRedirectVerifyCallba
// another protocol and throw an error.
LOG((" redirecting to a protocol that doesn't implement nsIChildChannel"));
result = NS_ERROR_DOM_BAD_URI;
}
if (newHttpChannel) {
// Must not be called until after redirect observers called.
newHttpChannel->SetOriginalURI(mOriginalURI);
+ newHttpChannel->GetReferrerPolicy(&referrerPolicy);
+ nsCOMPtr<nsIURI> newChannelReferrerURI;
+ newHttpChannel->GetReferrer(getter_AddRefs(newChannelReferrerURI));
+
+ SerializeURI(newChannelReferrerURI, referrerURI);
}
if (mRedirectingForSubsequentSynthesizedResponse) {
nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(mRedirectChannelChild);
MOZ_ASSERT(httpChannelChild);
RefPtr<HttpChannelChild> redirectedChannel =
static_cast<HttpChannelChild*>(httpChannelChild.get());
@@ -1640,18 +1650,18 @@ HttpChannelChild::OnRedirectVerifyCallba
nsCOMPtr<nsIRequest> request = do_QueryInterface(mRedirectChannelChild);
if (request) {
request->GetLoadFlags(&loadFlags);
}
}
if (mIPCOpen)
- SendRedirect2Verify(result, *headerTuples, loadFlags, redirectURI,
- corsPreflightArgs);
+ SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy,
+ referrerURI, redirectURI, corsPreflightArgs);
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIRequest
//-----------------------------------------------------------------------------
@@ -2021,16 +2031,41 @@ HttpChannelChild::ContinueAsyncOpen()
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIHttpChannel
//-----------------------------------------------------------------------------
NS_IMETHODIMP
+HttpChannelChild::SetReferrer(nsIURI *referrer)
+{
+ return SetReferrerWithPolicy(referrer, REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE);
+}
+
+NS_IMETHODIMP
+HttpChannelChild::SetReferrerWithPolicy(nsIURI *referrer,
+ uint32_t referrerPolicy)
+{
+ ENSURE_CALLED_BEFORE_CONNECT();
+
+ // remove old referrer if any
+ for (uint32_t i = 0; i < mClientSetRequestHeaders.Length(); i++ ) {
+ if (NS_LITERAL_CSTRING("Referer").Equals(mClientSetRequestHeaders[i].mHeader)) {
+ mClientSetRequestHeaders.RemoveElementAt(i);
+ }
+ }
+
+ nsresult rv = HttpBaseChannel::SetReferrerWithPolicy(referrer, referrerPolicy);
+ if (NS_FAILED(rv))
+ return rv;
+ return NS_OK;
+
+}
+NS_IMETHODIMP
HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue,
bool aMerge)
{
LOG(("HttpChannelChild::SetRequestHeader [this=%p]\n", this));
nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
if (NS_FAILED(rv))
return rv;
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -74,16 +74,18 @@ public:
NS_IMETHOD Suspend() override;
NS_IMETHOD Resume() override;
// nsIChannel
NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo) override;
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
// HttpBaseChannel::nsIHttpChannel
+ NS_IMETHOD SetReferrer(nsIURI *referrer) override;
+ NS_IMETHOD SetReferrerWithPolicy(nsIURI *referrer, uint32_t referrerPolicy) override;
NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue,
bool aMerge) override;
NS_IMETHOD SetEmptyRequestHeader(const nsACString& aHeader) override;
NS_IMETHOD RedirectTo(nsIURI *newURI) override;
NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override;
// nsIHttpChannelInternal
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -625,16 +625,18 @@ HttpChannelParent::RecvUpdateAssociatedC
}
return true;
}
bool
HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
const RequestHeaderTuples& changedHeaders,
const uint32_t& loadFlags,
+ const uint32_t& referrerPolicy,
+ const OptionalURIParams& aReferrerURI,
const OptionalURIParams& aAPIRedirectURI,
const OptionalCorsPreflightArgs& aCorsPreflightArgs)
{
LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%x]\n",
this, result));
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIHttpChannel> newHttpChannel =
do_QueryInterface(mRedirectChannel);
@@ -663,16 +665,19 @@ HttpChannelParent::RecvRedirect2Verify(c
if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
nsCOMPtr<nsIHttpChannelInternal> newInternalChannel =
do_QueryInterface(newHttpChannel);
MOZ_RELEASE_ASSERT(newInternalChannel);
const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders());
}
+
+ nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
+ newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy);
}
}
if (!mRedirectCallback) {
// This should according the logic never happen, log the situation.
if (mReceivedRedirect2Verify)
LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
if (mSentRedirect1BeginFailed)
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -146,16 +146,18 @@ protected:
virtual bool RecvSetClassOfService(const uint32_t& cos) override;
virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) override;
virtual bool RecvSuspend() override;
virtual bool RecvResume() override;
virtual bool RecvCancel(const nsresult& status) override;
virtual bool RecvRedirect2Verify(const nsresult& result,
const RequestHeaderTuples& changedHeaders,
const uint32_t& loadFlags,
+ const uint32_t& referrerPolicy,
+ const OptionalURIParams& aReferrerURI,
const OptionalURIParams& apiRedirectUri,
const OptionalCorsPreflightArgs& aCorsPreflightArgs) override;
virtual bool RecvUpdateAssociatedContentSecurity(const int32_t& broken,
const int32_t& no) override;
virtual bool RecvDocumentChannelCleanup() override;
virtual bool RecvMarkOfflineCacheEntryAsForeign() override;
virtual bool RecvDivertOnDataAvailable(const nsCString& data,
const uint64_t& offset,
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -40,17 +40,19 @@ parent:
int32_t no);
async Suspend();
async Resume();
async Cancel(nsresult status);
// Reports approval/veto of redirect by child process redirect observers
async Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders,
- uint32_t loadFlags, OptionalURIParams apiRedirectTo,
+ uint32_t loadFlags, uint32_t referrerPolicy,
+ OptionalURIParams referrerUri,
+ OptionalURIParams apiRedirectTo,
OptionalCorsPreflightArgs corsPreflightArgs);
// For document loads we keep this protocol open after child's
// OnStopRequest, and send this msg (instead of __delete__) to allow
// partial cleanup on parent.
async DocumentChannelCleanup();
// This might have to be sync. If this fails we must fail the document load