зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1754744 - isolating TLS handshake code, r=necko-reviewers,dragana
Differential Revision: https://phabricator.services.mozilla.com/D141093
This commit is contained in:
Родитель
7f4ca3792c
Коммит
dc33837cad
|
@ -139,8 +139,9 @@ void DnsAndConnectSocket::PrintDiagnostics(nsCString& log) {
|
||||||
void nsHttpConnection::PrintDiagnostics(nsCString& log) {
|
void nsHttpConnection::PrintDiagnostics(nsCString& log) {
|
||||||
log.AppendPrintf(" CanDirectlyActivate = %d\n", CanDirectlyActivate());
|
log.AppendPrintf(" CanDirectlyActivate = %d\n", CanDirectlyActivate());
|
||||||
|
|
||||||
log.AppendPrintf(" npncomplete = %d setupSSLCalled = %d\n", mNPNComplete,
|
log.AppendPrintf(" npncomplete = %d setupSSLCalled = %d\n",
|
||||||
mSetupSSLCalled);
|
mTlsHandshaker->NPNComplete(),
|
||||||
|
mTlsHandshaker->SetupSSLCalled());
|
||||||
|
|
||||||
log.AppendPrintf(" spdyVersion = %d reportedSpdy = %d everspdy = %d\n",
|
log.AppendPrintf(" spdyVersion = %d reportedSpdy = %d everspdy = %d\n",
|
||||||
static_cast<int32_t>(mUsingSpdyVersion), mReportedSpdy,
|
static_cast<int32_t>(mUsingSpdyVersion), mReportedSpdy,
|
||||||
|
|
|
@ -0,0 +1,332 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=4 sw=2 sts=2 et cin: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
// HttpLog.h should generally be included first
|
||||||
|
#include "HttpLog.h"
|
||||||
|
|
||||||
|
#include "TlsHandshaker.h"
|
||||||
|
#include "nsHttpConnectionInfo.h"
|
||||||
|
#include "nsHttpConnection.h"
|
||||||
|
#include "nsHttpHandler.h"
|
||||||
|
#include "nsISSLSocketControl.h"
|
||||||
|
#include "mozilla/StaticPrefs_network.h"
|
||||||
|
|
||||||
|
#define TLS_EARLY_DATA_NOT_AVAILABLE 0
|
||||||
|
#define TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED 1
|
||||||
|
#define TLS_EARLY_DATA_AVAILABLE_AND_USED 2
|
||||||
|
|
||||||
|
namespace mozilla::net {
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(TlsHandshaker, nsITlsHandshakeCallbackListener)
|
||||||
|
|
||||||
|
TlsHandshaker::TlsHandshaker(nsHttpConnectionInfo* aInfo,
|
||||||
|
nsHttpConnection* aOwner)
|
||||||
|
: mConnInfo(aInfo), mOwner(aOwner) {
|
||||||
|
LOG(("TlsHandshaker ctor %p", this));
|
||||||
|
}
|
||||||
|
|
||||||
|
TlsHandshaker::~TlsHandshaker() { LOG(("TlsHandshaker dtor %p", this)); }
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
TlsHandshaker::HandshakeDone() {
|
||||||
|
LOG(("TlsHandshaker::HandshakeDone mOwner=%p", mOwner.get()));
|
||||||
|
if (mOwner) {
|
||||||
|
mTlsHandshakeComplitionPending = true;
|
||||||
|
|
||||||
|
// HandshakeDone needs to be dispatched so that it is not called inside
|
||||||
|
// nss locks.
|
||||||
|
RefPtr<TlsHandshaker> self(this);
|
||||||
|
NS_DispatchToCurrentThread(NS_NewRunnableFunction(
|
||||||
|
"TlsHandshaker::HandshakeDoneInternal", [self{std::move(self)}]() {
|
||||||
|
if (self->mTlsHandshakeComplitionPending && self->mOwner) {
|
||||||
|
self->mOwner->HandshakeDoneInternal();
|
||||||
|
self->mTlsHandshakeComplitionPending = false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TlsHandshaker::SetupSSL(bool aInSpdyTunnel, bool aForcePlainText) {
|
||||||
|
if (!mOwner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG1(("TlsHandshaker::SetupSSL %p caps=0x%X %s\n", mOwner.get(),
|
||||||
|
mOwner->TransactionCaps(), mConnInfo->HashKey().get()));
|
||||||
|
|
||||||
|
if (mSetupSSLCalled) { // do only once
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mSetupSSLCalled = true;
|
||||||
|
|
||||||
|
if (mNPNComplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we flip this back to false if SetNPNList succeeds at the end
|
||||||
|
// of this function
|
||||||
|
mNPNComplete = true;
|
||||||
|
|
||||||
|
if (!mConnInfo->FirstHopSSL() || aForcePlainText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are connected to the proxy with TLS, start the TLS
|
||||||
|
// flow immediately without waiting for a CONNECT sequence.
|
||||||
|
DebugOnly<nsresult> rv{};
|
||||||
|
if (aInSpdyTunnel) {
|
||||||
|
rv = InitSSLParams(false, true);
|
||||||
|
} else {
|
||||||
|
bool usingHttpsProxy = mConnInfo->UsingHttpsProxy();
|
||||||
|
rv = InitSSLParams(usingHttpsProxy, usingHttpsProxy);
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult TlsHandshaker::InitSSLParams(bool connectingToProxy,
|
||||||
|
bool proxyStartSSL) {
|
||||||
|
LOG(("TlsHandshaker::InitSSLParams [mOwner=%p] connectingToProxy=%d\n",
|
||||||
|
mOwner.get(), connectingToProxy));
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
|
||||||
|
if (!mOwner) {
|
||||||
|
return NS_ERROR_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsISupports> securityInfo;
|
||||||
|
mOwner->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||||
|
if (!securityInfo) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If proxy is use or 0RTT is excluded for a origin, don't use early-data.
|
||||||
|
if (mConnInfo->UsingProxy() || gHttpHandler->Is0RttTcpExcluded(mConnInfo)) {
|
||||||
|
ssl->DisableEarlyData();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxyStartSSL) {
|
||||||
|
rv = ssl->ProxyStartSSL();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(SetupNPNList(ssl, mOwner->TransactionCaps())) &&
|
||||||
|
NS_SUCCEEDED(ssl->SetHandshakeCallbackListener(this))) {
|
||||||
|
LOG(("InitSSLParams Setting up SPDY Negotiation OK mOwner=%p",
|
||||||
|
mOwner.get()));
|
||||||
|
mNPNComplete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The naming of NPN is historical - this function creates the basic
|
||||||
|
// offer list for both NPN and ALPN. ALPN validation callbacks are made
|
||||||
|
// now before the handshake is complete, and NPN validation callbacks
|
||||||
|
// are made during the handshake.
|
||||||
|
nsresult TlsHandshaker::SetupNPNList(nsISSLSocketControl* ssl, uint32_t caps) {
|
||||||
|
nsTArray<nsCString> protocolArray;
|
||||||
|
|
||||||
|
nsCString npnToken = mConnInfo->GetNPNToken();
|
||||||
|
if (npnToken.IsEmpty()) {
|
||||||
|
// The first protocol is used as the fallback if none of the
|
||||||
|
// protocols supported overlap with the server's list.
|
||||||
|
// When using ALPN the advertised preferences are protocolArray indicies
|
||||||
|
// {1, .., N, 0} in decreasing order.
|
||||||
|
// For NPN, In the case of overlap, matching priority is driven by
|
||||||
|
// the order of the server's advertisement - with index 0 used when
|
||||||
|
// there is no match.
|
||||||
|
protocolArray.AppendElement("http/1.1"_ns);
|
||||||
|
|
||||||
|
if (StaticPrefs::network_http_http2_enabled() &&
|
||||||
|
!(caps & NS_HTTP_DISALLOW_SPDY)) {
|
||||||
|
LOG(("nsHttpConnection::SetupSSL Allow SPDY NPN selection"));
|
||||||
|
const SpdyInformation* info = gHttpHandler->SpdyInfo();
|
||||||
|
if (info->ALPNCallbacks(ssl)) {
|
||||||
|
protocolArray.AppendElement(info->VersionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(("nsHttpConnection::SetupSSL limiting NPN selection to %s",
|
||||||
|
npnToken.get()));
|
||||||
|
protocolArray.AppendElement(npnToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = ssl->SetNPNList(protocolArray);
|
||||||
|
LOG(("TlsHandshaker::SetupNPNList %p %" PRIx32 "\n", mOwner.get(),
|
||||||
|
static_cast<uint32_t>(rv)));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if TLS handshake is needed and it is responsible to move it forward.
|
||||||
|
bool TlsHandshaker::EnsureNPNComplete() {
|
||||||
|
if (!mOwner) {
|
||||||
|
mNPNComplete = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISocketTransport> transport = mOwner->Transport();
|
||||||
|
MOZ_ASSERT(transport);
|
||||||
|
if (!transport) {
|
||||||
|
// this cannot happen
|
||||||
|
mNPNComplete = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNPNComplete) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTlsHandshakeComplitionPending) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
nsCOMPtr<nsISupports> securityInfo;
|
||||||
|
mOwner->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||||
|
if (!securityInfo) {
|
||||||
|
FinishNPNSetup(false, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
FinishNPNSetup(false, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m0RTTChecked) {
|
||||||
|
// We reuse m0RTTChecked. We want to send this status only once.
|
||||||
|
RefPtr<nsAHttpTransaction> transaction = mOwner->Transaction();
|
||||||
|
nsCOMPtr<nsISocketTransport> transport = mOwner->Transport();
|
||||||
|
if (transaction && transport) {
|
||||||
|
transaction->OnTransportStatus(transport,
|
||||||
|
NS_NET_STATUS_TLS_HANDSHAKE_STARTING, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(("TlsHandshaker::EnsureNPNComplete [mOwner=%p] drive TLS handshake",
|
||||||
|
mOwner.get()));
|
||||||
|
rv = ssl->DriveHandshake();
|
||||||
|
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||||
|
FinishNPNSetup(false, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Check0RttEnabled(ssl);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TlsHandshaker::EarlyDataDone() {
|
||||||
|
if (mEarlyDataState == EarlyData::USED) {
|
||||||
|
mEarlyDataState = EarlyData::DONE_USED;
|
||||||
|
} else if (mEarlyDataState == EarlyData::CANNOT_BE_USED) {
|
||||||
|
mEarlyDataState = EarlyData::DONE_CANNOT_BE_USED;
|
||||||
|
} else if (mEarlyDataState == EarlyData::NOT_AVAILABLE) {
|
||||||
|
mEarlyDataState = EarlyData::DONE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TlsHandshaker::FinishNPNSetup(bool handshakeSucceeded,
|
||||||
|
bool hasSecurityInfo) {
|
||||||
|
LOG(("TlsHandshaker::FinishNPNSetup mOwner=%p", mOwner.get()));
|
||||||
|
mNPNComplete = true;
|
||||||
|
|
||||||
|
mOwner->PostProcessNPNSetup(handshakeSucceeded, hasSecurityInfo,
|
||||||
|
EarlyDataUsed());
|
||||||
|
EarlyDataDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TlsHandshaker::Check0RttEnabled(nsISSLSocketControl* ssl) {
|
||||||
|
if (!mOwner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m0RTTChecked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m0RTTChecked = true;
|
||||||
|
|
||||||
|
if (mConnInfo->UsingProxy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no ALPN info (yet!). We need to consider doing 0RTT. We
|
||||||
|
// will do so if there is ALPN information from a previous session
|
||||||
|
// (AlpnEarlySelection), we are using HTTP/1, and the request data can
|
||||||
|
// be safely retried.
|
||||||
|
if (NS_FAILED(ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN))) {
|
||||||
|
LOG1(
|
||||||
|
("TlsHandshaker::Check0RttEnabled %p - "
|
||||||
|
"early selected alpn not available",
|
||||||
|
mOwner.get()));
|
||||||
|
} else {
|
||||||
|
LOG1(
|
||||||
|
("TlsHandshaker::Check0RttEnabled %p -"
|
||||||
|
"early selected alpn: %s",
|
||||||
|
mOwner.get(), mEarlyNegotiatedALPN.get()));
|
||||||
|
const SpdyInformation* info = gHttpHandler->SpdyInfo();
|
||||||
|
if (!mEarlyNegotiatedALPN.Equals(info->VersionString)) {
|
||||||
|
// This is the HTTP/1 case.
|
||||||
|
// Check if early-data is allowed for this transaction.
|
||||||
|
RefPtr<nsAHttpTransaction> transaction = mOwner->Transaction();
|
||||||
|
if (transaction && transaction->Do0RTT()) {
|
||||||
|
LOG(
|
||||||
|
("TlsHandshaker::Check0RttEnabled [mOwner=%p] - We "
|
||||||
|
"can do 0RTT (http/1)!",
|
||||||
|
mOwner.get()));
|
||||||
|
mEarlyDataState = EarlyData::USED;
|
||||||
|
} else {
|
||||||
|
mEarlyDataState = EarlyData::CANNOT_BE_USED;
|
||||||
|
// Poll for read now. Polling for write will cause us to busy wait.
|
||||||
|
// When the handshake is done the polling flags will be set correctly.
|
||||||
|
Unused << mOwner->ResumeRecv();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We have h2, we can at least 0-RTT the preamble and opening
|
||||||
|
// SETTINGS, etc, and maybe some of the first request
|
||||||
|
LOG(
|
||||||
|
("TlsHandshaker::Check0RttEnabled [mOwner=%p] - Starting "
|
||||||
|
"0RTT for h2!",
|
||||||
|
mOwner.get()));
|
||||||
|
mEarlyDataState = EarlyData::USED;
|
||||||
|
mOwner->Start0RTTSpdy(info->Version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TlsHandshaker::EarlyDataTelemetry(int16_t tlsVersion,
|
||||||
|
bool earlyDataAccepted,
|
||||||
|
int64_t aContentBytesWritten0RTT) {
|
||||||
|
// Send the 0RTT telemetry only for tls1.3
|
||||||
|
if (tlsVersion > nsISSLSocketControl::TLS_VERSION_1_2) {
|
||||||
|
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_NEGOTIATED,
|
||||||
|
(mEarlyDataState == EarlyData::NOT_AVAILABLE)
|
||||||
|
? TLS_EARLY_DATA_NOT_AVAILABLE
|
||||||
|
: ((mEarlyDataState == EarlyData::USED)
|
||||||
|
? TLS_EARLY_DATA_AVAILABLE_AND_USED
|
||||||
|
: TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED));
|
||||||
|
if (EarlyDataUsed()) {
|
||||||
|
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_ACCEPTED,
|
||||||
|
earlyDataAccepted);
|
||||||
|
}
|
||||||
|
if (earlyDataAccepted) {
|
||||||
|
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_BYTES_WRITTEN,
|
||||||
|
aContentBytesWritten0RTT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla::net
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* 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 TlsHandshaker_h__
|
||||||
|
#define TlsHandshaker_h__
|
||||||
|
|
||||||
|
#include "nsITlsHandshakeListener.h"
|
||||||
|
|
||||||
|
class nsISocketTransport;
|
||||||
|
class nsISSLSocketControl;
|
||||||
|
|
||||||
|
namespace mozilla::net {
|
||||||
|
|
||||||
|
class nsHttpConnection;
|
||||||
|
class nsHttpConnectionInfo;
|
||||||
|
|
||||||
|
class TlsHandshaker : public nsITlsHandshakeCallbackListener {
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSITLSHANDSHAKECALLBACKLISTENER
|
||||||
|
|
||||||
|
TlsHandshaker(nsHttpConnectionInfo* aInfo, nsHttpConnection* aOwner);
|
||||||
|
|
||||||
|
void SetupSSL(bool aInSpdyTunnel, bool aForcePlainText);
|
||||||
|
[[nodiscard]] nsresult InitSSLParams(bool connectingToProxy,
|
||||||
|
bool ProxyStartSSL);
|
||||||
|
[[nodiscard]] nsresult SetupNPNList(nsISSLSocketControl* ssl, uint32_t caps);
|
||||||
|
// Makes certain the SSL handshake is complete and NPN negotiation
|
||||||
|
// has had a chance to happen
|
||||||
|
[[nodiscard]] bool EnsureNPNComplete();
|
||||||
|
void FinishNPNSetup(bool handshakeSucceeded, bool hasSecurityInfo);
|
||||||
|
bool EarlyDataAvailable() const {
|
||||||
|
return mEarlyDataState == EarlyData::USED ||
|
||||||
|
mEarlyDataState == EarlyData::CANNOT_BE_USED;
|
||||||
|
}
|
||||||
|
bool EarlyDataWasAvailable() const {
|
||||||
|
return mEarlyDataState != EarlyData::NOT_AVAILABLE &&
|
||||||
|
mEarlyDataState != EarlyData::DONE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
bool EarlyDataUsed() const { return mEarlyDataState == EarlyData::USED; }
|
||||||
|
bool EarlyDataCanNotBeUsed() const {
|
||||||
|
return mEarlyDataState == EarlyData::CANNOT_BE_USED;
|
||||||
|
}
|
||||||
|
void EarlyDataDone();
|
||||||
|
void EarlyDataTelemetry(int16_t tlsVersion, bool earlyDataAccepted,
|
||||||
|
int64_t aContentBytesWritten0RTT);
|
||||||
|
|
||||||
|
bool NPNComplete() const { return mNPNComplete; }
|
||||||
|
bool SetupSSLCalled() const { return mSetupSSLCalled; }
|
||||||
|
bool TlsHandshakeComplitionPending() const {
|
||||||
|
return mTlsHandshakeComplitionPending;
|
||||||
|
}
|
||||||
|
const nsCString& EarlyNegotiatedALPN() const { return mEarlyNegotiatedALPN; }
|
||||||
|
void SetNPNComplete() { mNPNComplete = true; }
|
||||||
|
void NotifyClose() {
|
||||||
|
mTlsHandshakeComplitionPending = false;
|
||||||
|
mOwner = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~TlsHandshaker();
|
||||||
|
|
||||||
|
void Check0RttEnabled(nsISSLSocketControl* ssl);
|
||||||
|
|
||||||
|
// SPDY related
|
||||||
|
bool mSetupSSLCalled{false};
|
||||||
|
bool mNPNComplete{false};
|
||||||
|
|
||||||
|
bool mTlsHandshakeComplitionPending{false};
|
||||||
|
// Helper variable for 0RTT handshake;
|
||||||
|
// Possible 0RTT has been checked.
|
||||||
|
bool m0RTTChecked{false};
|
||||||
|
// 0RTT data state.
|
||||||
|
enum EarlyData {
|
||||||
|
NOT_AVAILABLE,
|
||||||
|
USED,
|
||||||
|
CANNOT_BE_USED,
|
||||||
|
DONE_NOT_AVAILABLE,
|
||||||
|
DONE_USED,
|
||||||
|
DONE_CANNOT_BE_USED,
|
||||||
|
};
|
||||||
|
EarlyData mEarlyDataState{EarlyData::NOT_AVAILABLE};
|
||||||
|
nsCString mEarlyNegotiatedALPN;
|
||||||
|
RefPtr<nsHttpConnectionInfo> mConnInfo;
|
||||||
|
// nsHttpConnection and TlsHandshaker create a reference cycle. To break this
|
||||||
|
// cycle, NotifyClose() needs to be called in nsHttpConnection::Close().
|
||||||
|
RefPtr<nsHttpConnection> mOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::net
|
||||||
|
|
||||||
|
#endif // TlsHandshaker_h__
|
|
@ -153,6 +153,7 @@ UNIFIED_SOURCES += [
|
||||||
"SocketWrapper.cpp",
|
"SocketWrapper.cpp",
|
||||||
"SpeculativeTransaction.cpp",
|
"SpeculativeTransaction.cpp",
|
||||||
"TLSFilterTransaction.cpp",
|
"TLSFilterTransaction.cpp",
|
||||||
|
"TlsHandshaker.cpp",
|
||||||
"TRRServiceChannel.cpp",
|
"TRRServiceChannel.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
#undef LOG_ENABLED
|
#undef LOG_ENABLED
|
||||||
#define LOG_ENABLED() LOG5_ENABLED()
|
#define LOG_ENABLED() LOG5_ENABLED()
|
||||||
|
|
||||||
#define TLS_EARLY_DATA_NOT_AVAILABLE 0
|
|
||||||
#define TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED 1
|
|
||||||
#define TLS_EARLY_DATA_AVAILABLE_AND_USED 2
|
|
||||||
|
|
||||||
#include "ASpdySession.h"
|
#include "ASpdySession.h"
|
||||||
#include "mozilla/ChaosMode.h"
|
#include "mozilla/ChaosMode.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
|
@ -159,6 +155,7 @@ nsresult nsHttpConnection::Init(
|
||||||
mSocketTransport->SetSecurityCallbacks(this);
|
mSocketTransport->SetSecurityCallbacks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTlsHandshaker = new TlsHandshaker(mConnInfo, this);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,144 +368,9 @@ void nsHttpConnection::StartSpdy(nsISSLSocketControl* sslControl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsHttpConnection::Check0RttEnabled(nsISSLSocketControl* ssl) {
|
void nsHttpConnection::PostProcessNPNSetup(bool handshakeSucceeded,
|
||||||
if (m0RTTChecked) {
|
bool hasSecurityInfo,
|
||||||
return;
|
bool earlyDataUsed) {
|
||||||
}
|
|
||||||
|
|
||||||
m0RTTChecked = true;
|
|
||||||
|
|
||||||
if (mConnInfo->UsingProxy()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is no ALPN info (yet!). We need to consider doing 0RTT. We
|
|
||||||
// will do so if there is ALPN information from a previous session
|
|
||||||
// (AlpnEarlySelection), we are using HTTP/1, and the request data can
|
|
||||||
// be safely retried.
|
|
||||||
if (NS_FAILED(ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN))) {
|
|
||||||
LOG1(
|
|
||||||
("nsHttpConnection::Check0RttEnabled %p - "
|
|
||||||
"early selected alpn not available",
|
|
||||||
this));
|
|
||||||
} else {
|
|
||||||
LOG1(
|
|
||||||
("nsHttpConnection::Check0RttEnabled %p -"
|
|
||||||
"early selected alpn: %s",
|
|
||||||
this, mEarlyNegotiatedALPN.get()));
|
|
||||||
const SpdyInformation* info = gHttpHandler->SpdyInfo();
|
|
||||||
if (!mEarlyNegotiatedALPN.Equals(info->VersionString)) {
|
|
||||||
// This is the HTTP/1 case.
|
|
||||||
// Check if early-data is allowed for this transaction.
|
|
||||||
if (mTransaction->Do0RTT()) {
|
|
||||||
LOG(
|
|
||||||
("nsHttpConnection::Check0RttEnabled [this=%p] - We "
|
|
||||||
"can do 0RTT (http/1)!",
|
|
||||||
this));
|
|
||||||
mEarlyDataState = EarlyData::USED;
|
|
||||||
} else {
|
|
||||||
mEarlyDataState = EarlyData::CANNOT_BE_USED;
|
|
||||||
// Poll for read now. Polling for write will cause us to busy wait.
|
|
||||||
// When the handshake ia done the polling flags will be set correctly.
|
|
||||||
Unused << ResumeRecv();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We have h2, we can at least 0-RTT the preamble and opening
|
|
||||||
// SETTINGS, etc, and maybe some of the first request
|
|
||||||
LOG(
|
|
||||||
("nsHttpConnection::Check0RttEnabled [this=%p] - Starting "
|
|
||||||
"0RTT for h2!",
|
|
||||||
this));
|
|
||||||
mEarlyDataState = EarlyData::USED;
|
|
||||||
Start0RTTSpdy(info->Version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsHttpConnection::EarlyDataTelemetry(int16_t tlsVersion,
|
|
||||||
bool earlyDataAccepted) {
|
|
||||||
// Send the 0RTT telemetry only for tls1.3
|
|
||||||
if (tlsVersion > nsISSLSocketControl::TLS_VERSION_1_2) {
|
|
||||||
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_NEGOTIATED,
|
|
||||||
(mEarlyDataState == EarlyData::NOT_AVAILABLE)
|
|
||||||
? TLS_EARLY_DATA_NOT_AVAILABLE
|
|
||||||
: ((mEarlyDataState == EarlyData::USED)
|
|
||||||
? TLS_EARLY_DATA_AVAILABLE_AND_USED
|
|
||||||
: TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED));
|
|
||||||
if (EarlyDataUsed()) {
|
|
||||||
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_ACCEPTED,
|
|
||||||
earlyDataAccepted);
|
|
||||||
}
|
|
||||||
if (earlyDataAccepted) {
|
|
||||||
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_BYTES_WRITTEN,
|
|
||||||
mContentBytesWritten0RTT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if TLS handshake is needed and it is responsible to move it forward.
|
|
||||||
bool nsHttpConnection::EnsureNPNComplete() {
|
|
||||||
MOZ_ASSERT(mSocketTransport);
|
|
||||||
if (!mSocketTransport) {
|
|
||||||
// this cannot happen
|
|
||||||
mNPNComplete = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mNPNComplete) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTlsHandshakeComplitionPending) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
|
||||||
nsCOMPtr<nsISupports> securityInfo;
|
|
||||||
GetSecurityInfo(getter_AddRefs(securityInfo));
|
|
||||||
if (!securityInfo) {
|
|
||||||
FinishNPNSetup(false, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
FinishNPNSetup(false, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m0RTTChecked) {
|
|
||||||
// We reuse m0RTTChecked. We want to send this status only once.
|
|
||||||
mTransaction->OnTransportStatus(mSocketTransport,
|
|
||||||
NS_NET_STATUS_TLS_HANDSHAKE_STARTING, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] drive TLS handshake",
|
|
||||||
this));
|
|
||||||
rv = ssl->DriveHandshake();
|
|
||||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
|
||||||
FinishNPNSetup(false, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Check0RttEnabled(ssl);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsHttpConnection::EarlyDataDone() {
|
|
||||||
if (mEarlyDataState == EarlyData::USED) {
|
|
||||||
mEarlyDataState = EarlyData::DONE_USED;
|
|
||||||
} else if (mEarlyDataState == EarlyData::CANNOT_BE_USED) {
|
|
||||||
mEarlyDataState = EarlyData::DONE_CANNOT_BE_USED;
|
|
||||||
} else if (mEarlyDataState == EarlyData::NOT_AVAILABLE) {
|
|
||||||
mEarlyDataState = EarlyData::DONE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsHttpConnection::FinishNPNSetup(bool handshakeSucceeded,
|
|
||||||
bool hasSecurityInfo) {
|
|
||||||
mNPNComplete = true;
|
|
||||||
|
|
||||||
if (mTransaction) {
|
if (mTransaction) {
|
||||||
mTransaction->OnTransportStatus(mSocketTransport,
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
NS_NET_STATUS_TLS_HANDSHAKE_ENDED, 0);
|
NS_NET_STATUS_TLS_HANDSHAKE_ENDED, 0);
|
||||||
|
@ -529,9 +391,9 @@ void nsHttpConnection::FinishNPNSetup(bool handshakeSucceeded,
|
||||||
mBootstrappedTimings.connectEnd = TimeStamp::Now();
|
mBootstrappedTimings.connectEnd = TimeStamp::Now();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EarlyDataUsed()) {
|
if (earlyDataUsed) {
|
||||||
// Didn't get 0RTT OK, back out of the "attempting 0RTT" state
|
// Didn't get 0RTT OK, back out of the "attempting 0RTT" state
|
||||||
LOG(("nsHttpConnection::FinishNPNSetup [this=%p] 0rtt failed", this));
|
LOG(("nsHttpConnection::PostProcessNPNSetup [this=%p] 0rtt failed", this));
|
||||||
if (mTransaction && NS_FAILED(mTransaction->Finish0RTT(true, true))) {
|
if (mTransaction && NS_FAILED(mTransaction->Finish0RTT(true, true))) {
|
||||||
mTransaction->Close(NS_ERROR_NET_RESET);
|
mTransaction->Close(NS_ERROR_NET_RESET);
|
||||||
}
|
}
|
||||||
|
@ -541,8 +403,6 @@ void nsHttpConnection::FinishNPNSetup(bool handshakeSucceeded,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EarlyDataDone();
|
|
||||||
|
|
||||||
if (hasSecurityInfo) {
|
if (hasSecurityInfo) {
|
||||||
// Telemetry for tls failure rate with and without esni;
|
// Telemetry for tls failure rate with and without esni;
|
||||||
bool echConfigUsed = false;
|
bool echConfigUsed = false;
|
||||||
|
@ -585,7 +445,7 @@ nsresult nsHttpConnection::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
||||||
caps));
|
caps));
|
||||||
|
|
||||||
if (!mExperienced && !trans->IsNullTransaction()) {
|
if (!mExperienced && !trans->IsNullTransaction()) {
|
||||||
if (mNPNComplete) {
|
if (mTlsHandshaker->NPNComplete()) {
|
||||||
mExperienced = true;
|
mExperienced = true;
|
||||||
}
|
}
|
||||||
if (mBootstrappedTimingsSet) {
|
if (mBootstrappedTimingsSet) {
|
||||||
|
@ -647,7 +507,7 @@ nsresult nsHttpConnection::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
||||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||||
trans->GetSecurityCallbacks(getter_AddRefs(callbacks));
|
trans->GetSecurityCallbacks(getter_AddRefs(callbacks));
|
||||||
SetSecurityCallbacks(callbacks);
|
SetSecurityCallbacks(callbacks);
|
||||||
SetupSSL();
|
mTlsHandshaker->SetupSSL(mInSpdyTunnel, mForcePlainText);
|
||||||
|
|
||||||
// take ownership of the transaction
|
// take ownership of the transaction
|
||||||
mTransaction = trans;
|
mTransaction = trans;
|
||||||
|
@ -714,76 +574,6 @@ failed_activation:
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsHttpConnection::SetupSSL() {
|
|
||||||
LOG1(("nsHttpConnection::SetupSSL %p caps=0x%X %s\n", this, mTransactionCaps,
|
|
||||||
mConnInfo->HashKey().get()));
|
|
||||||
|
|
||||||
if (mSetupSSLCalled) { // do only once
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mSetupSSLCalled = true;
|
|
||||||
|
|
||||||
if (mNPNComplete) return;
|
|
||||||
|
|
||||||
// we flip this back to false if SetNPNList succeeds at the end
|
|
||||||
// of this function
|
|
||||||
mNPNComplete = true;
|
|
||||||
|
|
||||||
if (!mConnInfo->FirstHopSSL() || mForcePlainText) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we are connected to the proxy with TLS, start the TLS
|
|
||||||
// flow immediately without waiting for a CONNECT sequence.
|
|
||||||
DebugOnly<nsresult> rv{};
|
|
||||||
if (mInSpdyTunnel) {
|
|
||||||
rv = InitSSLParams(false, true);
|
|
||||||
} else {
|
|
||||||
bool usingHttpsProxy = mConnInfo->UsingHttpsProxy();
|
|
||||||
rv = InitSSLParams(usingHttpsProxy, usingHttpsProxy);
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
// The naming of NPN is historical - this function creates the basic
|
|
||||||
// offer list for both NPN and ALPN. ALPN validation callbacks are made
|
|
||||||
// now before the handshake is complete, and NPN validation callbacks
|
|
||||||
// are made during the handshake.
|
|
||||||
nsresult nsHttpConnection::SetupNPNList(nsISSLSocketControl* ssl,
|
|
||||||
uint32_t caps) {
|
|
||||||
nsTArray<nsCString> protocolArray;
|
|
||||||
|
|
||||||
nsCString npnToken = mConnInfo->GetNPNToken();
|
|
||||||
if (npnToken.IsEmpty()) {
|
|
||||||
// The first protocol is used as the fallback if none of the
|
|
||||||
// protocols supported overlap with the server's list.
|
|
||||||
// When using ALPN the advertised preferences are protocolArray indicies
|
|
||||||
// {1, .., N, 0} in decreasing order.
|
|
||||||
// For NPN, In the case of overlap, matching priority is driven by
|
|
||||||
// the order of the server's advertisement - with index 0 used when
|
|
||||||
// there is no match.
|
|
||||||
protocolArray.AppendElement("http/1.1"_ns);
|
|
||||||
|
|
||||||
if (StaticPrefs::network_http_http2_enabled() &&
|
|
||||||
!(caps & NS_HTTP_DISALLOW_SPDY)) {
|
|
||||||
LOG(("nsHttpConnection::SetupSSL Allow SPDY NPN selection"));
|
|
||||||
const SpdyInformation* info = gHttpHandler->SpdyInfo();
|
|
||||||
if (info->ALPNCallbacks(ssl)) {
|
|
||||||
protocolArray.AppendElement(info->VersionString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(("nsHttpConnection::SetupSSL limiting NPN selection to %s",
|
|
||||||
npnToken.get()));
|
|
||||||
protocolArray.AppendElement(npnToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = ssl->SetNPNList(protocolArray);
|
|
||||||
LOG(("nsHttpConnection::SetupNPNList %p %" PRIx32 "\n", this,
|
|
||||||
static_cast<uint32_t>(rv)));
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult nsHttpConnection::AddTransaction(nsAHttpTransaction* httpTransaction,
|
nsresult nsHttpConnection::AddTransaction(nsAHttpTransaction* httpTransaction,
|
||||||
int32_t priority) {
|
int32_t priority) {
|
||||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
@ -835,10 +625,8 @@ void nsHttpConnection::Close(nsresult reason, bool aIsShutdown) {
|
||||||
LOG(("nsHttpConnection::Close [this=%p reason=%" PRIx32 "]\n", this,
|
LOG(("nsHttpConnection::Close [this=%p reason=%" PRIx32 "]\n", this,
|
||||||
static_cast<uint32_t>(reason)));
|
static_cast<uint32_t>(reason)));
|
||||||
|
|
||||||
mClosed = true;
|
|
||||||
|
|
||||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
mTlsHandshakeComplitionPending = false;
|
mTlsHandshaker->NotifyClose();
|
||||||
mContinueHandshakeDone = nullptr;
|
mContinueHandshakeDone = nullptr;
|
||||||
// Ensure TCP keepalive timer is stopped.
|
// Ensure TCP keepalive timer is stopped.
|
||||||
if (mTCPKeepaliveTransitionTimer) {
|
if (mTCPKeepaliveTransitionTimer) {
|
||||||
|
@ -880,7 +668,7 @@ void nsHttpConnection::Close(nsresult reason, bool aIsShutdown) {
|
||||||
mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
|
mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
|
||||||
gHttpHandler->ClearHostMapping(mConnInfo);
|
gHttpHandler->ClearHostMapping(mConnInfo);
|
||||||
}
|
}
|
||||||
if (EarlyDataWasAvailable() &&
|
if (mTlsHandshaker->EarlyDataWasAvailable() &&
|
||||||
(reason ==
|
(reason ==
|
||||||
psm::GetXPCOMFromNSSError(SSL_ERROR_PROTOCOL_VERSION_ALERT))) {
|
psm::GetXPCOMFromNSSError(SSL_ERROR_PROTOCOL_VERSION_ALERT))) {
|
||||||
gHttpHandler->Exclude0RttTcp(mConnInfo);
|
gHttpHandler->Exclude0RttTcp(mConnInfo);
|
||||||
|
@ -914,46 +702,6 @@ void nsHttpConnection::Close(nsresult reason, bool aIsShutdown) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// called on the socket thread
|
|
||||||
nsresult nsHttpConnection::InitSSLParams(bool connectingToProxy,
|
|
||||||
bool proxyStartSSL) {
|
|
||||||
LOG(("nsHttpConnection::InitSSLParams [this=%p] connectingToProxy=%d\n", this,
|
|
||||||
connectingToProxy));
|
|
||||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
|
||||||
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsISupports> securityInfo;
|
|
||||||
GetSecurityInfo(getter_AddRefs(securityInfo));
|
|
||||||
if (!securityInfo) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If proxy is use or 0RTT is excluded for a origin, don't use early-data.
|
|
||||||
if (mConnInfo->UsingProxy() || gHttpHandler->Is0RttTcpExcluded(mConnInfo)) {
|
|
||||||
ssl->DisableEarlyData();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxyStartSSL) {
|
|
||||||
rv = ssl->ProxyStartSSL();
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(SetupNPNList(ssl, mTransactionCaps)) &&
|
|
||||||
NS_SUCCEEDED(ssl->SetHandshakeCallbackListener(this))) {
|
|
||||||
LOG(("InitSSLParams Setting up SPDY Negotiation OK"));
|
|
||||||
mNPNComplete = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsHttpConnection::DontReuse() {
|
void nsHttpConnection::DontReuse() {
|
||||||
LOG(("nsHttpConnection::DontReuse %p spdysession=%p\n", this,
|
LOG(("nsHttpConnection::DontReuse %p spdysession=%p\n", this,
|
||||||
mSpdySession.get()));
|
mSpdySession.get()));
|
||||||
|
@ -1060,7 +808,7 @@ bool nsHttpConnection::IsAlive() {
|
||||||
|
|
||||||
// SocketTransport::IsAlive can run the SSL state machine, so make sure
|
// SocketTransport::IsAlive can run the SSL state machine, so make sure
|
||||||
// the NPN options are set before that happens.
|
// the NPN options are set before that happens.
|
||||||
SetupSSL();
|
mTlsHandshaker->SetupSSL(mInSpdyTunnel, mForcePlainText);
|
||||||
|
|
||||||
bool alive;
|
bool alive;
|
||||||
nsresult rv = mSocketTransport->IsAlive(&alive);
|
nsresult rv = mSocketTransport->IsAlive(&alive);
|
||||||
|
@ -1244,7 +992,7 @@ void nsHttpConnection::HandleTunnelResponse(uint16_t responseStatus,
|
||||||
SetupSecondaryTLS();
|
SetupSecondaryTLS();
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = InitSSLParams(false, true);
|
rv = mTlsHandshaker->InitSSLParams(false, true);
|
||||||
LOG(("InitSSLParams [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
|
LOG(("InitSSLParams [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
|
||||||
} else {
|
} else {
|
||||||
// We have an https protocol but the CONNECT only flag was
|
// We have an https protocol but the CONNECT only flag was
|
||||||
|
@ -1252,7 +1000,7 @@ void nsHttpConnection::HandleTunnelResponse(uint16_t responseStatus,
|
||||||
// proxy. We have to mark this as complete to finish the
|
// proxy. We have to mark this as complete to finish the
|
||||||
// transaction and be upgraded. OnSocketReadable() uses this
|
// transaction and be upgraded. OnSocketReadable() uses this
|
||||||
// to detect an inactive tunnel and blocks completion.
|
// to detect an inactive tunnel and blocks completion.
|
||||||
mNPNComplete = true;
|
mTlsHandshaker->SetNPNComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
|
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
|
||||||
|
@ -1401,7 +1149,7 @@ uint32_t nsHttpConnection::ReadTimeoutTick(PRIntervalTime now) {
|
||||||
nextTickAfter = std::max(nextTickAfter, 1U);
|
nextTickAfter = std::max(nextTickAfter, 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mNPNComplete) {
|
if (!mTlsHandshaker->NPNComplete()) {
|
||||||
// We can reuse mLastWriteTime here, because it is set when the
|
// We can reuse mLastWriteTime here, because it is set when the
|
||||||
// connection is activated and only change when a transaction
|
// connection is activated and only change when a transaction
|
||||||
// succesfullu write to the socket and this can only happen after
|
// succesfullu write to the socket and this can only happen after
|
||||||
|
@ -1701,7 +1449,7 @@ void nsHttpConnection::CloseTransaction(nsAHttpTransaction* trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsHttpConnection::CheckCanWrite0RTTData() {
|
bool nsHttpConnection::CheckCanWrite0RTTData() {
|
||||||
MOZ_ASSERT(EarlyDataAvailable());
|
MOZ_ASSERT(mTlsHandshaker->EarlyDataAvailable());
|
||||||
nsCOMPtr<nsISupports> securityInfo;
|
nsCOMPtr<nsISupports> securityInfo;
|
||||||
GetSecurityInfo(getter_AddRefs(securityInfo));
|
GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||||
if (!securityInfo) {
|
if (!securityInfo) {
|
||||||
|
@ -1746,8 +1494,8 @@ nsresult nsHttpConnection::OnReadSegment(const char* buf, uint32_t count,
|
||||||
// handshake already.
|
// handshake already.
|
||||||
// IsAlive() calls drive the handshake and that may cause nss and necko
|
// IsAlive() calls drive the handshake and that may cause nss and necko
|
||||||
// to be out of sync.
|
// to be out of sync.
|
||||||
if (EarlyDataAvailable() && !CheckCanWrite0RTTData()) {
|
if (mTlsHandshaker->EarlyDataAvailable() && !CheckCanWrite0RTTData()) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mTlsHandshakeComplitionPending);
|
MOZ_DIAGNOSTIC_ASSERT(mTlsHandshaker->TlsHandshakeComplitionPending());
|
||||||
LOG(
|
LOG(
|
||||||
("nsHttpConnection::OnReadSegment Do not write any data, wait"
|
("nsHttpConnection::OnReadSegment Do not write any data, wait"
|
||||||
" for EnsureNPNComplete to be called [this=%p]",
|
" for EnsureNPNComplete to be called [this=%p]",
|
||||||
|
@ -1810,8 +1558,9 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
||||||
|
|
||||||
switch (mState) {
|
switch (mState) {
|
||||||
case HttpConnectionState::SETTING_UP_TUNNEL:
|
case HttpConnectionState::SETTING_UP_TUNNEL:
|
||||||
if (mConnInfo->UsingHttpsProxy() && !EnsureNPNComplete()) {
|
if (mConnInfo->UsingHttpsProxy() &&
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!EarlyDataAvailable());
|
!mTlsHandshaker->EnsureNPNComplete()) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!mTlsHandshaker->EarlyDataAvailable());
|
||||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
} else {
|
} else {
|
||||||
rv = SendConnectRequest(this, &transactionBytes);
|
rv = SendConnectRequest(this, &transactionBytes);
|
||||||
|
@ -1822,8 +1571,9 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
||||||
// transaction->readsegments() processing can proceed because we need to
|
// transaction->readsegments() processing can proceed because we need to
|
||||||
// know how to format the request differently for http/1, http/2, spdy,
|
// know how to format the request differently for http/1, http/2, spdy,
|
||||||
// etc.. and that is negotiated with NPN/ALPN in the SSL handshake.
|
// etc.. and that is negotiated with NPN/ALPN in the SSL handshake.
|
||||||
if (!EnsureNPNComplete() &&
|
if (!mTlsHandshaker->EnsureNPNComplete() &&
|
||||||
(!EarlyDataUsed() || mTlsHandshakeComplitionPending)) {
|
(!mTlsHandshaker->EarlyDataUsed() ||
|
||||||
|
mTlsHandshaker->TlsHandshakeComplitionPending())) {
|
||||||
// The handshake is not done and we cannot write 0RTT data or nss has
|
// The handshake is not done and we cannot write 0RTT data or nss has
|
||||||
// already finished 0RTT data.
|
// already finished 0RTT data.
|
||||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
@ -1832,7 +1582,7 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
||||||
LOG((" No Transaction In OnSocketWritable\n"));
|
LOG((" No Transaction In OnSocketWritable\n"));
|
||||||
} else if (NS_SUCCEEDED(rv)) {
|
} else if (NS_SUCCEEDED(rv)) {
|
||||||
// for non spdy sessions let the connection manager know
|
// for non spdy sessions let the connection manager know
|
||||||
if (!mReportedSpdy && mNPNComplete) {
|
if (!mReportedSpdy && mTlsHandshaker->NPNComplete()) {
|
||||||
mReportedSpdy = true;
|
mReportedSpdy = true;
|
||||||
MOZ_ASSERT(!mEverUsedSpdy);
|
MOZ_ASSERT(!mEverUsedSpdy);
|
||||||
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, false);
|
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, false);
|
||||||
|
@ -1842,12 +1592,12 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
||||||
rv = mTransaction->ReadSegmentsAgain(this,
|
rv = mTransaction->ReadSegmentsAgain(this,
|
||||||
nsIOService::gDefaultSegmentSize,
|
nsIOService::gDefaultSegmentSize,
|
||||||
&transactionBytes, &again);
|
&transactionBytes, &again);
|
||||||
if (EarlyDataUsed()) {
|
if (mTlsHandshaker->EarlyDataUsed()) {
|
||||||
mContentBytesWritten0RTT += transactionBytes;
|
mContentBytesWritten0RTT += transactionBytes;
|
||||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||||
// If an error happens while writting 0RTT data, restart
|
// If an error happens while writting 0RTT data, restart
|
||||||
// the transactiions without 0RTT.
|
// the transactiions without 0RTT.
|
||||||
FinishNPNSetup(false, true);
|
mTlsHandshaker->FinishNPNSetup(false, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mContentBytesWritten += transactionBytes;
|
mContentBytesWritten += transactionBytes;
|
||||||
|
@ -1881,7 +1631,7 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
||||||
if (mTLSFilter) {
|
if (mTLSFilter) {
|
||||||
LOG((" blocked tunnel (handshake?)\n"));
|
LOG((" blocked tunnel (handshake?)\n"));
|
||||||
rv = mTLSFilter->NudgeTunnel(this);
|
rv = mTLSFilter->NudgeTunnel(this);
|
||||||
} else if (mEarlyDataState != EarlyData::CANNOT_BE_USED) {
|
} else if (!mTlsHandshaker->EarlyDataCanNotBeUsed()) {
|
||||||
// continue writing
|
// continue writing
|
||||||
// We are not going to poll for write if the handshake is in progress,
|
// We are not going to poll for write if the handshake is in progress,
|
||||||
// but early data cannot be used.
|
// but early data cannot be used.
|
||||||
|
@ -1981,7 +1731,7 @@ nsresult nsHttpConnection::OnSocketReadable() {
|
||||||
bool again = true;
|
bool again = true;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!TunnelSetupInProgress() && !EnsureNPNComplete()) {
|
if (!TunnelSetupInProgress() && !mTlsHandshaker->EnsureNPNComplete()) {
|
||||||
// Unless we are setting up a tunnel via CONNECT, prevent reading
|
// Unless we are setting up a tunnel via CONNECT, prevent reading
|
||||||
// from the socket until the results of NPN
|
// from the socket until the results of NPN
|
||||||
// negotiation are known (which is determined from the write path).
|
// negotiation are known (which is determined from the write path).
|
||||||
|
@ -1993,7 +1743,7 @@ nsresult nsHttpConnection::OnSocketReadable() {
|
||||||
("nsHttpConnection::OnSocketReadable %p return due to inactive "
|
("nsHttpConnection::OnSocketReadable %p return due to inactive "
|
||||||
"tunnel setup but incomplete NPN state\n",
|
"tunnel setup but incomplete NPN state\n",
|
||||||
this));
|
this));
|
||||||
if (EarlyDataAvailable()) {
|
if (mTlsHandshaker->EarlyDataAvailable()) {
|
||||||
rv = ResumeRecv();
|
rv = ResumeRecv();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2299,7 +2049,6 @@ NS_INTERFACE_MAP_BEGIN(nsHttpConnection)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
|
NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsITlsHandshakeCallbackListener)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(HttpConnectionBase)
|
NS_INTERFACE_MAP_ENTRY(HttpConnectionBase)
|
||||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(nsHttpConnection)
|
NS_INTERFACE_MAP_ENTRY_CONCRETE(nsHttpConnection)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
@ -2529,27 +2278,9 @@ bool nsHttpConnection::GetEchConfigUsed() {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsHttpConnection::HandshakeDone() {
|
|
||||||
if (!mClosed) {
|
|
||||||
mTlsHandshakeComplitionPending = true;
|
|
||||||
|
|
||||||
// HandshakeDone needs to be dispatched so that it is not called inside
|
|
||||||
// nss locks.
|
|
||||||
RefPtr<nsHttpConnection> self(this);
|
|
||||||
NS_DispatchToCurrentThread(NS_NewRunnableFunction(
|
|
||||||
"nsHttpConnection::HandshakeDoneInternal", [self{std::move(self)}]() {
|
|
||||||
if (self->mTlsHandshakeComplitionPending && !self->mClosed) {
|
|
||||||
self->HandshakeDoneInternal();
|
|
||||||
self->mTlsHandshakeComplitionPending = false;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsHttpConnection::HandshakeDoneInternal() {
|
void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
if (mNPNComplete) {
|
LOG(("nsHttpConnection::HandshakeDoneInternal [this=%p]\n", this));
|
||||||
|
if (mTlsHandshaker->NPNComplete()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
@ -2560,19 +2291,19 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
|
|
||||||
GetSecurityInfo(getter_AddRefs(securityInfo));
|
GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||||
if (!securityInfo) {
|
if (!securityInfo) {
|
||||||
FinishNPNSetup(false, false);
|
mTlsHandshaker->FinishNPNSetup(false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssl = do_QueryInterface(securityInfo, &rv);
|
ssl = do_QueryInterface(securityInfo, &rv);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
FinishNPNSetup(false, false);
|
mTlsHandshaker->FinishNPNSetup(false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info = do_QueryInterface(securityInfo, &rv);
|
info = do_QueryInterface(securityInfo, &rv);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
FinishNPNSetup(false, false);
|
mTlsHandshaker->FinishNPNSetup(false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2580,7 +2311,7 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rvDebug));
|
MOZ_ASSERT(NS_SUCCEEDED(rvDebug));
|
||||||
|
|
||||||
bool earlyDataAccepted = false;
|
bool earlyDataAccepted = false;
|
||||||
if (EarlyDataUsed()) {
|
if (mTlsHandshaker->EarlyDataUsed()) {
|
||||||
// Check if early data has been accepted.
|
// Check if early data has been accepted.
|
||||||
nsresult rvEarlyData = ssl->GetEarlyDataAccepted(&earlyDataAccepted);
|
nsresult rvEarlyData = ssl->GetEarlyDataAccepted(&earlyDataAccepted);
|
||||||
LOG(
|
LOG(
|
||||||
|
@ -2592,7 +2323,8 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
if (NS_FAILED(rvEarlyData) ||
|
if (NS_FAILED(rvEarlyData) ||
|
||||||
(mTransaction &&
|
(mTransaction &&
|
||||||
NS_FAILED(mTransaction->Finish0RTT(
|
NS_FAILED(mTransaction->Finish0RTT(
|
||||||
!earlyDataAccepted, negotiatedNPN != mEarlyNegotiatedALPN)))) {
|
!earlyDataAccepted,
|
||||||
|
negotiatedNPN != mTlsHandshaker->EarlyNegotiatedALPN())))) {
|
||||||
LOG(
|
LOG(
|
||||||
("nsHttpConection::HandshakeDone [this=%p] closing transaction "
|
("nsHttpConection::HandshakeDone [this=%p] closing transaction "
|
||||||
"%p",
|
"%p",
|
||||||
|
@ -2600,15 +2332,16 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
if (mTransaction) {
|
if (mTransaction) {
|
||||||
mTransaction->Close(NS_ERROR_NET_RESET);
|
mTransaction->Close(NS_ERROR_NET_RESET);
|
||||||
}
|
}
|
||||||
FinishNPNSetup(false, true);
|
mTlsHandshaker->FinishNPNSetup(false, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mDid0RTTSpdy && (negotiatedNPN != mEarlyNegotiatedALPN)) {
|
if (mDid0RTTSpdy &&
|
||||||
|
(negotiatedNPN != mTlsHandshaker->EarlyNegotiatedALPN())) {
|
||||||
Reset0RttForSpdy();
|
Reset0RttForSpdy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EarlyDataAvailable() && !earlyDataAccepted) {
|
if (mTlsHandshaker->EarlyDataAvailable() && !earlyDataAccepted) {
|
||||||
// When the early-data were used but not accepted, we need to start
|
// When the early-data were used but not accepted, we need to start
|
||||||
// from the begining here and start writing the request again.
|
// from the begining here and start writing the request again.
|
||||||
// The same is true if 0RTT was available but not used.
|
// The same is true if 0RTT was available but not used.
|
||||||
|
@ -2624,8 +2357,9 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
(tlsVersion < nsISSLSocketControl::TLS_VERSION_1_3) &&
|
(tlsVersion < nsISSLSocketControl::TLS_VERSION_1_3) &&
|
||||||
(tlsVersion != nsISSLSocketControl::SSL_VERSION_UNKNOWN));
|
(tlsVersion != nsISSLSocketControl::SSL_VERSION_UNKNOWN));
|
||||||
|
|
||||||
EarlyDataTelemetry(tlsVersion, earlyDataAccepted);
|
mTlsHandshaker->EarlyDataTelemetry(tlsVersion, earlyDataAccepted,
|
||||||
EarlyDataDone();
|
mContentBytesWritten0RTT);
|
||||||
|
mTlsHandshaker->EarlyDataDone();
|
||||||
|
|
||||||
if (!earlyDataAccepted) {
|
if (!earlyDataAccepted) {
|
||||||
LOG(
|
LOG(
|
||||||
|
@ -2648,7 +2382,7 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
LOG(("nsHttpConnection do mContinueHandshakeDone [this=%p]",
|
LOG(("nsHttpConnection do mContinueHandshakeDone [this=%p]",
|
||||||
self.get()));
|
self.get()));
|
||||||
self->StartSpdy(ssl, info);
|
self->StartSpdy(ssl, info);
|
||||||
self->FinishNPNSetup(true, true);
|
self->mTlsHandshaker->FinishNPNSetup(true, true);
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2672,7 +2406,7 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
||||||
|
|
||||||
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
|
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
|
||||||
|
|
||||||
FinishNPNSetup(true, true);
|
mTlsHandshaker->FinishNPNSetup(true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "ARefBase.h"
|
#include "ARefBase.h"
|
||||||
#include "TimingStruct.h"
|
#include "TimingStruct.h"
|
||||||
#include "HttpTrafficAnalyzer.h"
|
#include "HttpTrafficAnalyzer.h"
|
||||||
|
#include "TlsHandshaker.h"
|
||||||
|
|
||||||
#include "nsIAsyncInputStream.h"
|
#include "nsIAsyncInputStream.h"
|
||||||
#include "nsIAsyncOutputStream.h"
|
#include "nsIAsyncOutputStream.h"
|
||||||
|
@ -58,7 +59,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
public nsIOutputStreamCallback,
|
public nsIOutputStreamCallback,
|
||||||
public nsITransportEventSink,
|
public nsITransportEventSink,
|
||||||
public nsIInterfaceRequestor,
|
public nsIInterfaceRequestor,
|
||||||
public nsITlsHandshakeCallbackListener,
|
|
||||||
public NudgeTunnelCallback {
|
public NudgeTunnelCallback {
|
||||||
private:
|
private:
|
||||||
virtual ~nsHttpConnection();
|
virtual ~nsHttpConnection();
|
||||||
|
@ -73,7 +73,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
NS_DECL_NSIOUTPUTSTREAMCALLBACK
|
NS_DECL_NSIOUTPUTSTREAMCALLBACK
|
||||||
NS_DECL_NSITRANSPORTEVENTSINK
|
NS_DECL_NSITRANSPORTEVENTSINK
|
||||||
NS_DECL_NSIINTERFACEREQUESTOR
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
NS_DECL_NSITLSHANDSHAKECALLBACKLISTENER
|
|
||||||
NS_DECL_NUDGETUNNELCALLBACK
|
NS_DECL_NUDGETUNNELCALLBACK
|
||||||
|
|
||||||
nsHttpConnection();
|
nsHttpConnection();
|
||||||
|
@ -123,6 +122,7 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
HttpVersion GetLastHttpResponseVersion() { return mLastHttpResponseVersion; }
|
HttpVersion GetLastHttpResponseVersion() { return mLastHttpResponseVersion; }
|
||||||
|
|
||||||
friend class HttpConnectionForceIO;
|
friend class HttpConnectionForceIO;
|
||||||
|
friend class TlsHandshaker;
|
||||||
|
|
||||||
// When a persistent connection is in the connection manager idle
|
// When a persistent connection is in the connection manager idle
|
||||||
// connection pool, the nsHttpConnection still reads errors and hangups
|
// connection pool, the nsHttpConnection still reads errors and hangups
|
||||||
|
@ -226,11 +226,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
kTCPKeepaliveLongLivedConfig
|
kTCPKeepaliveLongLivedConfig
|
||||||
};
|
};
|
||||||
|
|
||||||
// called to cause the underlying socket to start speaking SSL
|
|
||||||
[[nodiscard]] nsresult InitSSLParams(bool connectingToProxy,
|
|
||||||
bool ProxyStartSSL);
|
|
||||||
[[nodiscard]] nsresult SetupNPNList(nsISSLSocketControl* ssl, uint32_t caps);
|
|
||||||
|
|
||||||
[[nodiscard]] nsresult OnTransactionDone(nsresult reason);
|
[[nodiscard]] nsresult OnTransactionDone(nsresult reason);
|
||||||
[[nodiscard]] nsresult OnSocketWritable();
|
[[nodiscard]] nsresult OnSocketWritable();
|
||||||
[[nodiscard]] nsresult OnSocketReadable();
|
[[nodiscard]] nsresult OnSocketReadable();
|
||||||
|
@ -238,12 +233,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
PRIntervalTime IdleTime();
|
PRIntervalTime IdleTime();
|
||||||
bool IsAlive();
|
bool IsAlive();
|
||||||
|
|
||||||
// Makes certain the SSL handshake is complete and NPN negotiation
|
|
||||||
// has had a chance to happen
|
|
||||||
[[nodiscard]] bool EnsureNPNComplete();
|
|
||||||
|
|
||||||
void SetupSSL();
|
|
||||||
|
|
||||||
// Start the Spdy transaction handler when NPN indicates spdy/*
|
// Start the Spdy transaction handler when NPN indicates spdy/*
|
||||||
void StartSpdy(nsISSLSocketControl* ssl, SpdyVersion spdyVersion);
|
void StartSpdy(nsISSLSocketControl* ssl, SpdyVersion spdyVersion);
|
||||||
// Like the above, but do the bare minimum to do 0RTT data, so we can back
|
// Like the above, but do the bare minimum to do 0RTT data, so we can back
|
||||||
|
@ -265,17 +254,19 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
[[nodiscard]] nsresult DisableTCPKeepalives();
|
[[nodiscard]] nsresult DisableTCPKeepalives();
|
||||||
|
|
||||||
bool CheckCanWrite0RTTData();
|
bool CheckCanWrite0RTTData();
|
||||||
void Check0RttEnabled(nsISSLSocketControl* ssl);
|
void PostProcessNPNSetup(bool handshakeSucceeded, bool hasSecurityInfo,
|
||||||
void EarlyDataTelemetry(int16_t tlsVersion, bool earlyDataAccepted);
|
bool earlyDataUsed);
|
||||||
void FinishNPNSetup(bool handshakeSucceeded, bool hasSecurityInfo);
|
|
||||||
void Reset0RttForSpdy();
|
void Reset0RttForSpdy();
|
||||||
void HandshakeDoneInternal();
|
void HandshakeDoneInternal();
|
||||||
|
uint32_t TransactionCaps() const { return mTransactionCaps; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// mTransaction only points to the HTTP Transaction callbacks if the
|
// mTransaction only points to the HTTP Transaction callbacks if the
|
||||||
// transaction is open, otherwise it is null.
|
// transaction is open, otherwise it is null.
|
||||||
RefPtr<nsAHttpTransaction> mTransaction;
|
RefPtr<nsAHttpTransaction> mTransaction;
|
||||||
|
|
||||||
|
RefPtr<TlsHandshaker> mTlsHandshaker;
|
||||||
|
|
||||||
nsCOMPtr<nsIAsyncInputStream> mSocketIn;
|
nsCOMPtr<nsIAsyncInputStream> mSocketIn;
|
||||||
nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
|
nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
|
||||||
|
|
||||||
|
@ -330,10 +321,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
// on this persistent connection.
|
// on this persistent connection.
|
||||||
uint32_t mRemainingConnectionUses{0xffffffff};
|
uint32_t mRemainingConnectionUses{0xffffffff};
|
||||||
|
|
||||||
// SPDY related
|
|
||||||
bool mNPNComplete{false};
|
|
||||||
bool mSetupSSLCalled{false};
|
|
||||||
|
|
||||||
// version level in use, 0 if unused
|
// version level in use, 0 if unused
|
||||||
SpdyVersion mUsingSpdyVersion{SpdyVersion::NONE};
|
SpdyVersion mUsingSpdyVersion{SpdyVersion::NONE};
|
||||||
|
|
||||||
|
@ -364,34 +351,8 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
bool mForceSendPending{false};
|
bool mForceSendPending{false};
|
||||||
nsCOMPtr<nsITimer> mForceSendTimer;
|
nsCOMPtr<nsITimer> mForceSendTimer;
|
||||||
|
|
||||||
// Helper variable for 0RTT handshake;
|
|
||||||
// Possible 0RTT has been checked.
|
|
||||||
bool m0RTTChecked{false};
|
|
||||||
// 0RTT data state.
|
|
||||||
enum EarlyData {
|
|
||||||
NOT_AVAILABLE,
|
|
||||||
USED,
|
|
||||||
CANNOT_BE_USED,
|
|
||||||
DONE_NOT_AVAILABLE,
|
|
||||||
DONE_USED,
|
|
||||||
DONE_CANNOT_BE_USED,
|
|
||||||
};
|
|
||||||
EarlyData mEarlyDataState{EarlyData::NOT_AVAILABLE};
|
|
||||||
bool EarlyDataAvailable() const {
|
|
||||||
return mEarlyDataState == EarlyData::USED ||
|
|
||||||
mEarlyDataState == EarlyData::CANNOT_BE_USED;
|
|
||||||
}
|
|
||||||
bool EarlyDataWasAvailable() const {
|
|
||||||
return mEarlyDataState != EarlyData::NOT_AVAILABLE &&
|
|
||||||
mEarlyDataState != EarlyData::DONE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
bool EarlyDataUsed() const { return mEarlyDataState == EarlyData::USED; }
|
|
||||||
void EarlyDataDone();
|
|
||||||
|
|
||||||
int64_t mContentBytesWritten0RTT{0};
|
int64_t mContentBytesWritten0RTT{0};
|
||||||
nsCString mEarlyNegotiatedALPN;
|
|
||||||
bool mDid0RTTSpdy{false};
|
bool mDid0RTTSpdy{false};
|
||||||
bool mTlsHandshakeComplitionPending{false};
|
|
||||||
|
|
||||||
nsresult mErrorBeforeConnect = NS_OK;
|
nsresult mErrorBeforeConnect = NS_OK;
|
||||||
|
|
||||||
|
@ -406,8 +367,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
||||||
int64_t mTotalBytesWritten = 0; // does not include CONNECT tunnel
|
int64_t mTotalBytesWritten = 0; // does not include CONNECT tunnel
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> mProxyConnectStream;
|
nsCOMPtr<nsIInputStream> mProxyConnectStream;
|
||||||
|
|
||||||
bool mClosed{false};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID)
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче