Bug 1451293 - single thread access to ConnectionHandle::mConn r=mayhemer

The goal of this patch is to make sure single thread access to ConnectionHandle::mConn.
It contains:
- Remove nsHttpTransaction::GetConnectionReference()
- For the cases where we need the sticky connection, save the reference of the sticky connection's transaction instead. Then, the sticky connection will be extracted in socket thread and set it to the new transaction.

Differential Revision: https://phabricator.services.mozilla.com/D17221

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Kershaw Chang 2019-02-04 08:42:09 +00:00
Родитель c59f885b06
Коммит a9a7383ac8
8 изменённых файлов: 224 добавлений и 136 удалений

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

@ -740,7 +740,7 @@ void TransactionObserver::Complete(nsHttpTransaction *aTrans, nsresult reason) {
}
mRanOnce = true;
RefPtr<nsAHttpConnection> conn = aTrans->GetConnectionReference();
RefPtr<nsAHttpConnection> conn = aTrans->Connection();
LOG(("TransactionObserver::Complete %p aTrans %p reason %" PRIx32
" conn %p\n",
this, aTrans, static_cast<uint32_t>(reason), conn.get()));

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

@ -795,20 +795,22 @@ nsresult nsHttpChannel::ContinueConnect() {
return DoConnect();
}
nsresult nsHttpChannel::DoConnect(nsAHttpConnection *aConn) {
LOG(("nsHttpChannel::DoConnect [this=%p]\n", this));
nsresult nsHttpChannel::DoConnect(nsHttpTransaction *aTransWithStickyConn) {
LOG(("nsHttpChannel::DoConnect [this=%p, aTransWithStickyConn=%p]\n", this,
aTransWithStickyConn));
nsresult rv = SetupTransaction();
if (NS_FAILED(rv)) {
return rv;
}
// transfer ownership of connection to transaction
if (aConn) {
mTransaction->SetConnection(aConn);
if (aTransWithStickyConn) {
rv = gHttpHandler->InitiateTransactionWithStickyConn(
mTransaction, mPriority, aTransWithStickyConn);
} else {
rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
}
rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
if (NS_FAILED(rv)) {
return rv;
}
@ -5930,15 +5932,7 @@ NS_IMETHODIMP nsHttpChannel::CloseStickyConnection() {
return NS_OK;
}
RefPtr<nsAHttpConnection> conn = mTransaction->GetConnectionReference();
if (!conn) {
LOG((" no connection"));
return NS_OK;
}
// This turns the IsPersistent() indicator on the connection to false,
// and makes us throw it away in OnStopRequest.
conn->DontReuse();
mTransaction->DontReuseConnection();
return NS_OK;
}
@ -7475,16 +7469,22 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
LOG(("nsHttpChannel %p has a strongly framed transaction: %d", this,
mStronglyFramed));
//
// grab references to connection in case we need to retry an
// authentication request over it or use it for an upgrade
// to another protocol.
//
// Save the reference of |mTransaction| to |transactionWithStickyConn|
// when it has a sticky connection.
// In the case we need to retry an authentication request, we need to
// reuse the connection of |transactionWithStickyConn|.
RefPtr<nsHttpTransaction> transactionWithStickyConn;
if (mCaps & NS_HTTP_STICKY_CONNECTION ||
mTransaction->Caps() & NS_HTTP_STICKY_CONNECTION) {
transactionWithStickyConn = mTransaction;
LOG((" transaction %p has sticky connection",
transactionWithStickyConn.get()));
}
// this code relies on the code in nsHttpTransaction::Close, which
// tests for NS_HTTP_STICKY_CONNECTION to determine whether or not to
// keep the connection around after the transaction is finished.
//
RefPtr<nsAHttpConnection> conn;
LOG((" mAuthRetryPending=%d, status=%" PRIx32 ", sticky conn cap=%d",
mAuthRetryPending, static_cast<uint32_t>(status),
mCaps & NS_HTTP_STICKY_CONNECTION));
@ -7492,39 +7492,20 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
// might have been updated by the transaction itself during inspection of
// the reposnse headers yet on the socket thread (found connection based
// auth schema).
if ((mAuthRetryPending || NS_FAILED(status)) &&
(mCaps & NS_HTTP_STICKY_CONNECTION ||
mTransaction->Caps() & NS_HTTP_STICKY_CONNECTION)) {
conn = mTransaction->GetConnectionReference();
LOG((" transaction %p provides connection %p", mTransaction.get(),
conn.get()));
if (conn) {
if (NS_FAILED(status)) {
// Close (don't reuse) the sticky connection if it's in the middle
// of an NTLM negotiation and this channel has been cancelled.
// There are proxy servers known to get confused when we send
// a new request over such a half-stated connection.
if (!mAuthConnectionRestartable) {
LOG((" not reusing a half-authenticated sticky connection"));
conn->DontReuse();
}
conn = nullptr;
} else if (!conn->IsPersistent()) {
// This is so far a workaround to fix leak when reusing unpersistent
// connection for authentication retry. See bug 459620 comment 4
// for details.
LOG((" connection is not persistent, not reusing it"));
conn = nullptr;
if ((mAuthRetryPending || NS_FAILED(status)) && transactionWithStickyConn) {
if (NS_FAILED(status)) {
// Close (don't reuse) the sticky connection if it's in the middle
// of an NTLM negotiation and this channel has been cancelled.
// There are proxy servers known to get confused when we send
// a new request over such a half-stated connection.
if (!mAuthConnectionRestartable) {
LOG((" not reusing a half-authenticated sticky connection"));
transactionWithStickyConn->DontReuseConnection();
}
}
}
RefPtr<nsAHttpConnection> stickyConn;
if (mCaps & NS_HTTP_STICKY_CONNECTION) {
stickyConn = mTransaction->GetConnectionReference();
}
mTransferSize = mTransaction->GetTransferSize();
// If we are using the transaction to serve content, we also save the
@ -7566,18 +7547,20 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
if (authRetry) {
mAuthRetryPending = false;
auto continueOSR = [authRetry, isFromNet, contentComplete,
stickyConn{std::move(stickyConn)}](auto *self,
nsresult aStatus) {
transactionWithStickyConn](auto *self,
nsresult aStatus) {
return self->ContinueOnStopRequestAfterAuthRetry(
aStatus, authRetry, isFromNet, contentComplete, stickyConn);
aStatus, authRetry, isFromNet, contentComplete,
transactionWithStickyConn);
};
status = DoAuthRetry(conn, continueOSR);
status = DoAuthRetry(transactionWithStickyConn, continueOSR);
if (NS_SUCCEEDED(status)) {
return NS_OK;
}
}
return ContinueOnStopRequestAfterAuthRetry(status, authRetry, isFromNet,
contentComplete, stickyConn);
contentComplete,
transactionWithStickyConn);
}
return ContinueOnStopRequest(status, isFromNet, contentComplete);
@ -7585,13 +7568,13 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
nsresult nsHttpChannel::ContinueOnStopRequestAfterAuthRetry(
nsresult aStatus, bool aAuthRetry, bool aIsFromNet, bool aContentComplete,
nsAHttpConnection *aStickyConn) {
nsHttpTransaction *aTransWithStickyConn) {
LOG(
("nsHttpChannel::ContinueOnStopRequestAfterAuthRetry "
"[this=%p, aStatus=%" PRIx32
" aAuthRetry=%d, aIsFromNet=%d, aStickyConn=%p]\n",
" aAuthRetry=%d, aIsFromNet=%d, aTransWithStickyConn=%p]\n",
this, static_cast<uint32_t>(aStatus), aAuthRetry, aIsFromNet,
aStickyConn));
aTransWithStickyConn));
if (aAuthRetry && NS_SUCCEEDED(aStatus)) {
return NS_OK;
@ -7623,20 +7606,20 @@ nsresult nsHttpChannel::ContinueOnStopRequestAfterAuthRetry(
return NS_OK;
}
bool upgradeWebsocket = mUpgradeProtocolCallback && aStickyConn &&
bool upgradeWebsocket = mUpgradeProtocolCallback && aTransWithStickyConn &&
mResponseHead &&
((mResponseHead->Status() == 101 &&
mResponseHead->Version() == HttpVersion::v1_1) ||
(mResponseHead->Status() == 200 &&
mResponseHead->Version() == HttpVersion::v2_0));
bool upgradeConnect = mUpgradeProtocolCallback && aStickyConn &&
bool upgradeConnect = mUpgradeProtocolCallback && aTransWithStickyConn &&
(mCaps & NS_HTTP_CONNECT_ONLY) && mResponseHead &&
mResponseHead->Status() == 200;
if (upgradeWebsocket || upgradeConnect) {
nsresult rv = gHttpHandler->ConnMgr()->CompleteUpgrade(
aStickyConn, mUpgradeProtocolCallback);
aTransWithStickyConn, mUpgradeProtocolCallback);
if (NS_FAILED(rv)) {
LOG((" CompleteUpgrade failed with %08x", static_cast<uint32_t>(rv)));
}
@ -8401,10 +8384,11 @@ nsHttpChannel::ResumeAt(uint64_t aStartPos, const nsACString &aEntityID) {
}
nsresult nsHttpChannel::DoAuthRetry(
nsAHttpConnection *conn,
nsHttpTransaction *aTransWithStickyConn,
const std::function<nsresult(nsHttpChannel *, nsresult)>
&aContinueOnStopRequestFunc) {
LOG(("nsHttpChannel::DoAuthRetry [this=%p]\n", this));
LOG(("nsHttpChannel::DoAuthRetry [this=%p, aTransWithStickyConn=%p]\n", this,
aTransWithStickyConn));
MOZ_ASSERT(!mTransaction, "should not have a transaction");
@ -8427,15 +8411,15 @@ nsresult nsHttpChannel::DoAuthRetry(
// notify "http-on-modify-request" observers
CallOnModifyRequestObservers();
RefPtr<nsAHttpConnection> connRef(conn);
RefPtr<nsHttpTransaction> trans(aTransWithStickyConn);
return CallOrWaitForResume(
[conn{std::move(connRef)}, aContinueOnStopRequestFunc](auto *self) {
return self->ContinueDoAuthRetry(conn, aContinueOnStopRequestFunc);
[trans{std::move(trans)}, aContinueOnStopRequestFunc](auto *self) {
return self->ContinueDoAuthRetry(trans, aContinueOnStopRequestFunc);
});
}
nsresult nsHttpChannel::ContinueDoAuthRetry(
nsAHttpConnection *aConn,
nsHttpTransaction *aTransWithStickyConn,
const std::function<nsresult(nsHttpChannel *, nsresult)>
&aContinueOnStopRequestFunc) {
LOG(("nsHttpChannel::ContinueDoAuthRetry [this=%p]\n", this));
@ -8468,10 +8452,10 @@ nsresult nsHttpChannel::ContinueDoAuthRetry(
// notify "http-on-before-connect" observers
gHttpHandler->OnBeforeConnect(this);
RefPtr<nsAHttpConnection> connRef(aConn);
RefPtr<nsHttpTransaction> trans(aTransWithStickyConn);
return CallOrWaitForResume(
[conn{std::move(connRef)}, aContinueOnStopRequestFunc](auto *self) {
nsresult rv = self->DoConnect(conn);
[trans{std::move(trans)}, aContinueOnStopRequestFunc](auto *self) {
nsresult rv = self->DoConnect(trans);
return aContinueOnStopRequestFunc(self, rv);
});
}

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

@ -431,15 +431,18 @@ class nsHttpChannel final : public HttpBaseChannel,
MOZ_MUST_USE nsresult OnDoneReadingPartialCacheEntry(bool *streamDone);
MOZ_MUST_USE nsresult
DoAuthRetry(nsAHttpConnection *,
const std::function<nsresult(nsHttpChannel *, nsresult)> &aOuter);
MOZ_MUST_USE nsresult ContinueDoAuthRetry(
nsAHttpConnection *aConn,
const std::function<nsresult(nsHttpChannel *, nsresult)> &aOuter);
MOZ_MUST_USE nsresult DoConnect(nsAHttpConnection *aConn = nullptr);
DoAuthRetry(nsHttpTransaction *aTransWithStickyConn,
const std::function<nsresult(nsHttpChannel *, nsresult)>
&aContinueOnStopRequestFunc);
MOZ_MUST_USE nsresult
ContinueDoAuthRetry(nsHttpTransaction *aTransWithStickyConn,
const std::function<nsresult(nsHttpChannel *, nsresult)>
&aContinueOnStopRequestFunc);
MOZ_MUST_USE nsresult
DoConnect(nsHttpTransaction *aTransWithStickyConn = nullptr);
MOZ_MUST_USE nsresult ContinueOnStopRequestAfterAuthRetry(
nsresult aStatus, bool aAuthRetry, bool aIsFromNet, bool aContentComplete,
nsAHttpConnection *aStickyConn);
nsHttpTransaction *aTransWithStickyConn);
MOZ_MUST_USE nsresult ContinueOnStopRequest(nsresult status, bool aIsFromNet,
bool aContentComplete);

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

@ -370,6 +370,37 @@ nsresult nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans,
return PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
}
class NewTransactionData : public ARefBase {
public:
NewTransactionData(nsHttpTransaction *trans, int32_t priority,
nsHttpTransaction *transWithStickyConn)
: mTrans(trans),
mPriority(priority),
mTransWithStickyConn(transWithStickyConn) {}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NewTransactionData, override)
RefPtr<nsHttpTransaction> mTrans;
int32_t mPriority;
RefPtr<nsHttpTransaction> mTransWithStickyConn;
private:
virtual ~NewTransactionData() = default;
};
nsresult nsHttpConnectionMgr::AddTransactionWithStickyConn(
nsHttpTransaction *trans, int32_t priority,
nsHttpTransaction *transWithStickyConn) {
LOG(
("nsHttpConnectionMgr::AddTransactionWithStickyConn "
"[trans=%p %d transWithStickyConn=%p]\n",
trans, priority, transWithStickyConn));
RefPtr<NewTransactionData> data =
new NewTransactionData(trans, priority, transWithStickyConn);
return PostEvent(&nsHttpConnectionMgr::OnMsgNewTransactionWithStickyConn, 0,
data);
}
nsresult nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *trans,
int32_t priority) {
LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%p %d]\n", trans,
@ -515,17 +546,17 @@ nsresult nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *conn) {
return PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
}
// A structure used to marshall 5 pointers across the various necessary
// A structure used to marshall 6 pointers across the various necessary
// threads to complete an HTTP upgrade.
class nsCompleteUpgradeData : public ARefBase {
public:
nsCompleteUpgradeData(nsAHttpConnection *aConn,
nsCompleteUpgradeData(nsHttpTransaction *aTrans,
nsIHttpUpgradeListener *aListener, bool aJsWrapped)
: mConn(aConn), mUpgradeListener(aListener), mJsWrapped(aJsWrapped) {}
: mTrans(aTrans), mUpgradeListener(aListener), mJsWrapped(aJsWrapped) {}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsCompleteUpgradeData, override)
RefPtr<nsAHttpConnection> mConn;
RefPtr<nsHttpTransaction> mTrans;
nsCOMPtr<nsIHttpUpgradeListener> mUpgradeListener;
nsCOMPtr<nsISocketTransport> mSocketTransport;
@ -539,14 +570,14 @@ class nsCompleteUpgradeData : public ARefBase {
};
nsresult nsHttpConnectionMgr::CompleteUpgrade(
nsAHttpConnection *aConn, nsIHttpUpgradeListener *aUpgradeListener) {
nsHttpTransaction *aTrans, nsIHttpUpgradeListener *aUpgradeListener) {
// test if aUpgradeListener is a wrapped JsObject
nsCOMPtr<nsIXPConnectWrappedJS> wrapper = do_QueryInterface(aUpgradeListener);
bool wrapped = !!wrapper;
RefPtr<nsCompleteUpgradeData> data =
new nsCompleteUpgradeData(aConn, aUpgradeListener, wrapped);
new nsCompleteUpgradeData(aTrans, aUpgradeListener, wrapped);
return PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
}
@ -2309,6 +2340,38 @@ void nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority,
if (NS_FAILED(rv)) trans->Close(rv); // for whatever its worth
}
void nsHttpConnectionMgr::OnMsgNewTransactionWithStickyConn(int32_t priority,
ARefBase *param) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
NewTransactionData *data = static_cast<NewTransactionData *>(param);
LOG(
("nsHttpConnectionMgr::OnMsgNewTransactionWithStickyConn "
"[trans=%p, transWithStickyConn=%p, conn=%p]\n",
data->mTrans.get(), data->mTransWithStickyConn.get(),
data->mTransWithStickyConn->Connection()));
MOZ_ASSERT(data->mTransWithStickyConn &&
data->mTransWithStickyConn->Caps() & NS_HTTP_STICKY_CONNECTION);
data->mTrans->SetPriority(data->mPriority);
RefPtr<nsAHttpConnection> conn = data->mTransWithStickyConn->Connection();
if (conn && conn->IsPersistent()) {
// This is so far a workaround to only reuse persistent
// connection for authentication retry. See bug 459620 comment 4
// for details.
LOG((" Reuse connection [%p] for transaction [%p]", conn.get(),
data->mTrans.get()));
data->mTrans->SetConnection(conn);
}
nsresult rv = ProcessNewTransaction(data->mTrans);
if (NS_FAILED(rv)) {
data->mTrans->Close(rv); // for whatever its worth
}
}
static uint64_t TabIdForQueuing(nsAHttpTransaction *transaction) {
return gHttpHandler->ActiveTabPriority()
? transaction->TopLevelOuterContentWindowId()
@ -2792,43 +2855,54 @@ void nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, ARefBase *param) {
}
void nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, ARefBase *param) {
nsCompleteUpgradeData *data = static_cast<nsCompleteUpgradeData *>(param);
MOZ_ASSERT(OnSocketThread() || (data->mJsWrapped == NS_IsMainThread()),
"not on socket thread");
LOG((
"nsHttpConnectionMgr::OnMsgCompleteUpgrade "
"this=%p conn=%p listener=%p wrapped=%d\n",
this, data->mConn.get(), data->mUpgradeListener.get(), data->mJsWrapped));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
nsresult rv = NS_OK;
if (!data->mSocketTransport) {
rv = data->mConn->TakeTransport(getter_AddRefs(data->mSocketTransport),
getter_AddRefs(data->mSocketIn),
getter_AddRefs(data->mSocketOut));
nsCompleteUpgradeData *data = static_cast<nsCompleteUpgradeData *>(param);
MOZ_ASSERT(data->mTrans && data->mTrans->Caps() & NS_HTTP_STICKY_CONNECTION);
RefPtr<nsAHttpConnection> conn(data->mTrans->Connection());
LOG(
("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
"conn=%p listener=%p wrapped=%d\n",
conn.get(), data->mUpgradeListener.get(), data->mJsWrapped));
if (!conn) {
return;
}
if (NS_SUCCEEDED(rv)) {
if (!data->mJsWrapped || !OnSocketThread()) {
rv = data->mUpgradeListener->OnTransportAvailable(
data->mSocketTransport, data->mSocketIn, data->mSocketOut);
if (NS_FAILED(rv)) {
LOG(
("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
"this=%p conn=%p listener=%p wrapped=%d\n",
this, data->mConn.get(), data->mUpgradeListener.get(),
data->mJsWrapped));
}
} else {
LOG(
("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
"this=%p conn=%p listener=%p wrapped=%d pass to main thread\n",
this, data->mConn.get(), data->mUpgradeListener.get(),
data->mJsWrapped));
MOZ_ASSERT(!data->mSocketTransport);
rv = conn->TakeTransport(getter_AddRefs(data->mSocketTransport),
getter_AddRefs(data->mSocketIn),
getter_AddRefs(data->mSocketOut));
nsCOMPtr<nsIRunnable> event = new ConnEvent(
this, &nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, param);
NS_DispatchToMainThread(event);
if (NS_FAILED(rv)) {
return;
}
RefPtr<nsCompleteUpgradeData> upgradeData(data);
auto transportAvailableFunc = [upgradeData{std::move(upgradeData)}]() {
nsresult rv = upgradeData->mUpgradeListener->OnTransportAvailable(
upgradeData->mSocketTransport, upgradeData->mSocketIn,
upgradeData->mSocketOut);
if (NS_FAILED(rv)) {
LOG(
("nsHttpConnectionMgr::OnMsgCompleteUpgrade OnTransportAvailable "
"failed. listener=%p\n",
upgradeData->mUpgradeListener.get()));
}
};
if (data->mJsWrapped) {
LOG(
("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
"conn=%p listener=%p wrapped=%d pass to main thread\n",
conn.get(), data->mUpgradeListener.get(), data->mJsWrapped));
NS_DispatchToMainThread(
NS_NewRunnableFunction("net::nsHttpConnectionMgr::OnMsgCompleteUpgrade",
transportAvailableFunc));
} else {
transportAvailableFunc();
}
}
@ -3796,11 +3870,20 @@ void nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, ARefBase *param) {
}
}
bool ConnectionHandle::IsPersistent() { return mConn->IsPersistent(); }
bool ConnectionHandle::IsPersistent() {
MOZ_ASSERT(OnSocketThread());
return mConn->IsPersistent();
}
bool ConnectionHandle::IsReused() { return mConn->IsReused(); }
bool ConnectionHandle::IsReused() {
MOZ_ASSERT(OnSocketThread());
return mConn->IsReused();
}
void ConnectionHandle::DontReuse() { mConn->DontReuse(); }
void ConnectionHandle::DontReuse() {
MOZ_ASSERT(OnSocketThread());
mConn->DontReuse();
}
nsresult ConnectionHandle::PushBack(const char *buf, uint32_t bufLen) {
return mConn->PushBack(buf, bufLen);

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

@ -106,6 +106,11 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache {
// adds a transaction to the list of managed transactions.
MOZ_MUST_USE nsresult AddTransaction(nsHttpTransaction *, int32_t priority);
// Add a new transaction with a sticky connection from |transWithStickyConn|.
MOZ_MUST_USE nsresult
AddTransactionWithStickyConn(nsHttpTransaction *trans, int32_t priority,
nsHttpTransaction *transWithStickyConn);
// called to reschedule the given transaction. it must already have been
// added to the connection manager via AddTransaction.
MOZ_MUST_USE nsresult RescheduleTransaction(nsHttpTransaction *,
@ -161,8 +166,10 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache {
// socket thread after a 101 response has been received and the socket
// needs to be transferred to an expectant upgrade listener such as
// websockets.
// @param aTrans: a transaction that contains a sticky connection. We'll
// take the transport of this connection.
MOZ_MUST_USE nsresult CompleteUpgrade(
nsAHttpConnection *aConn, nsIHttpUpgradeListener *aUpgradeListener);
nsHttpTransaction *aTrans, nsIHttpUpgradeListener *aUpgradeListener);
// called to update a parameter after the connection manager has already
// been initialized.
@ -666,6 +673,7 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache {
void OnMsgShutdown(int32_t, ARefBase *);
void OnMsgShutdownConfirm(int32_t, ARefBase *);
void OnMsgNewTransaction(int32_t, ARefBase *);
void OnMsgNewTransactionWithStickyConn(int32_t, ARefBase *);
void OnMsgReschedTransaction(int32_t, ARefBase *);
void OnMsgUpdateClassOfServiceOnTransaction(int32_t, ARefBase *);
void OnMsgCancelTransaction(int32_t, ARefBase *);

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

@ -240,6 +240,16 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
return mConnMgr->AddTransaction(trans, priority);
}
// This function is also called to kick-off a new transaction. But the new
// transaction will take a sticky connection from |transWithStickyConn|
// and reuse it.
MOZ_MUST_USE nsresult
InitiateTransactionWithStickyConn(nsHttpTransaction *trans, int32_t priority,
nsHttpTransaction *transWithStickyConn) {
return mConnMgr->AddTransactionWithStickyConn(trans, priority,
transWithStickyConn);
}
// Called to change the priority of an existing transaction that has
// already been initiated.
MOZ_MUST_USE nsresult RescheduleTransaction(nsHttpTransaction *trans,

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

@ -462,20 +462,6 @@ nsAHttpConnection *nsHttpTransaction::Connection() {
return mConnection.get();
}
already_AddRefed<nsAHttpConnection>
nsHttpTransaction::GetConnectionReference() {
if (mH2WSTransaction) {
// Need to let the websocket transaction/connection know we've reached
// this point so it can stop forwarding information through us and
// instead communicate directly with the websocket channel.
mH2WSTransaction->SetConnRefTaken();
mH2WSTransaction = nullptr;
}
MutexAutoLock lock(mLock);
RefPtr<nsAHttpConnection> connection(mConnection);
return connection.forget();
}
nsHttpResponseHead *nsHttpTransaction::TakeResponseHead() {
MOZ_ASSERT(!mResponseHeadTaken, "TakeResponseHead called 2x");
@ -882,6 +868,22 @@ bool nsHttpTransaction::ShouldThrottle() {
return true;
}
void nsHttpTransaction::DontReuseConnection() {
LOG(("nsHttpTransaction::DontReuseConnection %p\n", this));
if (!OnSocketThread()) {
LOG(("DontReuseConnection %p not on socket thread\n", this));
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("nsHttpTransaction::DontReuseConnection", this,
&nsHttpTransaction::DontReuseConnection);
gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
return;
}
if (mConnection) {
mConnection->DontReuse();
}
}
nsresult nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
uint32_t count,
uint32_t *countWritten) {

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

@ -111,10 +111,6 @@ class nsHttpTransaction final : public nsAHttpTransaction,
// Returning null if there is no trailer.
nsHttpHeaderArray *TakeResponseTrailers();
// Provides a thread safe reference of the connection
// nsHttpTransaction::Connection should only be used on the socket thread
already_AddRefed<nsAHttpConnection> GetConnectionReference();
// Called to set/find out if the transaction generated a complete response.
bool ResponseIsComplete() { return mResponseIsComplete; }
void SetResponseIsComplete() { mResponseIsComplete = true; }
@ -428,6 +424,8 @@ class nsHttpTransaction final : public nsAHttpTransaction,
// class has been set while Leader, Unblocked, DontThrottle has not.
bool EligibleForThrottling() const;
void DontReuseConnection();
private:
bool mSubmittedRatePacing;
bool mPassedRatePacing;