mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 1650388 - Send 0RTT data. r=kershaw
Differential Revision: https://phabricator.services.mozilla.com/D87231
This commit is contained in:
parent
368bae162a
commit
05c4dcd62f
@ -156,6 +156,24 @@ nsresult Http3Session::Init(const nsACString& aOrigin,
|
||||
if (NS_SUCCEEDED(SSLTokensCache::Get(peerId, token))) {
|
||||
LOG(("Found a resumption token in the cache."));
|
||||
mHttp3Connection->SetResumptionToken(token);
|
||||
if (mHttp3Connection->IsZeroRtt()) {
|
||||
LOG(("Can send ZeroRtt data"));
|
||||
RefPtr<Http3Session> self(this);
|
||||
mState = ZERORTT;
|
||||
// Let the nsHttpConnectionMgr know that the connection can accept
|
||||
// transactions.
|
||||
// We need to dispatch the following function to this thread so that
|
||||
// it is executed after the current function. At this point a
|
||||
// Http3Session is still being initialized and ReportHttp3Connection
|
||||
// will try to dispatch transaction on this session therefore it
|
||||
// needs to be executed after the initializationg is done.
|
||||
DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(NS_NewRunnableFunction(
|
||||
"Http3Session::ReportHttp3Connection",
|
||||
[self]() {
|
||||
self->ReportHttp3Connection();
|
||||
}));
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -360,11 +378,10 @@ nsresult Http3Session::ProcessEvents(uint32_t count) {
|
||||
static_cast<uint32_t>(rv)));
|
||||
return rv;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Http3Event::Tag::DataWritable:
|
||||
MOZ_ASSERT(mState == CONNECTED);
|
||||
MOZ_ASSERT(CanSandData());
|
||||
LOG(("Http3Session::ProcessEvents - DataWritable"));
|
||||
if (mReadyForWriteButBlocked.RemoveElement(
|
||||
event.data_writable.stream_id)) {
|
||||
@ -417,12 +434,23 @@ nsresult Http3Session::ProcessEvents(uint32_t count) {
|
||||
CallCertVerification();
|
||||
}
|
||||
break;
|
||||
case Http3Event::Tag::ZeroRttRejected:
|
||||
LOG(("Http3Session::ProcessEvents - ZeroRttRejected"));
|
||||
if (mState == ZERORTT) {
|
||||
mState = INITIALIZING;
|
||||
Finish0Rtt(true);
|
||||
}
|
||||
break;
|
||||
case Http3Event::Tag::ConnectionConnected:
|
||||
{
|
||||
LOG(("Http3Session::ProcessEvents - ConnectionConnected"));
|
||||
bool was0RTT = mState == ZERORTT;
|
||||
mState = CONNECTED;
|
||||
SetSecInfo();
|
||||
mSocketControl->HandshakeCompleted();
|
||||
if (was0RTT) {
|
||||
Finish0Rtt(false);
|
||||
}
|
||||
nsTArray<uint8_t> token;
|
||||
mHttp3Connection->GetResumptionToken(token);
|
||||
if (!token.IsEmpty()) {
|
||||
@ -436,8 +464,7 @@ nsresult Http3Session::ProcessEvents(uint32_t count) {
|
||||
}
|
||||
}
|
||||
|
||||
gHttpHandler->ConnMgr()->ReportHttp3Connection(mSegmentReaderWriter);
|
||||
MaybeResumeSend();
|
||||
ReportHttp3Connection();
|
||||
}
|
||||
break;
|
||||
case Http3Event::Tag::GoawayReceived:
|
||||
@ -600,13 +627,25 @@ bool Http3Session::AddStream(nsAHttpTransaction* aHttpTransaction,
|
||||
Http3Stream* stream = new Http3Stream(aHttpTransaction, this);
|
||||
mStreamTransactionHash.Put(aHttpTransaction, RefPtr{stream});
|
||||
|
||||
if (mState == ZERORTT) {
|
||||
if (!stream->Do0RTT()) {
|
||||
LOG(("Http3Session %p will not get early data from Http3Stream %p",
|
||||
this, stream));
|
||||
if (!mCannotDo0RTTStreams.Contains(stream)) {
|
||||
mCannotDo0RTTStreams.AppendElement(stream);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
m0RTTStreams.AppendElement(stream);
|
||||
}
|
||||
}
|
||||
StreamReadyToWrite(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Http3Session::CanReuse() {
|
||||
return (mState == CONNECTED) && !(mGoawayReceived || mShouldClose);
|
||||
return CanSandData() && !(mGoawayReceived || mShouldClose);
|
||||
}
|
||||
|
||||
void Http3Session::QueueStream(Http3Stream* stream) {
|
||||
@ -677,6 +716,13 @@ nsresult Http3Session::TryActivating(
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
if (mState == ZERORTT) {
|
||||
if (!aStream->Do0RTT()) {
|
||||
MOZ_ASSERT(!mCannotDo0RTTStreams.Contains(aStream));
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = mHttp3Connection->Fetch(aMethod, aScheme, aAuthorityHeader,
|
||||
aPath, aHeaders, aStreamId);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -808,10 +854,7 @@ nsresult Http3Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
|
||||
Http3Stream* stream = nullptr;
|
||||
|
||||
// Step 1)
|
||||
while (
|
||||
(mState ==
|
||||
CONNECTED) && // Do not send transaction data untill we are connected.
|
||||
(stream = mReadyForWrite.PopFront())) {
|
||||
while (CanSandData() && (stream = mReadyForWrite.PopFront())) {
|
||||
LOG(
|
||||
("Http3Session::ReadSegmentsAgain call ReadSegments from stream=%p "
|
||||
"[this=%p]",
|
||||
@ -882,13 +925,13 @@ nsresult Http3Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
|
||||
void Http3Session::StreamReadyToWrite(Http3Stream* aStream) {
|
||||
MOZ_ASSERT(aStream);
|
||||
mReadyForWrite.Push(aStream);
|
||||
if ((mState == CONNECTED) && mConnection) {
|
||||
if (CanSandData() && mConnection) {
|
||||
Unused << mConnection->ResumeSend();
|
||||
}
|
||||
}
|
||||
|
||||
void Http3Session::MaybeResumeSend() {
|
||||
if ((mReadyForWrite.GetSize() > 0) && (mState == CONNECTED) && mConnection) {
|
||||
if ((mReadyForWrite.GetSize() > 0) && CanSandData() && mConnection) {
|
||||
Unused << mConnection->ResumeSend();
|
||||
}
|
||||
}
|
||||
@ -1271,7 +1314,7 @@ bool Http3Session::JoinConnection(const nsACString& hostname, int32_t port) {
|
||||
bool Http3Session::RealJoinConnection(const nsACString& hostname, int32_t port,
|
||||
bool justKidding) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
if (!mConnection || (mState != CONNECTED) || mShouldClose ||
|
||||
if (!mConnection || !CanSandData() || mShouldClose ||
|
||||
mGoawayReceived) {
|
||||
return false;
|
||||
}
|
||||
@ -1374,7 +1417,7 @@ void Http3Session::CallCertVerification() {
|
||||
void Http3Session::Authenticated(int32_t aError) {
|
||||
LOG(("Http3Session::Authenticated error=0x%" PRIx32 " [this=%p].", aError,
|
||||
this));
|
||||
if (mState == INITIALIZING) {
|
||||
if ((mState == INITIALIZING) || (mState == ZERORTT)) {
|
||||
if (psm::IsNSSErrorCode(aError)) {
|
||||
mError = psm::GetXPCOMFromNSSError(aError);
|
||||
LOG(("Http3Session::Authenticated psm-error=0x%" PRIx32 " [this=%p].",
|
||||
@ -1452,5 +1495,39 @@ void Http3Session::CloseConnectionTelemetry(CloseError& aError, bool aClosing) {
|
||||
aClosing ? "closing"_ns : "closed"_ns, value);
|
||||
}
|
||||
|
||||
void Http3Session::Finish0Rtt(bool aRestart) {
|
||||
for (size_t i = 0; i < m0RTTStreams.Length(); ++i) {
|
||||
if (m0RTTStreams[i]) {
|
||||
if (aRestart) {
|
||||
// When we need ot restart transactions remove them from all lists.
|
||||
if (m0RTTStreams[i]->HasStreamId()) {
|
||||
mStreamIdHash.Remove(m0RTTStreams[i]->StreamId());
|
||||
}
|
||||
RemoveStreamFromQueues(m0RTTStreams[i]);
|
||||
// The stream is ready to write again.
|
||||
mReadyForWrite.Push(m0RTTStreams[i]);
|
||||
}
|
||||
m0RTTStreams[i]->Finish0RTT(aRestart);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mCannotDo0RTTStreams.Length(); ++i) {
|
||||
if (mCannotDo0RTTStreams[i]) {
|
||||
mReadyForWrite.Push(mCannotDo0RTTStreams[i]);
|
||||
}
|
||||
}
|
||||
m0RTTStreams.Clear();
|
||||
mCannotDo0RTTStreams.Clear();
|
||||
MaybeResumeSend();
|
||||
}
|
||||
|
||||
void Http3Session::ReportHttp3Connection() {
|
||||
if (CanSandData() && !mHttp3ConnectionReported) {
|
||||
mHttp3ConnectionReported = true;
|
||||
gHttpHandler->ConnMgr()->ReportHttp3Connection(mSegmentReaderWriter);
|
||||
MaybeResumeSend();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -51,6 +51,7 @@ class Http3Session final : public nsAHttpTransaction,
|
||||
HttpConnectionUDP* readerWriter);
|
||||
|
||||
bool IsConnected() const { return mState == CONNECTED; }
|
||||
bool CanSandData() const { return (mState == CONNECTED) || (mState == ZERORTT); }
|
||||
bool IsClosing() const { return (mState == CLOSING || mState == CLOSED); }
|
||||
bool IsClosed() const { return mState == CLOSED; }
|
||||
|
||||
@ -100,6 +101,8 @@ class Http3Session final : public nsAHttpTransaction,
|
||||
|
||||
const nsCString& GetAlpnToken() { return mAlpnToken; }
|
||||
|
||||
void ReportHttp3Connection();
|
||||
|
||||
private:
|
||||
~Http3Session();
|
||||
|
||||
@ -137,6 +140,7 @@ class Http3Session final : public nsAHttpTransaction,
|
||||
void MaybeResumeSend();
|
||||
|
||||
void CloseConnectionTelemetry(CloseError& aError, bool aClosing);
|
||||
void Finish0Rtt(bool aRestart);
|
||||
|
||||
RefPtr<NeqoHttp3Conn> mHttp3Connection;
|
||||
RefPtr<nsAHttpConnection> mConnection;
|
||||
@ -149,13 +153,14 @@ class Http3Session final : public nsAHttpTransaction,
|
||||
nsTArray<RefPtr<Http3Stream>> mSlowConsumersReadyForRead;
|
||||
nsDeque<Http3Stream> mQueuedStreams;
|
||||
|
||||
enum State { INITIALIZING, CONNECTED, CLOSING, CLOSED } mState;
|
||||
enum State { INITIALIZING, ZERORTT, CONNECTED, CLOSING, CLOSED } mState;
|
||||
|
||||
bool mAuthenticationStarted;
|
||||
bool mCleanShutdown;
|
||||
bool mGoawayReceived;
|
||||
bool mShouldClose;
|
||||
bool mIsClosedByNeqo;
|
||||
bool mHttp3ConnectionReported = false;
|
||||
// mError is neqo error (a protocol error) and that may mean that we will
|
||||
// send some packets after that.
|
||||
nsresult mError;
|
||||
@ -180,6 +185,12 @@ class Http3Session final : public nsAHttpTransaction,
|
||||
nsCString mAlpnToken;
|
||||
|
||||
uint64_t mTransactionCount = 0;
|
||||
|
||||
// The stream(s) that we are getting 0RTT data from.
|
||||
nsTArray<WeakPtr<Http3Stream>> m0RTTStreams;
|
||||
// The stream(s) that are not able to send 0RTT data. We need to
|
||||
// remember them put them into mReadyForWrite queue when 0RTT finishes.
|
||||
nsTArray<WeakPtr<Http3Stream>> mCannotDo0RTTStreams;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(Http3Session, NS_HTTP3SESSION_IID);
|
||||
|
@ -375,5 +375,36 @@ nsresult Http3Stream::WriteSegments(nsAHttpSegmentWriter* writer,
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool Http3Stream::Do0RTT() {
|
||||
MOZ_ASSERT(mTransaction);
|
||||
mAttempting0RTT = mTransaction->Do0RTT();
|
||||
return mAttempting0RTT;
|
||||
}
|
||||
|
||||
nsresult Http3Stream::Finish0RTT(bool aRestart) {
|
||||
MOZ_ASSERT(mTransaction);
|
||||
mAttempting0RTT = false;
|
||||
nsresult rv = mTransaction->Finish0RTT(aRestart, false);
|
||||
if (aRestart) {
|
||||
nsHttpTransaction* trans = mTransaction->QueryHttpTransaction();
|
||||
if (trans) {
|
||||
trans->Refused0RTT();
|
||||
}
|
||||
}
|
||||
mSendState = PREPARING_HEADERS;
|
||||
mRecvState = READING_HEADERS;
|
||||
mStreamId = UINT64_MAX;
|
||||
mQueued = false;
|
||||
mRequestBlockedOnRead = false;
|
||||
mDataReceived = false;
|
||||
mResetRecv = false;
|
||||
mRequestBodyLenRemaining = 0;
|
||||
mTotalSent = 0;
|
||||
mTotalRead = 0;
|
||||
mFin = false;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "ARefBase.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@ -16,6 +17,7 @@ class Http3Session;
|
||||
|
||||
class Http3Stream final : public nsAHttpSegmentReader,
|
||||
public nsAHttpSegmentWriter,
|
||||
public SupportsWeakPtr,
|
||||
public ARefBase {
|
||||
public:
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
@ -60,6 +62,10 @@ class Http3Stream final : public nsAHttpSegmentReader,
|
||||
|
||||
void SetResponseHeaders(nsTArray<uint8_t>& aResponseHeaders, bool fin);
|
||||
|
||||
// Mirrors nsAHttpTransaction
|
||||
bool Do0RTT();
|
||||
nsresult Finish0RTT(bool aRestart);
|
||||
|
||||
private:
|
||||
~Http3Stream() = default;
|
||||
|
||||
@ -142,6 +148,8 @@ class Http3Stream final : public nsAHttpSegmentReader,
|
||||
uint64_t mTotalRead;
|
||||
|
||||
bool mFin;
|
||||
|
||||
bool mAttempting0RTT = false;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -88,6 +88,10 @@ class NeqoHttp3Conn final {
|
||||
neqo_http3conn_set_resumption_token(this, &aToken);
|
||||
}
|
||||
|
||||
bool IsZeroRtt() {
|
||||
return neqo_http3conn_is_zero_rtt(this);
|
||||
}
|
||||
|
||||
nsrefcnt AddRef() { return neqo_http3conn_addref(this); }
|
||||
nsrefcnt Release() { return neqo_http3conn_release(this); }
|
||||
|
||||
|
@ -690,3 +690,8 @@ pub extern "C" fn neqo_http3conn_resumption_token(conn: &mut NeqoHttp3Conn, toke
|
||||
pub extern "C" fn neqo_http3conn_set_resumption_token(conn: &mut NeqoHttp3Conn, token: &mut ThinVec<u8>,) {
|
||||
let _ = conn.conn.set_resumption_token(Instant::now(), token);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn neqo_http3conn_is_zero_rtt(conn: &mut NeqoHttp3Conn) -> bool {
|
||||
conn.conn.state() == Http3State::ZeroRtt
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user