From 467f6725fcf180a17768e14a51ea59eade9ee9f0 Mon Sep 17 00:00:00 2001 From: Kershaw Chang Date: Thu, 7 May 2020 11:12:46 +0000 Subject: [PATCH] Bug 1623380 - Send ODA directly to content process r=dragana Differential Revision: https://phabricator.services.mozilla.com/D67609 --- dom/media/gmp/PChromiumCDM.ipdl | 2 + ipc/glue/BackgroundParentImpl.cpp | 12 ++ ipc/glue/BackgroundParentImpl.h | 3 + ipc/glue/PBackground.ipdl | 4 + modules/libpref/init/StaticPrefList.yaml | 6 + netwerk/base/nsIOService.cpp | 1 + netwerk/ipc/SocketProcessChild.cpp | 24 ++- netwerk/ipc/SocketProcessChild.h | 12 ++ .../http/BackgroundDataBridgeChild.cpp | 39 +++++ .../protocol/http/BackgroundDataBridgeChild.h | 37 +++++ .../http/BackgroundDataBridgeParent.cpp | 39 +++++ .../http/BackgroundDataBridgeParent.h | 32 ++++ .../protocol/http/DelayHttpChannelQueue.cpp | 4 + netwerk/protocol/http/Http2Compression.cpp | 1 + .../http/HttpBackgroundChannelChild.cpp | 47 +++++- .../http/HttpBackgroundChannelChild.h | 17 ++- .../http/HttpBackgroundChannelParent.cpp | 2 +- netwerk/protocol/http/HttpChannelChild.cpp | 31 ++++ netwerk/protocol/http/HttpChannelChild.h | 1 + netwerk/protocol/http/HttpChannelParent.cpp | 6 + .../protocol/http/HttpTransactionChild.cpp | 137 ++++++++++++++++-- netwerk/protocol/http/HttpTransactionChild.h | 21 ++- .../protocol/http/HttpTransactionParent.cpp | 26 +++- netwerk/protocol/http/HttpTransactionParent.h | 13 +- netwerk/protocol/http/HttpTransactionShell.h | 3 + .../protocol/http/PBackgroundDataBridge.ipdl | 25 ++++ .../protocol/http/PHttpBackgroundChannel.ipdl | 3 +- netwerk/protocol/http/PHttpTransaction.ipdl | 6 +- netwerk/protocol/http/moz.build | 5 + netwerk/protocol/http/nsHttpChannel.cpp | 20 ++- netwerk/protocol/http/nsHttpChannel.h | 6 + netwerk/protocol/http/nsHttpResponseHead.cpp | 2 +- netwerk/protocol/http/nsHttpResponseHead.h | 2 +- netwerk/protocol/http/nsHttpTransaction.cpp | 2 + 34 files changed, 548 insertions(+), 43 deletions(-) create mode 100644 netwerk/protocol/http/BackgroundDataBridgeChild.cpp create mode 100644 netwerk/protocol/http/BackgroundDataBridgeChild.h create mode 100644 netwerk/protocol/http/BackgroundDataBridgeParent.cpp create mode 100644 netwerk/protocol/http/BackgroundDataBridgeParent.h create mode 100644 netwerk/protocol/http/PBackgroundDataBridge.ipdl diff --git a/dom/media/gmp/PChromiumCDM.ipdl b/dom/media/gmp/PChromiumCDM.ipdl index 595deca95624..6162f6f53ed0 100644 --- a/dom/media/gmp/PChromiumCDM.ipdl +++ b/dom/media/gmp/PChromiumCDM.ipdl @@ -8,6 +8,8 @@ include GMPTypes; using cdm::HdcpVersion from "content_decryption_module.h"; +include "GMPMessageUtils.h"; + namespace mozilla { namespace gmp { diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index 9b9090314a5f..8d6cb48e3b5d 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -57,6 +57,7 @@ #include "mozilla/ipc/PParentToChildStreamParent.h" #include "mozilla/layout/VsyncParent.h" #include "mozilla/net/HttpBackgroundChannelParent.h" +#include "mozilla/net/BackgroundDataBridgeParent.h" #include "mozilla/dom/network/UDPSocketParent.h" #include "mozilla/dom/WebAuthnTransactionParent.h" #include "mozilla/Preferences.h" @@ -136,6 +137,17 @@ void BackgroundParentImpl::ActorDestroy(ActorDestroyReason aWhy) { AssertIsOnBackgroundThread(); } +already_AddRefed +BackgroundParentImpl::AllocPBackgroundDataBridgeParent( + const uint64_t& aChannelID) { + MOZ_ASSERT(XRE_IsSocketProcess(), "Should be in socket process"); + AssertIsOnBackgroundThread(); + + RefPtr actor = + new net::BackgroundDataBridgeParent(aChannelID); + return actor.forget(); +} + BackgroundParentImpl::PBackgroundTestParent* BackgroundParentImpl::AllocPBackgroundTestParent(const nsCString& aTestArg) { AssertIsInMainOrSocketProcess(); diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index fdc89c396f19..6857dfa8640a 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -47,6 +47,9 @@ class BackgroundParentImpl : public PBackgroundParent, virtual already_AddRefed AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo) override; + virtual already_AddRefed + AllocPBackgroundDataBridgeParent(const uint64_t& aChannelID) override; + virtual mozilla::ipc::IPCResult RecvPBackgroundIDBFactoryConstructor( PBackgroundIDBFactoryParent* aActor, const LoggingInfo& aLoggingInfo) override; diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index a9aa6d14f1a1..599954078b13 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -2,6 +2,7 @@ * 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 PBackgroundDataBridge; include protocol PBackgroundIDBFactory; include protocol PBackgroundIndexedDBUtils; include protocol PBackgroundSDBConnection; @@ -72,6 +73,7 @@ namespace ipc { sync protocol PBackground { + manages PBackgroundDataBridge; manages PBackgroundIDBFactory; manages PBackgroundIndexedDBUtils; manages PBackgroundSDBConnection; @@ -122,6 +124,8 @@ parent: // Only called at startup during mochitests to check the basic infrastructure. async PBackgroundTest(nsCString testArg); + async PBackgroundDataBridge(uint64_t channelID); + async PBackgroundIDBFactory(LoggingInfo loggingInfo); async PBackgroundIndexedDBUtils(); diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index d2e41d9b7142..006694ae3326 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -7688,6 +7688,12 @@ #endif #endif +# Whether we can send OnDataAvailable to content process directly. +- name: network.send_ODA_to_content_directly + type: RelaxedAtomicBool + value: true + mirror: always + # Telemetry of traffic categories. Whether or not to enable HttpTrafficAnalyzer. - name: network.traffic_analyzer.enabled type: RelaxedAtomicBool diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 77a91c50167e..c19dd69d819d 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -222,6 +222,7 @@ static const char* gCallbackPrefsForSocketProcess[] = { WEBRTC_PREF_PREFIX, NETWORK_DNS_PREF, "network.ssl_tokens_cache_enabled", + "network.send_ODA_to_content_directly", nullptr, }; diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index bba7f8dafa6a..024d7b78d77a 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -14,10 +14,12 @@ #include "mozilla/dom/MemoryReportRequest.h" #include "mozilla/ipc/CrashReporterClient.h" #include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/FileDescriptorSetChild.h" #include "mozilla/ipc/IPCStreamAlloc.h" #include "mozilla/ipc/ProcessChild.h" #include "mozilla/net/AltSvcTransactionChild.h" +#include "mozilla/net/BackgroundDataBridgeParent.h" #include "mozilla/net/DNSRequestChild.h" #include "mozilla/net/DNSRequestParent.h" #include "mozilla/ipc/PChildToParentStreamChild.h" @@ -58,7 +60,8 @@ using namespace ipc; SocketProcessChild* sSocketProcessChild; -SocketProcessChild::SocketProcessChild() : mShuttingDown(false) { +SocketProcessChild::SocketProcessChild() + : mShuttingDown(false), mMutex("SocketProcessChild::mMutex") { LOG(("CONSTRUCT SocketProcessChild::SocketProcessChild\n")); nsDebugImpl::SetMultiprocessMode("Socket"); @@ -381,5 +384,24 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvPDNSRequestConstructor( return IPC_OK(); } +void SocketProcessChild::AddDataBridgeToMap( + uint64_t aChannelId, BackgroundDataBridgeParent* aActor) { + ipc::AssertIsOnBackgroundThread(); + MutexAutoLock lock(mMutex); + mBackgroundDataBridgeMap.Put(aChannelId, aActor); +} + +void SocketProcessChild::RemoveDataBridgeFromMap(uint64_t aChannelId) { + ipc::AssertIsOnBackgroundThread(); + MutexAutoLock lock(mMutex); + mBackgroundDataBridgeMap.Remove(aChannelId); +} + +Maybe> +SocketProcessChild::GetAndRemoveDataBridge(uint64_t aChannelId) { + MutexAutoLock lock(mMutex); + return mBackgroundDataBridgeMap.GetAndRemove(aChannelId); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/SocketProcessChild.h b/netwerk/ipc/SocketProcessChild.h index 35f69c7c6681..9cbd9904f968 100644 --- a/netwerk/ipc/SocketProcessChild.h +++ b/netwerk/ipc/SocketProcessChild.h @@ -8,6 +8,7 @@ #include "mozilla/net/PSocketProcessChild.h" #include "mozilla/ipc/InputStreamUtils.h" +#include "mozilla/Mutex.h" #include "nsRefPtrHashtable.h" namespace mozilla { @@ -18,6 +19,7 @@ namespace mozilla { namespace net { class SocketProcessBridgeParent; +class BackgroundDataBridgeParent; // The IPC actor implements PSocketProcessChild in child process. // This is allocated and kept alive by SocketProcessImpl. @@ -96,6 +98,12 @@ class SocketProcessChild final const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) override; + void AddDataBridgeToMap(uint64_t aChannelId, + BackgroundDataBridgeParent* aActor); + void RemoveDataBridgeFromMap(uint64_t aChannelId); + Maybe> GetAndRemoveDataBridge( + uint64_t aChannelId); + protected: friend class SocketProcessImpl; ~SocketProcessChild(); @@ -111,6 +119,10 @@ class SocketProcessChild final #endif bool mShuttingDown; + // Protect the table below. + Mutex mMutex; + nsDataHashtable> + mBackgroundDataBridgeMap; }; } // namespace net diff --git a/netwerk/protocol/http/BackgroundDataBridgeChild.cpp b/netwerk/protocol/http/BackgroundDataBridgeChild.cpp new file mode 100644 index 000000000000..bee637513ec1 --- /dev/null +++ b/netwerk/protocol/http/BackgroundDataBridgeChild.cpp @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/BackgroundDataBridgeChild.h" +#include "mozilla/net/HttpBackgroundChannelChild.h" + +namespace mozilla { +namespace net { + +BackgroundDataBridgeChild::BackgroundDataBridgeChild( + HttpBackgroundChannelChild* aBgChild) + : mBgChild(aBgChild), mBackgroundThread(NS_GetCurrentThread()) { + MOZ_ASSERT(aBgChild); +} + +BackgroundDataBridgeChild::~BackgroundDataBridgeChild() = default; + +void BackgroundDataBridgeChild::Destroy() { + RefPtr self = this; + MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch( + NS_NewRunnableFunction("BackgroundDataBridgeParent::Destroy", + [self]() { + if (self->CanSend()) { + Unused << self->Send__delete__(self); + } + }), + NS_DISPATCH_NORMAL)); +} + +mozilla::ipc::IPCResult BackgroundDataBridgeChild::RecvOnTransportAndData( + const uint64_t& offset, const uint32_t& count, const nsCString& data) { + MOZ_ASSERT(mBgChild); + return mBgChild->RecvOnTransportAndData(NS_OK, NS_NET_STATUS_RECEIVING_FROM, + offset, count, data, true); +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/BackgroundDataBridgeChild.h b/netwerk/protocol/http/BackgroundDataBridgeChild.h new file mode 100644 index 000000000000..e7923f0ba6e7 --- /dev/null +++ b/netwerk/protocol/http/BackgroundDataBridgeChild.h @@ -0,0 +1,37 @@ +/* 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_BackgroundDataBridgeChild_h +#define mozilla_net_BackgroundDataBridgeChild_h + +#include "mozilla/net/PBackgroundDataBridgeChild.h" +#include "mozilla/ipc/BackgroundChild.h" + +namespace mozilla { +namespace net { + +class HttpBackgroundChannelChild; + +class BackgroundDataBridgeChild final : public PBackgroundDataBridgeChild { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundDataBridgeChild, override) + + explicit BackgroundDataBridgeChild(HttpBackgroundChannelChild* aBgChild); + void Destroy(); + + protected: + virtual ~BackgroundDataBridgeChild(); + + RefPtr mBgChild; + nsCOMPtr mBackgroundThread; + + public: + mozilla::ipc::IPCResult RecvOnTransportAndData(const uint64_t& offset, + const uint32_t& count, + const nsCString& data); +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_BackgroundDataBridgeChild_h diff --git a/netwerk/protocol/http/BackgroundDataBridgeParent.cpp b/netwerk/protocol/http/BackgroundDataBridgeParent.cpp new file mode 100644 index 000000000000..6b448d8f2054 --- /dev/null +++ b/netwerk/protocol/http/BackgroundDataBridgeParent.cpp @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/BackgroundDataBridgeParent.h" +#include "mozilla/net/SocketProcessChild.h" +#include "mozilla/Unused.h" + +namespace mozilla { +namespace net { + +BackgroundDataBridgeParent::BackgroundDataBridgeParent(uint64_t aChannelID) + : mChannelID(aChannelID), mBackgroundThread(NS_GetCurrentThread()) { + SocketProcessChild::GetSingleton()->AddDataBridgeToMap(aChannelID, this); +} + +void BackgroundDataBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { + SocketProcessChild::GetSingleton()->RemoveDataBridgeFromMap(mChannelID); +} + +already_AddRefed BackgroundDataBridgeParent::GetBackgroundThread() { + nsCOMPtr thread = mBackgroundThread; + return thread.forget(); +} + +void BackgroundDataBridgeParent::Destroy() { + RefPtr self = this; + MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch( + NS_NewRunnableFunction("BackgroundDataBridgeParent::Destroy", + [self]() { + if (self->CanSend()) { + Unused << self->Send__delete__(self); + } + }), + NS_DISPATCH_NORMAL)); +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/BackgroundDataBridgeParent.h b/netwerk/protocol/http/BackgroundDataBridgeParent.h new file mode 100644 index 000000000000..415408af6681 --- /dev/null +++ b/netwerk/protocol/http/BackgroundDataBridgeParent.h @@ -0,0 +1,32 @@ +/* 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_BackgroundDataBridgeParent_h +#define mozilla_net_BackgroundDataBridgeParent_h + +#include "mozilla/net/PBackgroundDataBridgeParent.h" + +namespace mozilla { +namespace net { + +class BackgroundDataBridgeParent final : public PBackgroundDataBridgeParent { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundDataBridgeParent, override) + + explicit BackgroundDataBridgeParent(uint64_t aChannelID); + void ActorDestroy(ActorDestroyReason aWhy) override; + already_AddRefed GetBackgroundThread(); + void Destroy(); + + private: + virtual ~BackgroundDataBridgeParent() = default; + + uint64_t mChannelID; + nsCOMPtr mBackgroundThread; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_BackgroundDataBridgeParent_h diff --git a/netwerk/protocol/http/DelayHttpChannelQueue.cpp b/netwerk/protocol/http/DelayHttpChannelQueue.cpp index 7a7c129e94e0..7b6144f845a7 100644 --- a/netwerk/protocol/http/DelayHttpChannelQueue.cpp +++ b/netwerk/protocol/http/DelayHttpChannelQueue.cpp @@ -7,6 +7,10 @@ #include "DelayHttpChannelQueue.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" +#include "mozilla/TimeStamp.h" +#include "nsIObserverService.h" +#include "nsHttpChannel.h" +#include "nsThreadManager.h" using namespace mozilla; using namespace mozilla::net; diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp index 8270740fa0bf..7461ca94a6ac 100644 --- a/netwerk/protocol/http/Http2Compression.cpp +++ b/netwerk/protocol/http/Http2Compression.cpp @@ -18,6 +18,7 @@ #include "Http2HuffmanOutgoing.h" #include "mozilla/StaticPtr.h" #include "nsCharSeparatedTokenizer.h" +#include "nsIMemoryReporter.h" #include "nsHttpHandler.h" namespace mozilla { diff --git a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp index 59da92ec33c4..ed9d95e73bba 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp +++ b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp @@ -14,6 +14,7 @@ #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" #include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/net/BackgroundDataBridgeChild.h" #include "mozilla/Unused.h" #include "nsSocketTransportService2.h" @@ -46,6 +47,21 @@ nsresult HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild) { return NS_OK; } +void HttpBackgroundChannelChild::CreateDataBridge() { + MOZ_ASSERT(OnSocketThread()); + PBackgroundChild* actorChild = + BackgroundChild::GetOrCreateSocketActorForCurrentThread(); + if (NS_WARN_IF(!actorChild)) { + return; + } + + mDataBridgeChild = new BackgroundDataBridgeChild(this); + if (!actorChild->SendPBackgroundDataBridgeConstructor( + mDataBridgeChild, mChannelChild->ChannelId())) { + mDataBridgeChild = nullptr; + } +} + void HttpBackgroundChannelChild::OnChannelClosed() { LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this)); MOZ_ASSERT(OnSocketThread()); @@ -55,6 +71,11 @@ void HttpBackgroundChannelChild::OnChannelClosed() { // Remove pending IPC messages as well. mQueuedRunnables.Clear(); + + if (mDataBridgeChild) { + mDataBridgeChild->Destroy(); + mDataBridgeChild = nullptr; + } } void HttpBackgroundChannelChild::OnStartRequestReceived() { @@ -98,8 +119,18 @@ bool HttpBackgroundChannelChild::CreateBackgroundChannel() { return true; } -bool HttpBackgroundChannelChild::IsWaitingOnStartRequest() { +bool HttpBackgroundChannelChild::IsWaitingOnStartRequest( + bool aDataFromSocketProcess) { MOZ_ASSERT(OnSocketThread()); + + // When data is from socket process, it is possible that both mStartSent and + // mStartReceived are false here. We need to wait until OnStartRequest sent + // from parent process. + // TODO: We can remove this code when diversion is removed in bug 1604448. + if (aDataFromSocketProcess) { + return !mStartReceived; + } + // Need to wait for OnStartRequest if it is sent by // parent process but not received by content process. return (mStartSent && !mStartReceived); @@ -117,25 +148,29 @@ IPCResult HttpBackgroundChannelChild::RecvOnStartRequestSent() { IPCResult HttpBackgroundChannelChild::RecvOnTransportAndData( const nsresult& aChannelStatus, const nsresult& aTransportStatus, - const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) { - LOG(("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p]\n", this)); + const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData, + const bool& aDataFromSocketProcess) { + LOG( + ("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p, " + "aDataFromSocketProcess=%d]\n", + this, aDataFromSocketProcess)); MOZ_ASSERT(OnSocketThread()); if (NS_WARN_IF(!mChannelChild)) { return IPC_OK(); } - if (IsWaitingOnStartRequest()) { + if (IsWaitingOnStartRequest(aDataFromSocketProcess)) { LOG((" > pending until OnStartRequest [offset=%" PRIu64 " count=%" PRIu32 "]\n", aOffset, aCount)); mQueuedRunnables.AppendElement( NewRunnableMethod( + const uint32_t, const nsCString, bool>( "HttpBackgroundChannelChild::RecvOnTransportAndData", this, &HttpBackgroundChannelChild::RecvOnTransportAndData, aChannelStatus, - aTransportStatus, aOffset, aCount, aData)); + aTransportStatus, aOffset, aCount, aData, aDataFromSocketProcess)); return IPC_OK(); } diff --git a/netwerk/protocol/http/HttpBackgroundChannelChild.h b/netwerk/protocol/http/HttpBackgroundChannelChild.h index 0cfe25c62925..ba1872b00461 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelChild.h +++ b/netwerk/protocol/http/HttpBackgroundChannelChild.h @@ -17,11 +17,14 @@ using mozilla::ipc::IPCResult; namespace mozilla { namespace net { +class BackgroundDataBridgeChild; class HttpChannelChild; class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild { friend class BackgroundChannelCreateCallback; friend class PHttpBackgroundChannelChild; + friend class HttpChannelChild; + friend class BackgroundDataBridgeChild; public: explicit HttpBackgroundChannelChild(); @@ -45,7 +48,8 @@ class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild { const nsresult& aTransportStatus, const uint64_t& aOffset, const uint32_t& aCount, - const nsCString& aData); + const nsCString& aData, + const bool& aDataFromSocketProcess); IPCResult RecvOnStopRequest( const nsresult& aChannelStatus, const ResourceTimingStructArgs& aTiming, @@ -61,6 +65,8 @@ class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild { void ActorDestroy(ActorDestroyReason aWhy) override; + void CreateDataBridge(); + private: virtual ~HttpBackgroundChannelChild(); @@ -75,7 +81,12 @@ class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild { // OnStartRequestReceived. // return true after both RecvOnStartRequestSend and OnStartRequestReceived // are invoked. - bool IsWaitingOnStartRequest(); + // When ODA message is from socket process, it is possible that both + // RecvOnStartRequestSent and OnStartRequestReceived are not invoked, but + // RecvOnTransportAndData is already invoked. In this case, we only need to + // check if OnStartRequestReceived is invoked to make sure ODA doesn't happen + // before OnStartRequest. + bool IsWaitingOnStartRequest(bool aDataFromSocketProcess = false); // Associated HttpChannelChild for handling the channel events. // Will be removed while failed to create background channel, @@ -95,6 +106,8 @@ class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild { // Should be flushed after OnStartRequest is received and handled. // Should only access on STS thread. nsTArray> mQueuedRunnables; + + RefPtr mDataBridgeChild; }; } // namespace net diff --git a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp index 604d926b328e..6eb9422b4444 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp +++ b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp @@ -192,7 +192,7 @@ bool HttpBackgroundChannelParent::OnTransportAndData( } return SendOnTransportAndData(aChannelStatus, aTransportStatus, aOffset, - aCount, aData); + aCount, aData, false); } bool HttpBackgroundChannelParent::OnStopRequest( diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 131835774e3e..ec3d5e70ce4c 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -43,6 +43,8 @@ #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/net/ChannelDiverterChild.h" #include "mozilla/net/DNS.h" +#include "mozilla/net/SocketProcessBridgeChild.h" +#include "mozilla/StaticPrefs_network.h" #include "mozilla/StoragePrincipalHelper.h" #include "SerializedLoadContext.h" #include "nsInputStreamPump.h" @@ -60,6 +62,7 @@ #include "nsCORSListenerProxy.h" #include "nsApplicationCache.h" #include "ClassifierDummyChannel.h" +#include "nsIOService.h" #ifdef MOZ_TASK_TRACER # include "GeckoTaskTracer.h" @@ -878,6 +881,8 @@ void HttpChannelChild::OnTransportAndData(const nsresult& aChannelStatus, DoOnDataAvailable(this, nullptr, stringStream, aOffset, aCount); stringStream->Close(); + // TODO: Bug 1523916 backpressure needs to take into account if the data is + // coming from the main process or from the socket process via PBackground. if (NeedToReportBytesRead()) { mUnreportBytesRead += aCount; if (mUnreportBytesRead >= gHttpHandler->SendWindowSize() >> 2) { @@ -2090,6 +2095,8 @@ HttpChannelChild::ConnectParent(uint32_t registrarId) { mBgChild = std::move(bgChild); } + MaybeConnectToSocketProcess(); + return NS_OK; } @@ -2845,6 +2852,8 @@ nsresult HttpChannelChild::ContinueAsyncOpen() { mBgChild = std::move(bgChild); } + MaybeConnectToSocketProcess(); + return NS_OK; } @@ -4021,5 +4030,27 @@ void HttpChannelChild::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() { #endif } +void HttpChannelChild::MaybeConnectToSocketProcess() { + if (!nsIOService::UseSocketProcess()) { + return; + } + + if (!StaticPrefs::network_send_ODA_to_content_directly()) { + return; + } + + RefPtr bgChild = mBgChild; + SocketProcessBridgeChild::GetSocketProcessBridge()->Then( + GetCurrentThreadSerialEventTarget(), __func__, + [bgChild]() { + gSocketTransportService->Dispatch( + NewRunnableMethod("HttpBackgroundChannelChild::CreateDataBridge", + bgChild, + &HttpBackgroundChannelChild::CreateDataBridge), + NS_DISPATCH_NORMAL); + }, + []() { NS_WARNING("Failed to create SocketProcessBridgeChild"); }); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 13fa10f119ce..0c879bc58735 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -539,6 +539,7 @@ class HttpChannelChild final : public PHttpChannelChild, void DoNotifyListener(); void ContinueDoNotifyListener(); void OnAfterLastPart(const nsresult& aStatus); + void MaybeConnectToSocketProcess(); // Create a a new channel to be used in a redirection, based on the provided // response headers. diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index d7d4cc8b38c9..c0f0824b2024 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1695,6 +1695,12 @@ HttpChannelParent::OnDataAvailable(nsIRequest* aRequest, transportStatus = NS_NET_STATUS_READING; } + if (httpChannelImpl->OnDataAlreadySent()) { + LOG((" OnDataAvailable already sent to the child.\n")); + uint32_t n; + return aInputStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &n); + } + static uint32_t const kCopyChunkSize = 128 * 1024; uint32_t toRead = std::min(aCount, kCopyChunkSize); diff --git a/netwerk/protocol/http/HttpTransactionChild.cpp b/netwerk/protocol/http/HttpTransactionChild.cpp index 78d0cc18efe3..46765ef57e07 100644 --- a/netwerk/protocol/http/HttpTransactionChild.cpp +++ b/netwerk/protocol/http/HttpTransactionChild.cpp @@ -10,8 +10,11 @@ #include "HttpTransactionChild.h" #include "mozilla/ipc/IPCStreamUtils.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/net/BackgroundDataBridgeParent.h" #include "mozilla/net/InputChannelThrottleQueueChild.h" #include "mozilla/net/SocketProcessChild.h" +#include "mozilla/StaticPrefs_network.h" #include "nsInputStreamPump.h" #include "nsHttpHandler.h" #include "nsProxyInfo.h" @@ -19,18 +22,21 @@ #include "nsQueryObject.h" #include "nsSerializationHelper.h" +using mozilla::ipc::BackgroundParent; + namespace mozilla { namespace net { NS_IMPL_ISUPPORTS(HttpTransactionChild, nsIRequestObserver, nsIStreamListener, - nsITransportEventSink, nsIThrottledInputChannel); + nsITransportEventSink, nsIThrottledInputChannel, + nsIThreadRetargetableStreamListener); //----------------------------------------------------------------------------- // HttpTransactionChild //----------------------------------------------------------------------------- HttpTransactionChild::HttpTransactionChild() - : mCanceled(false), mStatus(NS_OK), mChannelId(0) { + : mCanceled(false), mStatus(NS_OK), mChannelId(0), mIsDocumentLoad(false) { LOG(("Creating HttpTransactionChild @%p\n", this)); } @@ -125,6 +131,11 @@ nsresult HttpTransactionChild::InitInternal( mozilla::ipc::IPCResult HttpTransactionChild::RecvCancelPump( const nsresult& aStatus) { LOG(("HttpTransactionChild::RecvCancelPump start [this=%p]\n", this)); + CancelInternal(aStatus); + return IPC_OK(); +} + +void HttpTransactionChild::CancelInternal(nsresult aStatus) { MOZ_ASSERT(NS_FAILED(aStatus)); mCanceled = true; @@ -132,8 +143,6 @@ mozilla::ipc::IPCResult HttpTransactionChild::RecvCancelPump( if (mTransactionPump) { mTransactionPump->Cancel(mStatus); } - - return IPC_OK(); } mozilla::ipc::IPCResult HttpTransactionChild::RecvSuspendPump() { @@ -164,7 +173,8 @@ mozilla::ipc::IPCResult HttpTransactionChild::RecvInit( const bool& aResponseTimeoutEnabled, const uint64_t& aChannelId, const bool& aHasTransactionObserver, const Maybe& aPushedStreamArg, - const mozilla::Maybe& aThrottleQueue) { + const mozilla::Maybe& aThrottleQueue, + const bool& aIsDocumentLoad) { mRequestHead = aReqHeaders; if (aRequestBody) { mUploadStream = mozilla::ipc::DeserializeIPCStream(aRequestBody); @@ -172,6 +182,7 @@ mozilla::ipc::IPCResult HttpTransactionChild::RecvInit( mTransaction = new nsHttpTransaction(); mChannelId = aChannelId; + mIsDocumentLoad = aIsDocumentLoad; if (aThrottleQueue.isSome()) { mThrottleQueue = @@ -254,10 +265,6 @@ HttpTransactionChild::OnDataAvailable(nsIRequest* aRequest, return mStatus; } - if (!CanSend()) { - return NS_ERROR_FAILURE; - } - // TODO: send string data in chunks and handle errors. Bug 1600129. nsCString data; nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount); @@ -265,7 +272,47 @@ HttpTransactionChild::OnDataAvailable(nsIRequest* aRequest, return rv; } - Unused << SendOnDataAvailable(data, aOffset, aCount); + if (NS_IsMainThread()) { + if (!CanSend()) { + return NS_ERROR_FAILURE; + } + + LOG((" ODA to parent process")); + Unused << SendOnDataAvailable(data, aOffset, aCount, false); + return NS_OK; + } + + ipc::AssertIsOnBackgroundThread(); + MOZ_ASSERT(mDataBridgeParent); + + if (!mDataBridgeParent->CanSend()) { + return NS_ERROR_FAILURE; + } + + bool dataSentToContentProcess = + mDataBridgeParent->SendOnTransportAndData(aOffset, aCount, data); + LOG((" ODA to content process, dataSentToContentProcess=%d", + dataSentToContentProcess)); + if (!dataSentToContentProcess) { + MOZ_ASSERT(false, "Send ODA to content process failed"); + return NS_ERROR_FAILURE; + } + + // We still need to send ODA to parent process, because the data needs to be + // saved in cache. Note that we set dataSentToChildProcess to true, to this + // ODA will not be sent to child process. + RefPtr self = this; + rv = NS_DispatchToMainThread( + NS_NewRunnableFunction( + "HttpTransactionChild::OnDataAvailable", + [self, offset(aOffset), count(aCount), data(data)]() { + if (!self->SendOnDataAvailable(data, offset, count, true)) { + self->CancelInternal(NS_ERROR_FAILURE); + } + }), + NS_DISPATCH_NORMAL); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return NS_OK; } @@ -293,6 +340,36 @@ static void GetDataForSniffer(void* aClosure, const uint8_t* aData, outData->AppendElements(aData, std::min(aCount, MAX_BYTES_SNIFFED)); } +bool HttpTransactionChild::CanSendODAToContentProcessDirectly( + const Maybe& aHead) { + if (!StaticPrefs::network_send_ODA_to_content_directly()) { + return false; + } + + // If this is a document load, the content process that receives ODA is not + // decided yet, so don't bother to do the rest check. + if (mIsDocumentLoad) { + return false; + } + + if (!aHead) { + return false; + } + + // We only need to deliver ODA when the response is succeed. + if (aHead->Status() != 200) { + return false; + } + + // UnknownDecoder could be used in parent process, so we can't send ODA to + // content process. + if (!aHead->HasContentType()) { + return false; + } + + return true; +} + NS_IMETHODIMP HttpTransactionChild::OnStartRequest(nsIRequest* aRequest) { LOG(("HttpTransactionChild::OnStartRequest start [this=%p] mTransaction=%p\n", @@ -336,6 +413,31 @@ HttpTransactionChild::OnStartRequest(nsIRequest* aRequest) { } } + if (CanSendODAToContentProcessDirectly(optionalHead)) { + Maybe> dataBridgeParent = + SocketProcessChild::GetSingleton()->GetAndRemoveDataBridge(mChannelId); + // Check if there is a registered BackgroundDataBridgeParent. + if (dataBridgeParent) { + mDataBridgeParent = std::move(dataBridgeParent.ref()); + + nsCOMPtr backgroundThread = + mDataBridgeParent->GetBackgroundThread(); + nsCOMPtr retargetableTransactionPump; + retargetableTransactionPump = do_QueryObject(mTransactionPump); + // nsInputStreamPump should implement this interface. + MOZ_ASSERT(retargetableTransactionPump); + + nsresult rv = + retargetableTransactionPump->RetargetDeliveryTo(backgroundThread); + LOG((" Retarget to background thread [this=%p rv=%08x]\n", this, + static_cast(rv))); + if (NS_FAILED(rv)) { + mDataBridgeParent->Destroy(); + mDataBridgeParent = nullptr; + } + } + } + int32_t proxyConnectResponseCode = mTransaction->GetProxyConnectResponseCode(); @@ -343,7 +445,6 @@ HttpTransactionChild::OnStartRequest(nsIRequest* aRequest) { mTransaction->ProxyConnectFailed(), ToTimingStructArgs(mTransaction->Timings()), proxyConnectResponseCode, dataForSniffer); - LOG(("HttpTransactionChild::OnStartRequest end [this=%p]\n", this)); return NS_OK; } @@ -351,6 +452,11 @@ NS_IMETHODIMP HttpTransactionChild::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) { LOG(("HttpTransactionChild::OnStopRequest [this=%p]\n", this)); + if (mDataBridgeParent) { + mDataBridgeParent->Destroy(); + mDataBridgeParent = nullptr; + } + // Don't bother sending IPC to parent process if already canceled. if (mCanceled) { return mStatus; @@ -434,5 +540,14 @@ HttpTransactionChild::GetThrottleQueue(nsIInputChannelThrottleQueue** aQueue) { return NS_OK; } +//----------------------------------------------------------------------------- +// EventSourceImpl::nsIThreadRetargetableStreamListener +//----------------------------------------------------------------------------- +NS_IMETHODIMP +HttpTransactionChild::CheckListenerChain() { + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!"); + return NS_OK; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/HttpTransactionChild.h b/netwerk/protocol/http/HttpTransactionChild.h index 9205a392ec38..9c9c5200c77a 100644 --- a/netwerk/protocol/http/HttpTransactionChild.h +++ b/netwerk/protocol/http/HttpTransactionChild.h @@ -6,11 +6,13 @@ #ifndef HttpTransactionChild_h__ #define HttpTransactionChild_h__ +#include "mozilla/Atomics.h" #include "mozilla/net/NeckoChannelParams.h" #include "mozilla/net/PHttpTransactionChild.h" #include "nsHttpRequestHead.h" #include "nsIRequest.h" #include "nsIStreamListener.h" +#include "nsIThreadRetargetableStreamListener.h" #include "nsIThrottledInputChannel.h" #include "nsITransport.h" @@ -19,6 +21,7 @@ class nsInputStreamPump; namespace mozilla { namespace net { +class BackgroundDataBridgeParent; class InputChannelThrottleQueueChild; class nsHttpConnectionInfo; class nsHttpTransaction; @@ -31,13 +34,15 @@ class nsProxyInfo; class HttpTransactionChild final : public PHttpTransactionChild, public nsIStreamListener, public nsITransportEventSink, - public nsIThrottledInputChannel { + public nsIThrottledInputChannel, + public nsIThreadRetargetableStreamListener { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSITRANSPORTEVENTSINK NS_DECL_NSITHROTTLEDINPUTCHANNEL + NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER explicit HttpTransactionChild(); @@ -52,7 +57,8 @@ class HttpTransactionChild final : public PHttpTransactionChild, const bool& aResponseTimeoutEnabled, const uint64_t& aChannelId, const bool& aHasTransactionObserver, const Maybe& aPushedStreamArg, - const mozilla::Maybe& aThrottleQueue); + const mozilla::Maybe& aThrottleQueue, + const bool& aIsDocumentLoad); mozilla::ipc::IPCResult RecvUpdateClassOfService( const uint32_t& classOfService); mozilla::ipc::IPCResult RecvCancelPump(const nsresult& aStatus); @@ -85,16 +91,25 @@ class HttpTransactionChild final : public PHttpTransactionChild, bool aHasTransactionObserver, const Maybe& aPushedStreamArg); - bool mCanceled; + void CancelInternal(nsresult aStatus); + + bool CanSendODAToContentProcessDirectly( + const Maybe& aHead); + + // Use Release-Acquire ordering to ensure the OMT ODA is ignored while + // transaction is canceled on main thread. + Atomic mCanceled; nsresult mStatus; uint64_t mChannelId; nsHttpRequestHead mRequestHead; + bool mIsDocumentLoad; nsCOMPtr mUploadStream; RefPtr mTransaction; nsCOMPtr mTransactionPump; Maybe mTransactionObserverResult; RefPtr mThrottleQueue; + RefPtr mDataBridgeParent; }; } // namespace net diff --git a/netwerk/protocol/http/HttpTransactionParent.cpp b/netwerk/protocol/http/HttpTransactionParent.cpp index 8454aa0f1d40..041ecb804da3 100644 --- a/netwerk/protocol/http/HttpTransactionParent.cpp +++ b/netwerk/protocol/http/HttpTransactionParent.cpp @@ -64,7 +64,7 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpTransactionParent::Release(void) { // HttpTransactionParent //----------------------------------------------------------------------------- -HttpTransactionParent::HttpTransactionParent() +HttpTransactionParent::HttpTransactionParent(bool aIsDocumentLoad) : mResponseIsComplete(false), mTransferSize(0), mRequestSize(0), @@ -79,7 +79,9 @@ HttpTransactionParent::HttpTransactionParent() mOnStopRequestCalled(false), mResolvedByTRR(false), mProxyConnectResponseCode(0), - mChannelId(0) { + mChannelId(0), + mDataAlreadySent(false), + mIsDocumentLoad(aIsDocumentLoad) { LOG(("Creating HttpTransactionParent @%p\n", this)); this->mSelfAddr.inet = {}; @@ -170,7 +172,8 @@ nsresult HttpTransactionParent::Init( topLevelOuterContentWindowId, static_cast(trafficCategory), requestContextID, classOfService, initialRwin, responseTimeoutEnabled, mChannelId, - !!mTransactionObserver, pushedStreamArg, throttleQueue)) { + !!mTransactionObserver, pushedStreamArg, throttleQueue, + mIsDocumentLoad)) { return NS_ERROR_FAILURE; } @@ -288,6 +291,8 @@ int64_t HttpTransactionParent::GetTransferSize() { return mTransferSize; } int64_t HttpTransactionParent::GetRequestSize() { return mRequestSize; } +bool HttpTransactionParent::DataAlreadySent() { return mDataAlreadySent; } + nsISupports* HttpTransactionParent::SecurityInfo() { return mSecurityInfo; } bool HttpTransactionParent::ProxyConnectFailed() { return mProxyConnectFailed; } @@ -434,7 +439,8 @@ void HttpTransactionParent::DoOnTransportStatus(const nsresult& aStatus, } mozilla::ipc::IPCResult HttpTransactionParent::RecvOnDataAvailable( - const nsCString& aData, const uint64_t& aOffset, const uint32_t& aCount) { + const nsCString& aData, const uint64_t& aOffset, const uint32_t& aCount, + const bool& aDataSentToChildProcess) { LOG(("HttpTransactionParent::RecvOnDataAvailable [this=%p, aOffset= %" PRIu64 " aCount=%" PRIu32, this, aOffset, aCount)); @@ -445,18 +451,22 @@ mozilla::ipc::IPCResult HttpTransactionParent::RecvOnDataAvailable( mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( this, [self = UnsafePtr(this), aData, aOffset, - aCount]() { self->DoOnDataAvailable(aData, aOffset, aCount); })); + aCount, aDataSentToChildProcess]() { + self->DoOnDataAvailable(aData, aOffset, aCount, + aDataSentToChildProcess); + })); return IPC_OK(); } -void HttpTransactionParent::DoOnDataAvailable(const nsCString& aData, - const uint64_t& aOffset, - const uint32_t& aCount) { +void HttpTransactionParent::DoOnDataAvailable( + const nsCString& aData, const uint64_t& aOffset, const uint32_t& aCount, + const bool& aDataSentToChildProcess) { LOG(("HttpTransactionParent::DoOnDataAvailable [this=%p]\n", this)); if (mCanceled) { return; } + mDataAlreadySent = aDataSentToChildProcess; nsCOMPtr stringStream; nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), MakeSpan(aData.get(), aCount), diff --git a/netwerk/protocol/http/HttpTransactionParent.h b/netwerk/protocol/http/HttpTransactionParent.h index b93dd77007e1..3de73e2bd2b1 100644 --- a/netwerk/protocol/http/HttpTransactionParent.h +++ b/netwerk/protocol/http/HttpTransactionParent.h @@ -41,7 +41,7 @@ class HttpTransactionParent final : public PHttpTransactionParent, NS_DECL_NSITHREADRETARGETABLEREQUEST NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_TRANSACTION_PARENT_IID) - explicit HttpTransactionParent(); + explicit HttpTransactionParent(bool aIsDocumentLoad); void ActorDestroy(ActorDestroyReason aWhy) override; @@ -54,9 +54,9 @@ class HttpTransactionParent final : public PHttpTransactionParent, mozilla::ipc::IPCResult RecvOnTransportStatus(const nsresult& aStatus, const int64_t& aProgress, const int64_t& aProgressMax); - mozilla::ipc::IPCResult RecvOnDataAvailable(const nsCString& aData, - const uint64_t& aOffset, - const uint32_t& aCount); + mozilla::ipc::IPCResult RecvOnDataAvailable( + const nsCString& aData, const uint64_t& aOffset, const uint32_t& aCount, + const bool& aDataSentToChildProcess); mozilla::ipc::IPCResult RecvOnStopRequest( const nsresult& aStatus, const bool& aResponseIsComplete, const int64_t& aTransferSize, const TimingStructArgs& aTimings, @@ -93,7 +93,8 @@ class HttpTransactionParent final : public PHttpTransactionParent, void DoOnTransportStatus(const nsresult& aStatus, const int64_t& aProgress, const int64_t& aProgressMax); void DoOnDataAvailable(const nsCString& aData, const uint64_t& aOffset, - const uint32_t& aCount); + const uint32_t& aCount, + const bool& aDataSentToChildProcess); void DoOnStopRequest( const nsresult& aStatus, const bool& aResponseIsComplete, const int64_t& aTransferSize, const TimingStructArgs& aTimings, @@ -125,6 +126,8 @@ class HttpTransactionParent final : public PHttpTransactionParent, bool mResolvedByTRR; int32_t mProxyConnectResponseCode; uint64_t mChannelId; + bool mDataAlreadySent; + bool mIsDocumentLoad; NetAddr mSelfAddr; NetAddr mPeerAddr; diff --git a/netwerk/protocol/http/HttpTransactionShell.h b/netwerk/protocol/http/HttpTransactionShell.h index 3dca4c70a970..f91fd19fce2a 100644 --- a/netwerk/protocol/http/HttpTransactionShell.h +++ b/netwerk/protocol/http/HttpTransactionShell.h @@ -147,6 +147,8 @@ class HttpTransactionShell : public nsISupports { virtual bool ProxyConnectFailed() = 0; virtual int32_t GetProxyConnectResponseCode() = 0; + virtual bool DataAlreadySent() = 0; + virtual nsHttpTransaction* AsHttpTransaction() = 0; virtual HttpTransactionParent* AsHttpTransactionParent() = 0; }; @@ -200,6 +202,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(HttpTransactionShell, HTTPTRANSACTIONSHELL_IID) virtual void SetH2WSConnRefTaken() override; \ virtual bool ProxyConnectFailed() override; \ virtual int32_t GetProxyConnectResponseCode() override; \ + virtual bool DataAlreadySent() override; \ virtual nsHttpTransaction* AsHttpTransaction() override; \ virtual HttpTransactionParent* AsHttpTransactionParent() override; } // namespace net diff --git a/netwerk/protocol/http/PBackgroundDataBridge.ipdl b/netwerk/protocol/http/PBackgroundDataBridge.ipdl new file mode 100644 index 000000000000..bedc385e811c --- /dev/null +++ b/netwerk/protocol/http/PBackgroundDataBridge.ipdl @@ -0,0 +1,25 @@ +/* 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 PBackground; + +namespace mozilla { +namespace net { + +//------------------------------------------------------------------- +async refcounted protocol PBackgroundDataBridge +{ + manager PBackground; + +child: + async OnTransportAndData(uint64_t offset, + uint32_t count, + nsCString data); + +both: + async __delete__(); +}; + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl index ae9e37d8c029..cdfd706f0747 100644 --- a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl +++ b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl @@ -36,7 +36,8 @@ child: nsresult transportStatus, uint64_t offset, uint32_t count, - nsCString data); + nsCString data, + bool dataFromSocketProcess); // This is duplicated on PHttpChannel, which gets used for multi-part // streams to make synchronization when we get OnStartRequest multiple diff --git a/netwerk/protocol/http/PHttpTransaction.ipdl b/netwerk/protocol/http/PHttpTransaction.ipdl index e8dc395ce8b5..9463e51885e8 100644 --- a/netwerk/protocol/http/PHttpTransaction.ipdl +++ b/netwerk/protocol/http/PHttpTransaction.ipdl @@ -43,7 +43,8 @@ parent: int64_t progressMax); async OnDataAvailable(nsCString data, uint64_t offset, - uint32_t count); + uint32_t count, + bool dataSentToChildProcess); async OnStopRequest(nsresult status, bool responseIsComplete, int64_t transferSize, @@ -74,7 +75,8 @@ child: uint64_t channelId, bool hasTransactionObserver, H2PushedStreamArg? pushedStreamArg, - PInputChannelThrottleQueue? throttleQueue); + PInputChannelThrottleQueue? throttleQueue, + bool aIsDocumentLoad); async UpdateClassOfService(uint32_t classOfService); async CancelPump(nsresult status); diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index 4c6a2cf5fbbe..2bf480977ef4 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -42,6 +42,8 @@ EXPORTS.mozilla.net += [ 'AltSvcTransactionChild.h', 'AltSvcTransactionParent.h', 'BackgroundChannelRegistrar.h', + 'BackgroundDataBridgeChild.h', + 'BackgroundDataBridgeParent.h', 'ClassifierDummyChannel.h', 'ClassifierDummyChannelChild.h', 'ClassifierDummyChannelParent.h', @@ -82,6 +84,8 @@ UNIFIED_SOURCES += [ 'AltSvcTransactionParent.cpp', 'ASpdySession.cpp', 'BackgroundChannelRegistrar.cpp', + 'BackgroundDataBridgeChild.cpp', + 'BackgroundDataBridgeParent.cpp', 'CacheControlParser.cpp', 'ClassifierDummyChannel.cpp', 'ClassifierDummyChannelChild.cpp', @@ -145,6 +149,7 @@ IPDL_SOURCES += [ 'PAltDataOutputStream.ipdl', 'PAltService.ipdl', 'PAltSvcTransaction.ipdl', + 'PBackgroundDataBridge.ipdl', 'PClassifierDummyChannel.ipdl', 'PHttpBackgroundChannel.ipdl', 'PHttpChannel.ipdl', diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index abcfe1a0d944..4c70391a01d3 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -396,6 +396,7 @@ nsHttpChannel::nsHttpChannel() mIsIsolated(0), mTopWindowOriginComputed(0), mHasCrossOriginOpenerPolicyMismatch(0), + mDataAlreadySent(0), mPushedStreamId(0), mLocalBlocklist(false), mOnTailUnblock(nullptr), @@ -1349,7 +1350,16 @@ nsresult nsHttpChannel::SetupTransaction() { MOZ_ASSERT(gIOService->SocketProcessReady(), "Socket process should be ready."); - RefPtr transParent = new HttpTransactionParent(); + nsCOMPtr parentChannel; + NS_QueryNotificationCallbacks(this, parentChannel); + RefPtr documentChannelParent = + do_QueryObject(parentChannel); + // See HttpTransactionChild::CanSendODAToContentProcessDirectly() and + // nsHttpChannel::CallOnStartRequest() for the reason why we need to know if + // this is a document load. We only send ODA directly to child process for + // non document loads. + RefPtr transParent = + new HttpTransactionParent(!!documentChannelParent); LOG1(("nsHttpChannel %p created HttpTransactionParent %p\n", this, transParent.get())); @@ -1923,6 +1933,10 @@ nsresult nsHttpChannel::CallOnStartRequest() { } } + // Note that the code below should be synced with the code in + // HttpTransactionChild::CanSendODAToContentProcessDirectly(). We MUST make + // sure HttpTransactionChild::CanSendODAToContentProcessDirectly() returns + // false when a stream converter is applied. bool unknownDecoderStarted = false; if (mResponseHead && !mResponseHead->HasContentType()) { MOZ_ASSERT(mConnectionInfo, "Should have connection info here"); @@ -8466,6 +8480,10 @@ nsHttpChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* input, seekable = nullptr; } + mDataAlreadySent = false; + if (mTransaction) { + mDataAlreadySent = mTransaction->DataAlreadySent(); + } nsresult rv = mListener->OnDataAvailable(this, input, mLogicalOffset, count); if (NS_SUCCEEDED(rv)) { diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index f38c493e00ac..a3c591757da1 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -198,6 +198,8 @@ class nsHttpChannel final : public HttpBaseChannel, void SetWarningReporter(HttpChannelSecurityWarningReporter* aReporter); HttpChannelSecurityWarningReporter* GetWarningReporter(); + bool OnDataAlreadySent() { return mDataAlreadySent; } + public: /* internal necko use only */ uint32_t GetRequestTime() const { return mRequestTime; } @@ -735,6 +737,10 @@ class nsHttpChannel final : public HttpBaseChannel, // opener policy ( see ComputeCrossOriginOpenerPolicyMismatch ) uint32_t mHasCrossOriginOpenerPolicyMismatch : 1; + // True if the data has already been sent from the socket process to the + // content process. + uint32_t mDataAlreadySent : 1; + // The origin of the top window, only valid when mTopWindowOriginComputed is // true. nsCString mTopWindowOrigin; diff --git a/netwerk/protocol/http/nsHttpResponseHead.cpp b/netwerk/protocol/http/nsHttpResponseHead.cpp index bf6c3d0d5031..77c662207954 100644 --- a/netwerk/protocol/http/nsHttpResponseHead.cpp +++ b/netwerk/protocol/http/nsHttpResponseHead.cpp @@ -1175,7 +1175,7 @@ nsresult nsHttpResponseHead::GetOriginalHeader(nsHttpAtom aHeader, return rv; } -bool nsHttpResponseHead::HasContentType() { +bool nsHttpResponseHead::HasContentType() const { RecursiveMutexAutoLock monitor(mRecursiveMutex); return !mContentType.IsEmpty(); } diff --git a/netwerk/protocol/http/nsHttpResponseHead.h b/netwerk/protocol/http/nsHttpResponseHead.h index 30bb692f4ba5..f641b214be65 100644 --- a/netwerk/protocol/http/nsHttpResponseHead.h +++ b/netwerk/protocol/http/nsHttpResponseHead.h @@ -157,7 +157,7 @@ class nsHttpResponseHead { [[nodiscard]] nsresult GetOriginalHeader(nsHttpAtom aHeader, nsIHttpHeaderVisitor* aVisitor); - bool HasContentType(); + bool HasContentType() const; bool HasContentCharset(); bool GetContentTypeOptionsHeader(nsACString& aOutput); diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index af0b64b7ec38..1021ca599188 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -1003,6 +1003,8 @@ nsresult nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter* writer, bool nsHttpTransaction::ProxyConnectFailed() { return mProxyConnectFailed; } +bool nsHttpTransaction::DataAlreadySent() { return false; } + nsISupports* nsHttpTransaction::SecurityInfo() { return mSecurityInfo; } bool nsHttpTransaction::HasStickyConnection() const {