summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http')
-rw-r--r--netwerk/protocol/http/Http2Compression.cpp33
-rw-r--r--netwerk/protocol/http/Http2Compression.h9
-rw-r--r--netwerk/protocol/http/HttpChannelChild.cpp49
-rw-r--r--netwerk/protocol/http/HttpChannelChild.h10
-rw-r--r--netwerk/protocol/http/TlsHandshaker.cpp18
-rw-r--r--netwerk/protocol/http/nsITlsHandshakeListener.idl2
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();
};