mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Bug 1322373 - TLS 1.3 early-data for http/2
This commit is contained in:
parent
0f08cb0c4f
commit
202ca6d067
11 changed files with 342 additions and 82 deletions
|
|
@ -87,6 +87,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mWaitingFor0RTTResponse(false)
|
||||
, mContentBytesWritten0RTT(0)
|
||||
, mEarlyDataNegotiated(false)
|
||||
, mDid0RTTSpdy(false)
|
||||
{
|
||||
LOG(("Creating nsHttpConnection @%p\n", this));
|
||||
|
||||
|
|
@ -158,16 +159,113 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list)
|
||||
{
|
||||
nsresult rv = mTransaction->TakeSubTransactions(list);
|
||||
|
||||
if (rv == NS_ERROR_ALREADY_OPENED) {
|
||||
// Has the interface for TakeSubTransactions() changed?
|
||||
LOG(("TakeSubTransactions somehow called after "
|
||||
"nsAHttpTransaction began processing\n"));
|
||||
MOZ_ASSERT(false,
|
||||
"TakeSubTransactions somehow called after "
|
||||
"nsAHttpTransaction began processing");
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||
// Has the interface for TakeSubTransactions() changed?
|
||||
LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()"));
|
||||
MOZ_ASSERT(false,
|
||||
"unexpected result from "
|
||||
"nsAHttpTransaction::TakeSubTransactions()");
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::MoveTransactionsToSpdy(nsresult status, nsTArray<RefPtr<nsAHttpTransaction> > &list)
|
||||
{
|
||||
if (NS_FAILED(status)) { // includes NS_ERROR_NOT_IMPLEMENTED
|
||||
MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty");
|
||||
|
||||
// This is ok - treat mTransaction as a single real request.
|
||||
// Wrap the old http transaction into the new spdy session
|
||||
// as the first stream.
|
||||
LOG(("nsHttpConnection::MoveTransactionsToSpdy moves single transaction %p "
|
||||
"into SpdySession %p\n", mTransaction.get(), mSpdySession.get()));
|
||||
nsresult rv = AddTransaction(mTransaction, mPriority);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
int32_t count = list.Length();
|
||||
|
||||
LOG(("nsHttpConnection::MoveTransactionsToSpdy moving transaction list len=%d "
|
||||
"into SpdySession %p\n", count, mSpdySession.get()));
|
||||
|
||||
if (!count) {
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
for (int32_t index = 0; index < count; ++index) {
|
||||
nsresult rv = AddTransaction(list[index], mPriority);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::Start0RTTSpdy(uint8_t spdyVersion)
|
||||
{
|
||||
LOG(("nsHttpConnection::Start0RTTSpdy [this=%p]", this));
|
||||
mDid0RTTSpdy = true;
|
||||
mUsingSpdyVersion = spdyVersion;
|
||||
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport,
|
||||
true);
|
||||
|
||||
nsTArray<RefPtr<nsAHttpTransaction> > list;
|
||||
nsresult rv = TryTakeSubTransactions(list);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||
LOG(("nsHttpConnection::Start0RTTSpdy [this=%p] failed taking "
|
||||
"subtransactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv)));
|
||||
return;
|
||||
}
|
||||
|
||||
rv = MoveTransactionsToSpdy(rv, list);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsHttpConnection::Start0RTTSpdy [this=%p] failed moving "
|
||||
"transactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv)));
|
||||
return;
|
||||
}
|
||||
|
||||
mTransaction = mSpdySession;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
||||
{
|
||||
LOG(("nsHttpConnection::StartSpdy [this=%p]\n", this));
|
||||
LOG(("nsHttpConnection::StartSpdy [this=%p, mDid0RTTSpdy=%d]\n", this, mDid0RTTSpdy));
|
||||
|
||||
MOZ_ASSERT(!mSpdySession);
|
||||
MOZ_ASSERT(!mSpdySession || mDid0RTTSpdy);
|
||||
|
||||
mUsingSpdyVersion = spdyVersion;
|
||||
mEverUsedSpdy = true;
|
||||
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport);
|
||||
|
||||
if (!mDid0RTTSpdy) {
|
||||
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport,
|
||||
false);
|
||||
}
|
||||
|
||||
if (!mReportedSpdy) {
|
||||
mReportedSpdy = true;
|
||||
|
|
@ -185,27 +283,13 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
// pack them all into a new spdy session.
|
||||
|
||||
nsTArray<RefPtr<nsAHttpTransaction> > list;
|
||||
nsresult rv = mTransaction->TakeSubTransactions(list);
|
||||
nsresult rv = NS_OK;
|
||||
if (!mDid0RTTSpdy) {
|
||||
rv = TryTakeSubTransactions(list);
|
||||
|
||||
if (rv == NS_ERROR_ALREADY_OPENED) {
|
||||
// Has the interface for TakeSubTransactions() changed?
|
||||
LOG(("TakeSubTransactions somehow called after "
|
||||
"nsAHttpTransaction began processing\n"));
|
||||
MOZ_ASSERT(false,
|
||||
"TakeSubTransactions somehow called after "
|
||||
"nsAHttpTransaction began processing");
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||
// Has the interface for TakeSubTransactions() changed?
|
||||
LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()"));
|
||||
MOZ_ASSERT(false,
|
||||
"unexpected result from "
|
||||
"nsAHttpTransaction::TakeSubTransactions()");
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
return;
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (NeedSpdyTunnel()) {
|
||||
|
|
@ -227,35 +311,11 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
mConnInfo = wildCardProxyCi;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) { // includes NS_ERROR_NOT_IMPLEMENTED
|
||||
MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty");
|
||||
|
||||
// This is ok - treat mTransaction as a single real request.
|
||||
// Wrap the old http transaction into the new spdy session
|
||||
// as the first stream.
|
||||
LOG(("nsHttpConnection::StartSpdy moves single transaction %p "
|
||||
"into SpdySession %p\n", mTransaction.get(), mSpdySession.get()));
|
||||
rv = AddTransaction(mTransaction, mPriority);
|
||||
if (!mDid0RTTSpdy) {
|
||||
rv = MoveTransactionsToSpdy(rv, list);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int32_t count = list.Length();
|
||||
|
||||
LOG(("nsHttpConnection::StartSpdy moving transaction list len=%d "
|
||||
"into SpdySession %p\n", count, mSpdySession.get()));
|
||||
|
||||
if (!count) {
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t index = 0; index < count; ++index) {
|
||||
rv = AddTransaction(list[index], mPriority);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable TCP Keepalives - use SPDY ping instead.
|
||||
|
|
@ -328,8 +388,7 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
|||
// (AlpnEarlySelection), we are using HTTP/1, and the request data can
|
||||
// be safely retried.
|
||||
m0RTTChecked = true;
|
||||
nsAutoCString earlyNegotiatedNPN;
|
||||
nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN);
|
||||
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
|
||||
|
|
@ -346,7 +405,7 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
|||
// Check NegotiatedNPN first.
|
||||
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
|
||||
if (rv == NS_ERROR_NOT_CONNECTED) {
|
||||
rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN);
|
||||
rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -356,19 +415,26 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
|||
mEarlyDataNegotiated = false;
|
||||
} else {
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete %p -"
|
||||
"early selected alpn: %s", this, earlyNegotiatedNPN.get()));
|
||||
"early selected alpn: %s", this, mEarlyNegotiatedALPN.get()));
|
||||
uint32_t infoIndex;
|
||||
const SpdyInformation *info = gHttpHandler->SpdyInfo();
|
||||
// We are doing 0RTT only with Http/1 right now!
|
||||
if (NS_FAILED(info->GetNPNIndex(earlyNegotiatedNPN, &infoIndex))) {
|
||||
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!", this));
|
||||
"can do 0RTT (http/1)!", this));
|
||||
mWaitingFor0RTTResponse = true;
|
||||
}
|
||||
mEarlyDataNegotiated = 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -398,16 +464,17 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
|||
this, mConnInfo->HashKey().get(), negotiatedNPN.get(),
|
||||
mTLSFilter ? " [Double Tunnel]" : ""));
|
||||
|
||||
bool ealyDataAccepted = false;
|
||||
bool earlyDataAccepted = false;
|
||||
if (mWaitingFor0RTTResponse) {
|
||||
// Check if early data has been accepted.
|
||||
rv = ssl->GetEarlyDataAccepted(&ealyDataAccepted);
|
||||
rv = ssl->GetEarlyDataAccepted(&earlyDataAccepted);
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data "
|
||||
"that was sent during 0RTT %s been accepted.",
|
||||
this, ealyDataAccepted ? "has" : "has not"));
|
||||
"that was sent during 0RTT %s been accepted [rv=%" PRIx32 "].",
|
||||
this, earlyDataAccepted ? "has" : "has not", static_cast<uint32_t>(rv)));
|
||||
|
||||
if (NS_FAILED(rv) ||
|
||||
NS_FAILED(mTransaction->Finish0RTT(!ealyDataAccepted))) {
|
||||
NS_FAILED(mTransaction->Finish0RTT(!earlyDataAccepted, negotiatedNPN != mEarlyNegotiatedALPN))) {
|
||||
LOG(("nsHttpConection::EnsureNPNComplete [this=%p] closing transaction %p", this, mTransaction.get()));
|
||||
mTransaction->Close(NS_ERROR_NET_RESET);
|
||||
goto npnComplete;
|
||||
}
|
||||
|
|
@ -423,16 +490,17 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
|||
: TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED));
|
||||
if (mWaitingFor0RTTResponse) {
|
||||
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_ACCEPTED,
|
||||
ealyDataAccepted);
|
||||
earlyDataAccepted);
|
||||
}
|
||||
if (ealyDataAccepted) {
|
||||
if (earlyDataAccepted) {
|
||||
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_BYTES_WRITTEN,
|
||||
mContentBytesWritten0RTT);
|
||||
}
|
||||
}
|
||||
mWaitingFor0RTTResponse = false;
|
||||
|
||||
if (!ealyDataAccepted) {
|
||||
if (!earlyDataAccepted) {
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] early data not accepted", this));
|
||||
uint32_t infoIndex;
|
||||
const SpdyInformation *info = gHttpHandler->SpdyInfo();
|
||||
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
|
||||
|
|
@ -442,13 +510,20 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
|||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %d bytes "
|
||||
"has been sent during 0RTT.", this, mContentBytesWritten0RTT));
|
||||
mContentBytesWritten = mContentBytesWritten0RTT;
|
||||
if (mSpdySession) {
|
||||
// We had already started 0RTT-spdy, now we need to fully set up
|
||||
// spdy, since we know we're sticking with it.
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - finishing "
|
||||
"StartSpdy for 0rtt spdy session %p", this, mSpdySession.get()));
|
||||
StartSpdy(mSpdySession->SpdyVersion());
|
||||
}
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
|
||||
}
|
||||
|
||||
npnComplete:
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete setting complete to true"));
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] setting complete to true", this));
|
||||
mNPNComplete = true;
|
||||
|
||||
mTransaction->OnTransportStatus(mSocketTransport,
|
||||
|
|
@ -456,12 +531,25 @@ npnComplete:
|
|||
0);
|
||||
|
||||
if (mWaitingFor0RTTResponse) {
|
||||
// Didn't get 0RTT OK, back out of the "attempting 0RTT" state
|
||||
mWaitingFor0RTTResponse = false;
|
||||
if (NS_FAILED(mTransaction->Finish0RTT(true))) {
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] 0rtt failed", this));
|
||||
if (NS_FAILED(mTransaction->Finish0RTT(true, negotiatedNPN != mEarlyNegotiatedALPN))) {
|
||||
mTransaction->Close(NS_ERROR_NET_RESET);
|
||||
}
|
||||
mContentBytesWritten0RTT = 0;
|
||||
}
|
||||
|
||||
if (mDid0RTTSpdy && negotiatedNPN != mEarlyNegotiatedALPN) {
|
||||
// Reset the work done by Start0RTTSpdy
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] resetting Start0RTTSpdy", this));
|
||||
mUsingSpdyVersion = 0;
|
||||
mTransaction = nullptr;
|
||||
mSpdySession = nullptr;
|
||||
// We have to reset this here, just in case we end up starting spdy again,
|
||||
// so it can actually do everything it needs to do.
|
||||
mDid0RTTSpdy = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue