Bug 1623380 - Send ODA directly to content process r=dragana

Differential Revision: https://phabricator.services.mozilla.com/D67609
This commit is contained in:
Kershaw Chang 2020-05-07 11:12:46 +00:00
Родитель 92d967bf64
Коммит 467f6725fc
34 изменённых файлов: 548 добавлений и 43 удалений

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

@ -8,6 +8,8 @@ include GMPTypes;
using cdm::HdcpVersion from "content_decryption_module.h";
include "GMPMessageUtils.h";
namespace mozilla {
namespace gmp {

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

@ -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<net::PBackgroundDataBridgeParent>
BackgroundParentImpl::AllocPBackgroundDataBridgeParent(
const uint64_t& aChannelID) {
MOZ_ASSERT(XRE_IsSocketProcess(), "Should be in socket process");
AssertIsOnBackgroundThread();
RefPtr<net::BackgroundDataBridgeParent> actor =
new net::BackgroundDataBridgeParent(aChannelID);
return actor.forget();
}
BackgroundParentImpl::PBackgroundTestParent*
BackgroundParentImpl::AllocPBackgroundTestParent(const nsCString& aTestArg) {
AssertIsInMainOrSocketProcess();

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

@ -47,6 +47,9 @@ class BackgroundParentImpl : public PBackgroundParent,
virtual already_AddRefed<PBackgroundIDBFactoryParent>
AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo) override;
virtual already_AddRefed<net::PBackgroundDataBridgeParent>
AllocPBackgroundDataBridgeParent(const uint64_t& aChannelID) override;
virtual mozilla::ipc::IPCResult RecvPBackgroundIDBFactoryConstructor(
PBackgroundIDBFactoryParent* aActor,
const LoggingInfo& aLoggingInfo) override;

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

@ -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();

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

@ -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

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

@ -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,
};

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

@ -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<RefPtr<BackgroundDataBridgeParent>>
SocketProcessChild::GetAndRemoveDataBridge(uint64_t aChannelId) {
MutexAutoLock lock(mMutex);
return mBackgroundDataBridgeMap.GetAndRemove(aChannelId);
}
} // namespace net
} // namespace mozilla

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

@ -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<RefPtr<BackgroundDataBridgeParent>> 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<nsUint64HashKey, RefPtr<BackgroundDataBridgeParent>>
mBackgroundDataBridgeMap;
};
} // namespace net

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

@ -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<BackgroundDataBridgeChild> 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

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

@ -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<HttpBackgroundChannelChild> mBgChild;
nsCOMPtr<nsIThread> 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

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

@ -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<nsIThread> BackgroundDataBridgeParent::GetBackgroundThread() {
nsCOMPtr<nsIThread> thread = mBackgroundThread;
return thread.forget();
}
void BackgroundDataBridgeParent::Destroy() {
RefPtr<BackgroundDataBridgeParent> 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

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

@ -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<nsIThread> GetBackgroundThread();
void Destroy();
private:
virtual ~BackgroundDataBridgeParent() = default;
uint64_t mChannelID;
nsCOMPtr<nsIThread> mBackgroundThread;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_BackgroundDataBridgeParent_h

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

@ -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;

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

@ -18,6 +18,7 @@
#include "Http2HuffmanOutgoing.h"
#include "mozilla/StaticPtr.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsIMemoryReporter.h"
#include "nsHttpHandler.h"
namespace mozilla {

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

@ -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 nsresult, const nsresult, const uint64_t,
const uint32_t, const nsCString>(
const uint32_t, const nsCString, bool>(
"HttpBackgroundChannelChild::RecvOnTransportAndData", this,
&HttpBackgroundChannelChild::RecvOnTransportAndData, aChannelStatus,
aTransportStatus, aOffset, aCount, aData));
aTransportStatus, aOffset, aCount, aData, aDataFromSocketProcess));
return IPC_OK();
}

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

@ -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<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
RefPtr<BackgroundDataBridgeChild> mDataBridgeChild;
};
} // namespace net

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

@ -192,7 +192,7 @@ bool HttpBackgroundChannelParent::OnTransportAndData(
}
return SendOnTransportAndData(aChannelStatus, aTransportStatus, aOffset,
aCount, aData);
aCount, aData, false);
}
bool HttpBackgroundChannelParent::OnStopRequest(

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

@ -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<HttpBackgroundChannelChild> 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

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

@ -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.

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

@ -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<uint32_t>(aCount, kCopyChunkSize);

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

@ -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 <public>
//-----------------------------------------------------------------------------
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<H2PushedStreamArg>& aPushedStreamArg,
const mozilla::Maybe<PInputChannelThrottleQueueChild*>& aThrottleQueue) {
const mozilla::Maybe<PInputChannelThrottleQueueChild*>& 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<HttpTransactionChild> 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<nsHttpResponseHead>& 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<RefPtr<BackgroundDataBridgeParent>> dataBridgeParent =
SocketProcessChild::GetSingleton()->GetAndRemoveDataBridge(mChannelId);
// Check if there is a registered BackgroundDataBridgeParent.
if (dataBridgeParent) {
mDataBridgeParent = std::move(dataBridgeParent.ref());
nsCOMPtr<nsIThread> backgroundThread =
mDataBridgeParent->GetBackgroundThread();
nsCOMPtr<nsIThreadRetargetableRequest> 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<uint32_t>(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

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

@ -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<H2PushedStreamArg>& aPushedStreamArg,
const mozilla::Maybe<PInputChannelThrottleQueueChild*>& aThrottleQueue);
const mozilla::Maybe<PInputChannelThrottleQueueChild*>& 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<H2PushedStreamArg>& aPushedStreamArg);
bool mCanceled;
void CancelInternal(nsresult aStatus);
bool CanSendODAToContentProcessDirectly(
const Maybe<nsHttpResponseHead>& aHead);
// Use Release-Acquire ordering to ensure the OMT ODA is ignored while
// transaction is canceled on main thread.
Atomic<bool, ReleaseAcquire> mCanceled;
nsresult mStatus;
uint64_t mChannelId;
nsHttpRequestHead mRequestHead;
bool mIsDocumentLoad;
nsCOMPtr<nsIInputStream> mUploadStream;
RefPtr<nsHttpTransaction> mTransaction;
nsCOMPtr<nsIRequest> mTransactionPump;
Maybe<TransactionObserverResult> mTransactionObserverResult;
RefPtr<InputChannelThrottleQueueChild> mThrottleQueue;
RefPtr<BackgroundDataBridgeParent> mDataBridgeParent;
};
} // namespace net

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

@ -64,7 +64,7 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpTransactionParent::Release(void) {
// HttpTransactionParent <public>
//-----------------------------------------------------------------------------
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<uint8_t>(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<HttpTransactionParent>(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<nsIInputStream> stringStream;
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
MakeSpan(aData.get(), aCount),

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

@ -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;

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

@ -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

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

@ -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

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

@ -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

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

@ -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);

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

@ -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',

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

@ -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<HttpTransactionParent> transParent = new HttpTransactionParent();
nsCOMPtr<nsIParentChannel> parentChannel;
NS_QueryNotificationCallbacks(this, parentChannel);
RefPtr<DocumentLoadListener> 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<HttpTransactionParent> 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)) {

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

@ -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;

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

@ -1175,7 +1175,7 @@ nsresult nsHttpResponseHead::GetOriginalHeader(nsHttpAtom aHeader,
return rv;
}
bool nsHttpResponseHead::HasContentType() {
bool nsHttpResponseHead::HasContentType() const {
RecursiveMutexAutoLock monitor(mRecursiveMutex);
return !mContentType.IsEmpty();
}

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

@ -157,7 +157,7 @@ class nsHttpResponseHead {
[[nodiscard]] nsresult GetOriginalHeader(nsHttpAtom aHeader,
nsIHttpHeaderVisitor* aVisitor);
bool HasContentType();
bool HasContentType() const;
bool HasContentCharset();
bool GetContentTypeOptionsHeader(nsACString& aOutput);

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

@ -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 {