diff options
Diffstat (limited to 'netwerk/protocol/http')
-rw-r--r-- | netwerk/protocol/http/Http2Compression.cpp | 33 | ||||
-rw-r--r-- | netwerk/protocol/http/Http2Compression.h | 9 | ||||
-rw-r--r-- | netwerk/protocol/http/HttpChannelChild.cpp | 49 | ||||
-rw-r--r-- | netwerk/protocol/http/HttpChannelChild.h | 10 | ||||
-rw-r--r-- | netwerk/protocol/http/TlsHandshaker.cpp | 18 | ||||
-rw-r--r-- | netwerk/protocol/http/nsITlsHandshakeListener.idl | 2 |
6 files changed, 83 insertions, 38 deletions
diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp index 4d16e9e532..b95883f13f 100644 --- a/netwerk/protocol/http/Http2Compression.cpp +++ b/netwerk/protocol/http/Http2Compression.cpp @@ -61,6 +61,7 @@ class HpackDynamicTableReporter final : public nsIMemoryReporter { NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) override { + MutexAutoLock lock(mMutex); if (mCompressor) { MOZ_COLLECT_REPORT("explicit/network/hpack/dynamic-tables", KIND_HEAP, UNITS_BYTES, @@ -75,7 +76,8 @@ class HpackDynamicTableReporter final : public nsIMemoryReporter { ~HpackDynamicTableReporter() = default; - Http2BaseCompressor* mCompressor; + Mutex mMutex{"HpackDynamicTableReporter"}; + Http2BaseCompressor* mCompressor MOZ_GUARDED_BY(mMutex); friend class Http2BaseCompressor; }; @@ -187,13 +189,18 @@ nvFIFO::~nvFIFO() { Clear(); } void nvFIFO::AddElement(const nsCString& name, const nsCString& value) { nvPair* pair = new nvPair(name, value); mByteCount += pair->Size(); + MutexAutoLock lock(mMutex); mTable.PushFront(pair); } void nvFIFO::AddElement(const nsCString& name) { AddElement(name, ""_ns); } void nvFIFO::RemoveElement() { - nvPair* pair = mTable.Pop(); + nvPair* pair = nullptr; + { + MutexAutoLock lock(mMutex); + pair = mTable.Pop(); + } if (pair) { mByteCount -= pair->Size(); delete pair; @@ -212,6 +219,7 @@ size_t nvFIFO::StaticLength() const { return gStaticHeaders->GetSize(); } void nvFIFO::Clear() { mByteCount = 0; + MutexAutoLock lock(mMutex); while (mTable.GetSize()) { delete mTable.Pop(); } @@ -244,20 +252,27 @@ Http2BaseCompressor::~Http2BaseCompressor() { Telemetry::Accumulate(mPeakCountID, mPeakCount); } UnregisterStrongMemoryReporter(mDynamicReporter); - mDynamicReporter->mCompressor = nullptr; + { + MutexAutoLock lock(mDynamicReporter->mMutex); + mDynamicReporter->mCompressor = nullptr; + } mDynamicReporter = nullptr; } +size_t nvFIFO::SizeOfDynamicTable(mozilla::MallocSizeOf aMallocSizeOf) const { + size_t size = 0; + MutexAutoLock lock(mMutex); + for (const auto elem : mTable) { + size += elem->SizeOfIncludingThis(aMallocSizeOf); + } + return size; +} + void Http2BaseCompressor::ClearHeaderTable() { mHeaderTable.Clear(); } size_t Http2BaseCompressor::SizeOfExcludingThis( mozilla::MallocSizeOf aMallocSizeOf) const { - size_t size = 0; - for (uint32_t i = mHeaderTable.StaticLength(); i < mHeaderTable.Length(); - ++i) { - size += mHeaderTable[i]->SizeOfIncludingThis(aMallocSizeOf); - } - return size; + return mHeaderTable.SizeOfDynamicTable(aMallocSizeOf); } void Http2BaseCompressor::MakeRoom(uint32_t amount, const char* direction) { diff --git a/netwerk/protocol/http/Http2Compression.h b/netwerk/protocol/http/Http2Compression.h index dd98584607..ad47949938 100644 --- a/netwerk/protocol/http/Http2Compression.h +++ b/netwerk/protocol/http/Http2Compression.h @@ -13,6 +13,7 @@ #include "nsDeque.h" #include "nsString.h" #include "mozilla/Telemetry.h" +#include "mozilla/Mutex.h" namespace mozilla { namespace net { @@ -47,10 +48,18 @@ class nvFIFO { size_t StaticLength() const; void Clear(); const nvPair* operator[](size_t index) const; + size_t SizeOfDynamicTable(mozilla::MallocSizeOf aMallocSizeOf) const; private: uint32_t mByteCount{0}; nsDeque<nvPair> mTable; + + // This mutex is held when adding or removing elements in the table + // and when accessing the table from the main thread (in SizeOfDynamicTable) + // Since the operator[] and other const methods are always called + // on the socket thread, they don't need to lock the mutex. + // Mutable so it can be locked in SizeOfDynamicTable which is const + mutable Mutex mMutex MOZ_UNANNOTATED{"nvFIFO"}; }; class HpackDynamicTableReporter; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 34e7a2cf0d..240bb14433 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -87,7 +87,8 @@ HttpChannelChild::HttpChannelChild() mIsLastPartOfMultiPart(false), mSuspendForWaitCompleteRedirectSetup(false), mRecvOnStartRequestSentCalled(false), - mSuspendedByWaitingForPermissionCookie(false) { + mSuspendedByWaitingForPermissionCookie(false), + mAlreadyReleased(false) { LOG(("Creating HttpChannelChild @%p\n", this)); mChannelCreationTime = PR_Now(); @@ -199,12 +200,16 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() { // We don't have a listener when AsyncOpen has failed or when this channel // has been sucessfully redirected. if (MOZ_LIKELY(LoadOnStartRequestCalled() && LoadOnStopRequestCalled()) || - !mListener) { + !mListener || mAlreadyReleased) { NS_LOG_RELEASE(this, 0, "HttpChannelChild"); delete this; return 0; } + // This ensures that when the refcount goes to 0 again, we don't dispatch + // yet another runnable and get in a loop. + mAlreadyReleased = true; + // This makes sure we fulfill the stream listener contract all the time. if (NS_SUCCEEDED(mStatus)) { mStatus = NS_ERROR_ABORT; @@ -223,27 +228,11 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() { // 3) Finally, we turn the reference into a regular smart pointer. RefPtr<HttpChannelChild> channel = dont_AddRef(this); - - // This runnable will create a strong reference to |this|. - NS_DispatchToMainThread( - NewRunnableMethod("~HttpChannelChild>DoNotifyListener", channel, - &HttpChannelChild::DoNotifyListener)); - + NS_DispatchToMainThread(NS_NewRunnableFunction( + "~HttpChannelChild>DoNotifyListener", + [chan = std::move(channel)] { chan->DoNotifyListener(false); })); // If NS_DispatchToMainThread failed then we're going to leak the runnable, // and thus the channel, so there's no need to do anything else. - - // We should have already done any special handling for the refcount = 1 - // case when the refcount first went from 2 to 1. We don't want it to happen - // when |channel| is destroyed. - MOZ_ASSERT(!mKeptAlive || !CanSend()); - - // XXX If std::move(channel) is allowed, then we don't have to have extra - // checks for the refcount going from 2 to 1. See bug 1680217. - - // This will release the stabilization refcount, which is necessary to avoid - // a leak. - channel = nullptr; - return mRefCnt; } @@ -1233,7 +1222,7 @@ void HttpChannelChild::NotifyOrReleaseListeners(nsresult rv) { DoNotifyListener(); } -void HttpChannelChild::DoNotifyListener() { +void HttpChannelChild::DoNotifyListener(bool aUseEventQueue) { LOG(("HttpChannelChild::DoNotifyListener this=%p", this)); MOZ_ASSERT(NS_IsMainThread()); @@ -1246,16 +1235,20 @@ void HttpChannelChild::DoNotifyListener() { if (mListener && !LoadOnStartRequestCalled()) { nsCOMPtr<nsIStreamListener> listener = mListener; - StoreOnStartRequestCalled( - true); // avoid reentrancy bugs by setting this now + // avoid reentrancy bugs by setting this now + StoreOnStartRequestCalled(true); listener->OnStartRequest(this); } StoreOnStartRequestCalled(true); - mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( - this, [self = UnsafePtr<HttpChannelChild>(this)] { - self->ContinueDoNotifyListener(); - })); + if (aUseEventQueue) { + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr<HttpChannelChild>(this)] { + self->ContinueDoNotifyListener(); + })); + } else { + ContinueDoNotifyListener(); + } } void HttpChannelChild::ContinueDoNotifyListener() { diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index c88d30023c..6a54ce390a 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -395,6 +395,12 @@ class HttpChannelChild final : public PHttpChannelChild, // permission or cookie. That is, RecvOnStartRequestSent is received. uint8_t mSuspendedByWaitingForPermissionCookie : 1; + // HttpChannelChild::Release has some special logic that makes sure + // OnStart/OnStop are always called when releasing the channel. + // But we have to make sure we only do this once - otherwise we could + // get stuck in a loop. + uint8_t mAlreadyReleased : 1; + void CleanupRedirectingChannel(nsresult rv); // Calls OnStartRequest and/or OnStopRequest on our listener in case we didn't @@ -427,7 +433,9 @@ class HttpChannelChild final : public PHttpChannelChild, const ResourceTimingStructArgs& timing); void Redirect3Complete(); void DeleteSelf(); - void DoNotifyListener(); + // aUseEventQueue should only be false when called from + // HttpChannelChild::Release to make sure OnStopRequest is called syncly. + void DoNotifyListener(bool aUseEventQueue = true); void ContinueDoNotifyListener(); void OnAfterLastPart(const nsresult& aStatus); void MaybeConnectToSocketProcess(); diff --git a/netwerk/protocol/http/TlsHandshaker.cpp b/netwerk/protocol/http/TlsHandshaker.cpp index 88f0062516..56fe011920 100644 --- a/netwerk/protocol/http/TlsHandshaker.cpp +++ b/netwerk/protocol/http/TlsHandshaker.cpp @@ -31,6 +31,24 @@ TlsHandshaker::TlsHandshaker(nsHttpConnectionInfo* aInfo, TlsHandshaker::~TlsHandshaker() { LOG(("TlsHandshaker dtor %p", this)); } NS_IMETHODIMP +TlsHandshaker::CertVerificationDone() { + LOG(("TlsHandshaker::CertVerificationDone mOwner=%p", mOwner.get())); + if (mOwner) { + Unused << mOwner->ResumeSend(); + } + return NS_OK; +} + +NS_IMETHODIMP +TlsHandshaker::ClientAuthCertificateSelected() { + LOG(("TlsHandshaker::ClientAuthCertificateSelected mOwner=%p", mOwner.get())); + if (mOwner) { + Unused << mOwner->ResumeSend(); + } + return NS_OK; +} + +NS_IMETHODIMP TlsHandshaker::HandshakeDone() { LOG(("TlsHandshaker::HandshakeDone mOwner=%p", mOwner.get())); if (mOwner) { diff --git a/netwerk/protocol/http/nsITlsHandshakeListener.idl b/netwerk/protocol/http/nsITlsHandshakeListener.idl index cb5444f6d7..0d5806be24 100644 --- a/netwerk/protocol/http/nsITlsHandshakeListener.idl +++ b/netwerk/protocol/http/nsITlsHandshakeListener.idl @@ -9,4 +9,6 @@ [uuid(b4bbe824-ec4c-48be-9a40-6a7339347f40)] interface nsITlsHandshakeCallbackListener : nsISupports { [noscript] void handshakeDone(); + [noscript] void certVerificationDone(); + [noscript] void clientAuthCertificateSelected(); }; |