Bug 1382886 - Refactor EnsureNPNComplete r=necko-reviewers,kershaw

Extract Check0RttEnabled
The old code checks 0RTT state then does a DriveHandshake then checks 0RTT again. This is done in this way because before DriveHandshake is called for the first time 0RTT states are not set.  DriveHandshake is sometimes called as a side effect by IsAlive() check. The new code makes this less complex and just calls DriveHandshaek before checking 0RTT.
Extract code for setting 0RTT telemetry values.
Remove some code that set timing because the same code is called a bit later again.

Differential Revision: https://phabricator.services.mozilla.com/D123645
This commit is contained in:
Dragana Damjanovic 2021-09-17 13:19:00 +00:00
Родитель 8fb130c146
Коммит e5fd2cf6d3
2 изменённых файлов: 85 добавлений и 94 удалений

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

@ -363,6 +363,79 @@ void nsHttpConnection::StartSpdy(nsISSLSocketControl* sslControl,
}
}
void nsHttpConnection::Check0RttEnabled(nsISSLSocketControl* ssl) {
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(
("nsHttpConnection::Check0RttEnabled %p - "
"early selected alpn not available",
this));
mEarlyDataNegotiated = false;
} else {
LOG1(
("nsHttpConnection::Check0RttEnabled %p -"
"early selected alpn: %s",
this, mEarlyNegotiatedALPN.get()));
uint32_t infoIndex;
const SpdyInformation* info = gHttpHandler->SpdyInfo();
if (NS_FAILED(info->GetNPNIndex(mEarlyNegotiatedALPN, &infoIndex))) {
// 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));
mWaitingFor0RTTResponse = true;
}
} 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));
mWaitingFor0RTTResponse = true;
Start0RTTSpdy(info->Version[infoIndex]);
}
mEarlyDataNegotiated = true;
}
}
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,
(!mEarlyDataNegotiated)
? TLS_EARLY_DATA_NOT_AVAILABLE
: ((mWaitingFor0RTTResponse)
? TLS_EARLY_DATA_AVAILABLE_AND_USED
: TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED));
if (mWaitingFor0RTTResponse) {
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_ACCEPTED,
earlyDataAccepted);
}
if (earlyDataAccepted) {
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_BYTES_WRITTEN,
mContentBytesWritten0RTT);
}
}
}
bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue,
uint32_t& aOut0RTTBytesWritten) {
// If for some reason the components to check on NPN aren't available,
@ -408,73 +481,19 @@ bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue,
}
rv = info->GetNegotiatedNPN(negotiatedNPN);
if (!m0RTTChecked && (rv == NS_ERROR_NOT_CONNECTED) &&
!mConnInfo->UsingProxy()) {
// 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.
m0RTTChecked = true;
nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN);
if (NS_FAILED(rvEarlyAlpn)) {
// if ssl->DriveHandshake() has never been called the value
// for AlpnEarlySelection is still not set. So call it here and
// check again.
LOG1(
("nsHttpConnection::EnsureNPNComplete %p - "
"early selected alpn not available, we will try one more time.",
this));
// Let's do DriveHandshake again.
rv = ssl->DriveHandshake();
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
goto npnComplete;
}
// Check NegotiatedNPN first.
rv = info->GetNegotiatedNPN(negotiatedNPN);
if (rv == NS_ERROR_NOT_CONNECTED) {
rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN);
}
if (rv == NS_ERROR_NOT_CONNECTED) {
rv = ssl->DriveHandshake();
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
goto npnComplete;
}
if (NS_FAILED(rvEarlyAlpn)) {
LOG1(
("nsHttpConnection::EnsureNPNComplete %p - "
"early selected alpn not available",
this));
mEarlyDataNegotiated = false;
} else {
LOG1(
("nsHttpConnection::EnsureNPNComplete %p -"
"early selected alpn: %s",
this, mEarlyNegotiatedALPN.get()));
uint32_t infoIndex;
const SpdyInformation* info = gHttpHandler->SpdyInfo();
if (NS_FAILED(info->GetNPNIndex(mEarlyNegotiatedALPN, &infoIndex))) {
// This is the HTTP/1 case.
// Check if early-data is allowed for this transaction.
if (mTransaction->Do0RTT()) {
LOG(
("nsHttpConnection::EnsureNPNComplete [this=%p] - We "
"can do 0RTT (http/1)!",
this));
mWaitingFor0RTTResponse = true;
}
} 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::EnsureNPNComplete [this=%p] - Starting "
"0RTT for h2!",
this));
mWaitingFor0RTTResponse = true;
Start0RTTSpdy(info->Version[infoIndex]);
}
mEarlyDataNegotiated = true;
}
// Check again, maybe the handshake is done now.
rv = info->GetNegotiatedNPN(negotiatedNPN);
}
if (rv == NS_ERROR_NOT_CONNECTED) {
Check0RttEnabled(ssl);
if (mWaitingFor0RTTResponse) {
aOut0RTTWriteHandshakeValue = mTransaction->ReadSegments(
this, nsIOService::gDefaultSegmentSize, &aOut0RTTBytesWritten);
@ -489,11 +508,6 @@ bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue,
mContentBytesWritten0RTT += aOut0RTTBytesWritten;
}
rv = ssl->DriveHandshake();
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
goto npnComplete;
}
return false;
}
@ -532,24 +546,7 @@ bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue,
}
}
// Send the 0RTT telemetry only for tls1.3
if (tlsVersion > nsISSLSocketControl::TLS_VERSION_1_2) {
Telemetry::Accumulate(
Telemetry::TLS_EARLY_DATA_NEGOTIATED,
(!mEarlyDataNegotiated)
? TLS_EARLY_DATA_NOT_AVAILABLE
: ((mWaitingFor0RTTResponse)
? TLS_EARLY_DATA_AVAILABLE_AND_USED
: TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED));
if (mWaitingFor0RTTResponse) {
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_ACCEPTED,
earlyDataAccepted);
}
if (earlyDataAccepted) {
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_BYTES_WRITTEN,
mContentBytesWritten0RTT);
}
}
EarlyDataTelemetry(tlsVersion, earlyDataAccepted);
mWaitingFor0RTTResponse = false;
if (!earlyDataAccepted) {
@ -557,14 +554,7 @@ bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue,
("nsHttpConnection::EnsureNPNComplete [this=%p] early data not "
"accepted",
this));
if (mTransaction->QueryNullTransaction() &&
(mBootstrappedTimings.secureConnectionStart.IsNull() ||
mBootstrappedTimings.tcpConnectEnd.IsNull())) {
mBootstrappedTimings.secureConnectionStart =
mTransaction->QueryNullTransaction()->GetSecureConnectionStart();
mBootstrappedTimings.tcpConnectEnd =
mTransaction->QueryNullTransaction()->GetTcpConnectEnd();
}
uint32_t infoIndex;
const SpdyInformation* info = gHttpHandler->SpdyInfo();
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
@ -585,7 +575,6 @@ bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue,
StartSpdy(ssl, mSpdySession->SpdyVersion());
}
}
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
}

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

@ -243,6 +243,8 @@ class nsHttpConnection final : public HttpConnectionBase,
[[nodiscard]] nsresult DisableTCPKeepalives();
bool CheckCanWrite0RTTData();
void Check0RttEnabled(nsISSLSocketControl* ssl);
void EarlyDataTelemetry(int16_t tlsVersion, bool earlyDataAccepted);
private:
// mTransaction only points to the HTTP Transaction callbacks if the