Backed out 5 changesets (bug 1790392, bug 1790398, bug 1789858) for causing build bustage at Http3WebTransportSession.cpp. CLOSED TREE

Backed out changeset 6ffb6a0029dc (bug 1790398)
Backed out changeset 93366266b85a (bug 1790398)
Backed out changeset 9d7331dd64c8 (bug 1790398)
Backed out changeset 07185f9a62ec (bug 1790392)
Backed out changeset 87a8741c5a2b (bug 1789858)
This commit is contained in:
Butkovits Atila 2022-10-20 01:46:29 +03:00
parent 51e536fea5
commit 1455ec3e55
42 changed files with 159 additions and 2365 deletions

View File

@ -320,10 +320,6 @@ var NetUtil = {
return channel;
},
newWebTransport: function NetUtil_newWebTransport() {
return Services.io.newWebTransport();
},
/**
* Reads aCount bytes from aInputStream into a string.
*

View File

@ -314,7 +314,6 @@ LOCAL_INCLUDES += [
"/dom/base",
"/netwerk/dns",
"/netwerk/protocol/http",
"/netwerk/protocol/webtransport",
"/netwerk/socket",
"/netwerk/url-classifier",
"/security/manager/ssl",

View File

@ -12,7 +12,6 @@ interface nsIURI;
interface nsIFile;
interface nsIPrincipal;
interface nsILoadInfo;
interface nsIWebTransport;
webidl Node;
@ -150,11 +149,6 @@ interface nsIIOService : nsISupports
in unsigned long aSecurityFlags,
in nsContentPolicyType aContentPolicyType);
/**
* Creates a WebTransport.
*/
nsIWebTransport newWebTransport();
/**
* Returns true if networking is in "offline" mode. When in offline mode,
* attempts to access the network will fail (although this does not

View File

@ -35,10 +35,8 @@
#include "nsIProtocolProxyService2.h"
#include "MainThreadUtils.h"
#include "nsINode.h"
#include "nsIWebTransport.h"
#include "nsIWidget.h"
#include "nsThreadUtils.h"
#include "WebTransportSessionProxy.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/net/NeckoCommon.h"
@ -1241,18 +1239,6 @@ nsIOService::NewChannel(const nsACString& aSpec, const char* aCharset,
aContentPolicyType, result);
}
NS_IMETHODIMP
nsIOService::NewWebTransport(nsIWebTransport** result) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIWebTransport> webTransport = new WebTransportSessionProxy();
webTransport.forget(result);
return NS_OK;
}
bool nsIOService::IsLinkUp() {
InitializeNetworkLinkService();

View File

@ -17,7 +17,6 @@ There is also documentation for the `HTTP server we use for unit tests`_.
new_to_necko_resources
network_test_guidelines.md
url_parsers.md
webtransport/webtransport
captive_portals.md
.. _HTTP server we use for unit tests: http_server_for_testing.html

View File

@ -1,7 +0,0 @@
WebTransport
============
Components:
- [WebTransportSessionProxy](webtransportsessionproxy.md)

View File

@ -1,19 +0,0 @@
# WebTransportSessionProxy
WebTransportSessionProxy is introduced to enable the creation of a Http3WebTransportSession and coordination of actions that are performed on the main thread and on the socket thread.
WebTransportSessionProxy can be in different states and the following diagram depicts the transition between the states. “MT” and “ST” mean: the action is happening on the main and socket thread. More details about this class can be found in [WebTransportSessionProxy.h](https://searchfox.org/mozilla-central/source/netwerk/protocol/webtransport/WebTransportSessionProxy.h).
```{mermaid}
graph TD
A[INIT] -->|"nsIWebTransport::AsyncConnect; MT"| B[NEGOTIATING]
B -->|"200 response; ST"| C[NEGOTIATING_SUCCEEDED]
B -->|"nsHttpChannel::OnStart/OnStop failed; MT"| D[DONE]
B -->|"nsIWebTransport::CloseSession; MT"| D
C -->|"nsHttpChannel::OnStart/OnStop failed; MT"| F[SESSION_CLOSE_PENDING]
C -->|"nsHttpChannel::OnStart/OnStop succeeded; MT"| E[ACTIVE]
E -->|"nsIWebTransport::CloseSession; MT"| F
E -->|"The peer closed the session or HTTP/3 connection error; ST"| G[CLOSE_CALLBACK_PENDING]
F -->|"CloseSessionInternal called, The peer closed the session or HTTP/3 connection error; ST"| D
G -->|"CallOnSessionClosed or nsIWebTransport::CloseSession; MT"| D
```

View File

@ -394,7 +394,6 @@ struct HttpConnectionInfoCloneArgs
bool isIPv6Disabled;
nsCString topWindowOrigin;
bool isHttp3;
bool webTransport;
bool hasIPHintAddress;
nsCString echConfig;
ProxyInfoCloneArgs[] proxyInfo;

View File

@ -354,7 +354,7 @@ void AltSvcMapping::GetConnectionInfo(
const OriginAttributes& originAttributes) {
RefPtr<nsHttpConnectionInfo> ci = new nsHttpConnectionInfo(
mOriginHost, mOriginPort, mNPNToken, mUsername, pi, originAttributes,
mAlternateHost, mAlternatePort, mIsHttp3, false);
mAlternateHost, mAlternatePort, mIsHttp3);
// http:// without the mixed-scheme attribute needs to be segmented in the
// connection manager connection information hash with this attribute

View File

@ -49,11 +49,6 @@ nsresult ConnectionHandle::TakeTransport(nsISocketTransport** aTransport,
return mConn->TakeTransport(aTransport, aInputStream, aOutputStream);
}
Http3WebTransportSession* ConnectionHandle::GetWebTransportSession(
nsAHttpTransaction* aTransaction) {
return mConn->GetWebTransportSession(aTransaction);
}
bool ConnectionHandle::IsPersistent() {
MOZ_ASSERT(OnSocketThread());
return mConn->IsPersistent();

View File

@ -576,7 +576,7 @@ nsresult DnsAndConnectSocket::SetupConn(bool isPrimary, nsresult status) {
conn.get(), static_cast<uint32_t>(rv)));
if (nsHttpTransaction* trans = mTransaction->QueryHttpTransaction()) {
if (mIsHttp3 && !mConnInfo->GetWebTransport()) {
if (mIsHttp3) {
trans->DisableHttp3(true);
gHttpHandler->ExcludeHttp3(mConnInfo);
}

View File

@ -4271,12 +4271,6 @@ nsresult Http2Session::TakeTransport(nsISocketTransport**,
return NS_ERROR_UNEXPECTED;
}
Http3WebTransportSession* Http2Session::GetWebTransportSession(
nsAHttpTransaction* aTransaction) {
MOZ_ASSERT(false, "GetWebTransportSession of Http2Session");
return nullptr;
}
already_AddRefed<HttpConnectionBase> Http2Session::TakeHttpConnection() {
MOZ_ASSERT(false, "TakeHttpConnection of Http2Session");
return nullptr;

View File

@ -7,8 +7,6 @@
#include "HttpLog.h"
#include "Http3Session.h"
#include "Http3Stream.h"
#include "Http3StreamBase.h"
#include "Http3WebTransportSession.h"
#include "mozilla/net/DNS.h"
#include "nsHttpHandler.h"
#include "mozilla/RefPtr.h"
@ -111,18 +109,12 @@ nsresult Http3Session::Init(const nsHttpConnectionInfo* aConnInfo,
LOG3(
("Http3Session::Init origin=%s, alpn=%s, selfAddr=%s, peerAddr=%s,"
" qpack table size=%u, max blocked streams=%u webtransport=%d "
"[this=%p]",
" qpack table size=%u, max blocked streams=%u [this=%p]",
PromiseFlatCString(mConnInfo->GetOrigin()).get(),
PromiseFlatCString(mConnInfo->GetNPNToken()).get(),
selfAddr.ToString().get(), peerAddr.ToString().get(),
gHttpHandler->DefaultQpackTableSize(),
gHttpHandler->DefaultHttp3MaxBlockedStreams(),
mConnInfo->GetWebTransport(), this));
if (mConnInfo->GetWebTransport()) {
mWebTransportNegotiationStatus = WebTransportNegotiation::NEGOTIATING;
}
gHttpHandler->DefaultHttp3MaxBlockedStreams(), this));
nsresult rv = NeqoHttp3Conn::Init(
mConnInfo->GetOrigin(), mConnInfo->GetNPNToken(), selfAddr, peerAddr,
@ -131,8 +123,7 @@ nsresult Http3Session::Init(const nsHttpConnectionInfo* aConnInfo,
StaticPrefs::network_http_http3_max_data(),
StaticPrefs::network_http_http3_max_stream_data(),
StaticPrefs::network_http_http3_version_negotiation_enabled(),
mConnInfo->GetWebTransport(), gHttpHandler->Http3QlogDir(),
getter_AddRefs(mHttp3Connection));
gHttpHandler->Http3QlogDir(), getter_AddRefs(mHttp3Connection));
if (NS_FAILED(rv)) {
return rv;
}
@ -239,8 +230,7 @@ void Http3Session::Shutdown() {
stream->Transaction()->DoNotRemoveAltSvc();
}
stream->Close(NS_ERROR_NET_RESET);
} else if (stream->GetHttp3Stream() &&
stream->GetHttp3Stream()->RecvdData()) {
} else if (stream->RecvdData()) {
stream->Close(NS_ERROR_NET_PARTIAL_TRANSFER);
} else if (mError == NS_ERROR_NET_HTTP3_PROTOCOL_ERROR) {
stream->Close(NS_ERROR_NET_HTTP3_PROTOCOL_ERROR);
@ -254,14 +244,8 @@ void Http3Session::Shutdown() {
mStreamIdHash.Remove(stream->StreamId());
}
}
mStreamTransactionHash.Clear();
for (const auto& stream : mWebTransportSessions) {
stream->Close(NS_ERROR_ABORT);
RemoveStreamFromQueues(stream);
mStreamIdHash.Remove(stream->StreamId());
}
mWebTransportSessions.Clear();
mStreamTransactionHash.Clear();
}
Http3Session::~Http3Session() {
@ -329,8 +313,9 @@ void Http3Session::ProcessInput(nsIUDPSocket* socket) {
}
}
nsresult Http3Session::ProcessTransactionRead(uint64_t stream_id) {
RefPtr<Http3StreamBase> stream = mStreamIdHash.Get(stream_id);
nsresult Http3Session::ProcessTransactionRead(uint64_t stream_id,
uint32_t* countWritten) {
RefPtr<Http3Stream> stream = mStreamIdHash.Get(stream_id);
if (!stream) {
LOG(
("Http3Session::ProcessTransactionRead - stream not found "
@ -339,11 +324,13 @@ nsresult Http3Session::ProcessTransactionRead(uint64_t stream_id) {
return NS_OK;
}
return ProcessTransactionRead(stream);
return ProcessTransactionRead(stream, countWritten);
}
nsresult Http3Session::ProcessTransactionRead(Http3StreamBase* stream) {
nsresult rv = stream->WriteSegments();
nsresult Http3Session::ProcessTransactionRead(Http3Stream* stream,
uint32_t* countWritten) {
nsresult rv = stream->WriteSegments(stream, nsIOService::gDefaultSegmentSize,
countWritten);
if (ASpdySession::SoftStreamError(rv) || stream->Done()) {
LOG3(
@ -386,7 +373,7 @@ nsresult Http3Session::ProcessEvents() {
LOG(("Http3Session::ProcessEvents - HeaderReady"));
uint64_t id = event.header_ready.stream_id;
RefPtr<Http3StreamBase> stream = mStreamIdHash.Get(id);
RefPtr<Http3Stream> stream = mStreamIdHash.Get(id);
if (!stream) {
LOG(
("Http3Session::ProcessEvents - HeaderReady - stream not found "
@ -395,13 +382,11 @@ nsresult Http3Session::ProcessEvents() {
break;
}
MOZ_RELEASE_ASSERT(stream->GetHttp3Stream(),
"This must be a Http3Stream");
stream->SetResponseHeaders(data, event.header_ready.fin,
event.header_ready.interim);
rv = ProcessTransactionRead(stream);
uint32_t read = 0;
rv = ProcessTransactionRead(stream, &read);
if (NS_FAILED(rv)) {
LOG(("Http3Session::ProcessEvents [this=%p] rv=%" PRIx32, this,
@ -415,7 +400,8 @@ nsresult Http3Session::ProcessEvents() {
LOG(("Http3Session::ProcessEvents - DataReadable"));
uint64_t id = event.data_readable.stream_id;
nsresult rv = ProcessTransactionRead(id);
uint32_t read = 0;
nsresult rv = ProcessTransactionRead(id, &read);
if (NS_FAILED(rv)) {
LOG(("Http3Session::ProcessEvents [this=%p] rv=%" PRIx32, this,
@ -428,9 +414,8 @@ nsresult Http3Session::ProcessEvents() {
MOZ_ASSERT(CanSandData());
LOG(("Http3Session::ProcessEvents - DataWritable"));
RefPtr<Http3StreamBase> stream =
RefPtr<Http3Stream> stream =
mStreamIdHash.Get(event.data_writable.stream_id);
if (stream) {
StreamReadyToWrite(stream);
}
@ -443,12 +428,10 @@ nsresult Http3Session::ProcessEvents() {
LOG(("Http3Session::ProcessEvents - StopSeniding with error 0x%" PRIx64,
event.stop_sending.error));
if (event.stop_sending.error == HTTP3_APP_ERROR_NO_ERROR) {
RefPtr<Http3StreamBase> stream =
RefPtr<Http3Stream> stream =
mStreamIdHash.Get(event.data_writable.stream_id);
if (stream) {
RefPtr<Http3Stream> httpStream = stream->GetHttp3Stream();
MOZ_RELEASE_ASSERT(httpStream, "This must be a Http3Stream");
httpStream->StopSending();
stream->StopSending();
}
} else {
ResetRecvd(event.reset.stream_id, event.reset.error);
@ -602,102 +585,6 @@ nsresult Http3Session::ProcessEvents() {
CallCertVerification(Some(echPublicName));
}
} break;
case Http3Event::Tag::WebTransport: {
switch (event.web_transport._0.tag) {
case WebTransportEventExternal::Tag::Negotiated:
LOG(("Http3Session::ProcessEvents - WebTransport %d",
event.web_transport._0.negotiated._0));
MOZ_ASSERT(mWebTransportNegotiationStatus ==
WebTransportNegotiation::NEGOTIATING);
mWebTransportNegotiationStatus =
event.web_transport._0.negotiated._0
? WebTransportNegotiation::SUCCEEDED
: WebTransportNegotiation::FAILED;
WebTransportNegotiationDone();
break;
case WebTransportEventExternal::Tag::Session: {
MOZ_ASSERT(mState == CONNECTED);
uint64_t id = event.web_transport._0.session._0;
LOG(
("Http3Session::ProcessEvents - WebTransport Session "
" sessionId=0x%" PRIx64,
id));
RefPtr<Http3StreamBase> stream = mStreamIdHash.Get(id);
if (!stream) {
LOG(
("Http3Session::ProcessEvents - WebTransport Session - "
"stream not found "
"stream_id=0x%" PRIx64 " [this=%p].",
id, this));
break;
}
MOZ_RELEASE_ASSERT(stream->GetHttp3WebTransportSession(),
"It must be a WebTransport session");
stream->SetResponseHeaders(data, false, false);
rv = stream->WriteSegments();
if (ASpdySession::SoftStreamError(rv) || stream->Done()) {
LOG3(
("Http3Session::ProcessSingleTransactionRead session=%p "
"stream=%p "
"0x%" PRIx64 " cleanup stream rv=0x%" PRIx32 " done=%d.\n",
this, stream.get(), stream->StreamId(),
static_cast<uint32_t>(rv), stream->Done()));
if (mStreamTransactionHash.Contains(stream->Transaction())) {
CloseStream(stream, (rv == NS_BINDING_RETARGETED)
? NS_BINDING_RETARGETED
: NS_OK);
} else {
stream->GetHttp3WebTransportSession()->TransactionIsDone(
(rv == NS_BINDING_RETARGETED) ? NS_BINDING_RETARGETED
: NS_OK);
}
return NS_OK;
}
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
LOG(("Http3Session::ProcessEvents [this=%p] rv=%" PRIx32, this,
static_cast<uint32_t>(rv)));
return rv;
}
} break;
case WebTransportEventExternal::Tag::SessionClosed: {
uint64_t id = event.web_transport._0.session_closed.stream_id;
LOG(
("Http3Session::ProcessEvents - WebTransport SessionClosed "
" sessionId=0x%" PRIx64,
id));
RefPtr<Http3StreamBase> stream = mStreamIdHash.Get(id);
if (!stream) {
LOG(
("Http3Session::ProcessEvents - WebTransport SessionClosed - "
"stream not found "
"stream_id=0x%" PRIx64 " [this=%p].",
id, this));
break;
}
RefPtr<Http3WebTransportSession> wt =
stream->GetHttp3WebTransportSession();
MOZ_RELEASE_ASSERT(wt, "It must be a WebTransport session");
// TODO read status and reason properly.
// TODO we do not hanlde the case when a WebTransport session stream
// is closed before headers are send.
nsCString reason = ""_ns;
wt->OnSessionClosed(0, reason);
} break;
case WebTransportEventExternal::Tag::NewStream:
LOG(
("Http3Session::ProcessEvents - WebTransport NewStream "
"streamId=0x%" PRIx64 " sessionId=0x%" PRIx64,
event.web_transport._0.new_stream.stream_id,
event.web_transport._0.new_stream.session_id));
break;
}
} break;
default:
break;
}
@ -870,18 +757,9 @@ bool Http3Session::AddStream(nsAHttpTransaction* aHttpTransaction,
cos = trans->GetClassOfService();
}
Http3StreamBase* stream = nullptr;
if (trans && trans->IsForWebTransport()) {
LOG3(("Http3Session::AddStream new WeTransport session %p atrans=%p.\n",
this, aHttpTransaction));
stream = new Http3WebTransportSession(aHttpTransaction, this);
} else {
LOG3(("Http3Session::AddStream %p atrans=%p.\n", this, aHttpTransaction));
stream = new Http3Stream(aHttpTransaction, this, cos,
mCurrentTopBrowsingContextId);
}
LOG3(("Http3Session::AddStream %p atrans=%p.\n", this, aHttpTransaction));
Http3Stream* stream = new Http3Stream(aHttpTransaction, this, cos,
mCurrentTopBrowsingContextId);
mStreamTransactionHash.InsertOrUpdate(aHttpTransaction, RefPtr{stream});
if (mState == ZERORTT) {
@ -896,18 +774,12 @@ bool Http3Session::AddStream(nsAHttpTransaction* aHttpTransaction,
m0RTTStreams.AppendElement(stream);
}
if ((mWebTransportNegotiationStatus ==
WebTransportNegotiation::NEGOTIATING) &&
(trans && trans->IsForWebTransport())) {
mWaitingForWebTransportNegotiation.AppendElement(stream);
return true;
}
if (!mFirstHttpTransaction && !IsConnected()) {
mFirstHttpTransaction = aHttpTransaction->QueryHttpTransaction();
LOG3(("Http3Session::AddStream first session=%p trans=%p ", this,
mFirstHttpTransaction.get()));
}
StreamReadyToWrite(stream);
return true;
@ -917,7 +789,7 @@ bool Http3Session::CanReuse() {
return CanSandData() && !(mGoawayReceived || mShouldClose);
}
void Http3Session::QueueStream(Http3StreamBase* stream) {
void Http3Session::QueueStream(Http3Stream* stream) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(!stream->Queued());
@ -930,7 +802,7 @@ void Http3Session::QueueStream(Http3StreamBase* stream) {
void Http3Session::ProcessPending() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
Http3StreamBase* stream;
Http3Stream* stream;
while ((stream = mQueuedStreams.PopFront())) {
LOG3(("Http3Session::ProcessPending %p stream %p woken from queue.", this,
stream));
@ -941,18 +813,18 @@ void Http3Session::ProcessPending() {
MaybeResumeSend();
}
static void RemoveStreamFromQueue(Http3StreamBase* aStream,
nsDeque<Http3StreamBase>& queue) {
static void RemoveStreamFromQueue(Http3Stream* aStream,
nsDeque<Http3Stream>& queue) {
size_t size = queue.GetSize();
for (size_t count = 0; count < size; ++count) {
Http3StreamBase* stream = queue.PopFront();
Http3Stream* stream = queue.PopFront();
if (stream != aStream) {
queue.Push(stream);
}
}
}
void Http3Session::RemoveStreamFromQueues(Http3StreamBase* aStream) {
void Http3Session::RemoveStreamFromQueues(Http3Stream* aStream) {
RemoveStreamFromQueue(aStream, mReadyForWrite);
RemoveStreamFromQueue(aStream, mQueuedStreams);
mSlowConsumersReadyForRead.RemoveElement(aStream);
@ -964,7 +836,7 @@ void Http3Session::RemoveStreamFromQueues(Http3StreamBase* aStream) {
nsresult Http3Session::TryActivating(
const nsACString& aMethod, const nsACString& aScheme,
const nsACString& aAuthorityHeader, const nsACString& aPath,
const nsACString& aHeaders, uint64_t* aStreamId, Http3StreamBase* aStream) {
const nsACString& aHeaders, uint64_t* aStreamId, Http3Stream* aStream) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(*aStreamId == UINT64_MAX);
@ -991,19 +863,9 @@ nsresult Http3Session::TryActivating(
}
}
nsresult rv = NS_OK;
RefPtr<Http3Stream> httpStream = aStream->GetHttp3Stream();
if (httpStream) {
rv = mHttp3Connection->Fetch(
aMethod, aScheme, aAuthorityHeader, aPath, aHeaders, aStreamId,
httpStream->PriorityUrgency(), httpStream->PriorityIncremental());
} else {
MOZ_RELEASE_ASSERT(aStream->GetHttp3WebTransportSession(),
"It must be a WebTransport session");
rv = mHttp3Connection->CreateWebTransport(aAuthorityHeader, aPath, aHeaders,
aStreamId);
}
nsresult rv = mHttp3Connection->Fetch(
aMethod, aScheme, aAuthorityHeader, aPath, aHeaders, aStreamId,
aStream->PriorityUrgency(), aStream->PriorityIncremental());
if (NS_FAILED(rv)) {
LOG(("Http3Session::TryActivating returns error=0x%" PRIx32 "[stream=%p, "
"this=%p]",
@ -1077,15 +939,12 @@ nsresult Http3Session::SendRequestBody(uint64_t aStreamId, const char* buf,
void Http3Session::ResetRecvd(uint64_t aStreamId, uint64_t aError) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
RefPtr<Http3StreamBase> stream = mStreamIdHash.Get(aStreamId);
RefPtr<Http3Stream> stream = mStreamIdHash.Get(aStreamId);
if (!stream) {
return;
}
RefPtr<Http3Stream> httpStream = stream->GetHttp3Stream();
MOZ_RELEASE_ASSERT(httpStream, "This must be a Http3Stream");
httpStream->SetRecvdReset();
stream->SetRecvdReset();
// We only handle some of Http3 error as epecial, the rest are just equivalent
// to cancel.
@ -1093,17 +952,17 @@ void Http3Session::ResetRecvd(uint64_t aStreamId, uint64_t aError) {
// We will restart the request and the alt-svc will be removed
// automatically.
// Also disable http3 we want http1.1.
httpStream->Transaction()->DisableHttp3(false);
httpStream->Transaction()->DisableSpdy();
stream->Transaction()->DisableHttp3(false);
stream->Transaction()->DisableSpdy();
CloseStream(stream, NS_ERROR_NET_RESET);
} else if (aError == HTTP3_APP_ERROR_REQUEST_REJECTED) {
// This request was rejected because server is probably busy or going away.
// We can restart the request using alt-svc. Without calling
// DoNotRemoveAltSvc the alt-svc route will be removed.
httpStream->Transaction()->DoNotRemoveAltSvc();
stream->Transaction()->DoNotRemoveAltSvc();
CloseStream(stream, NS_ERROR_NET_RESET);
} else {
if (httpStream->RecvdData()) {
if (stream->RecvdData()) {
CloseStream(stream, NS_ERROR_NET_PARTIAL_TRANSFER);
} else {
CloseStream(stream, NS_ERROR_NET_INTERRUPT);
@ -1220,14 +1079,14 @@ nsresult Http3Session::SendData(nsIUDPSocket* socket) {
// to let the error be handled).
nsresult rv = NS_OK;
Http3StreamBase* stream = nullptr;
Http3Stream* stream = nullptr;
// Step 1)
while (CanSandData() && (stream = mReadyForWrite.PopFront())) {
LOG(("Http3Session::SendData call ReadSegments from stream=%p [this=%p]",
stream, this));
rv = stream->ReadSegments();
rv = stream->ReadSegments(nullptr);
// on stream error we return earlier to let the error be handled.
if (NS_FAILED(rv)) {
@ -1262,7 +1121,7 @@ nsresult Http3Session::SendData(nsIUDPSocket* socket) {
return rv;
}
void Http3Session::StreamReadyToWrite(Http3StreamBase* aStream) {
void Http3Session::StreamReadyToWrite(Http3Stream* aStream) {
MOZ_ASSERT(aStream);
mReadyForWrite.Push(aStream);
if (CanSandData() && mConnection) {
@ -1281,11 +1140,11 @@ nsresult Http3Session::ProcessSlowConsumers() {
return NS_OK;
}
RefPtr<Http3StreamBase> slowConsumer =
mSlowConsumersReadyForRead.ElementAt(0);
RefPtr<Http3Stream> slowConsumer = mSlowConsumersReadyForRead.ElementAt(0);
mSlowConsumersReadyForRead.RemoveElementAt(0);
nsresult rv = ProcessTransactionRead(slowConsumer);
uint32_t countRead = 0;
nsresult rv = ProcessTransactionRead(slowConsumer, &countRead);
return rv;
}
@ -1467,7 +1326,7 @@ void Http3Session::CloseTransaction(nsAHttpTransaction* aTransaction,
// Generally this arrives as a cancel event from the connection manager.
// need to find the stream and call CloseStream() on it.
RefPtr<Http3StreamBase> stream = mStreamTransactionHash.Get(aTransaction);
RefPtr<Http3Stream> stream = mStreamTransactionHash.Get(aTransaction);
if (!stream) {
LOG3(("Http3Session::CloseTransaction %p %p 0x%" PRIx32 " - not found.",
this, aTransaction, static_cast<uint32_t>(aResult)));
@ -1484,15 +1343,13 @@ void Http3Session::CloseTransaction(nsAHttpTransaction* aTransaction,
}
}
void Http3Session::CloseStream(Http3StreamBase* aStream, nsresult aResult) {
void Http3Session::CloseStream(Http3Stream* aStream, nsresult aResult) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
RefPtr<Http3Stream> httpStream = aStream->GetHttp3Stream();
if (httpStream && !httpStream->RecvdFin() && !httpStream->RecvdReset() &&
httpStream->HasStreamId()) {
mHttp3Connection->CancelFetch(httpStream->StreamId(),
if (!aStream->RecvdFin() && !aStream->RecvdReset() &&
(aStream->HasStreamId())) {
mHttp3Connection->CancelFetch(aStream->StreamId(),
HTTP3_APP_ERROR_REQUEST_CANCELLED);
}
aStream->Close(aResult);
if (aStream->HasStreamId()) {
// We know the transaction reusing an idle connection has succeeded or
@ -1523,9 +1380,7 @@ void Http3Session::CloseStream(Http3StreamBase* aStream, nsresult aResult) {
}
RemoveStreamFromQueues(aStream);
mStreamTransactionHash.Remove(aStream->Transaction());
mWebTransportSessions.RemoveElement(aStream);
if ((mShouldClose || mGoawayReceived) &&
(!mStreamTransactionHash.Count() || !mWebTransportSessions.IsEmpty())) {
if ((mShouldClose || mGoawayReceived) && !mStreamTransactionHash.Count()) {
MOZ_ASSERT(!IsClosing());
Close(NS_OK);
}
@ -1538,20 +1393,6 @@ nsresult Http3Session::TakeTransport(nsISocketTransport**,
return NS_ERROR_UNEXPECTED;
}
Http3WebTransportSession* Http3Session::GetWebTransportSession(
nsAHttpTransaction* aTransaction) {
RefPtr<Http3StreamBase> stream = mStreamTransactionHash.Get(aTransaction);
if (!stream || !stream->GetHttp3WebTransportSession()) {
MOZ_ASSERT(false, "There must be a stream");
return nullptr;
}
RemoveStreamFromQueues(stream);
mStreamTransactionHash.Remove(aTransaction);
mWebTransportSessions.AppendElement(stream);
return stream->GetHttp3WebTransportSession();
}
bool Http3Session::IsPersistent() { return true; }
void Http3Session::DontReuse() {
@ -1580,10 +1421,7 @@ void Http3Session::TopBrowsingContextIdChanged(uint64_t id) {
mCurrentTopBrowsingContextId = id;
for (const auto& stream : mStreamTransactionHash.Values()) {
RefPtr<Http3Stream> httpStream = stream->GetHttp3Stream();
if (httpStream) {
httpStream->TopBrowsingContextIdChanged(id);
}
stream->TopBrowsingContextIdChanged(id);
}
}
@ -1621,7 +1459,7 @@ void Http3Session::TransactionHasDataToWrite(nsAHttpTransaction* caller) {
// a trapped signal from the http transaction to the connection that
// it is no longer blocked on read.
RefPtr<Http3StreamBase> stream = mStreamTransactionHash.Get(caller);
RefPtr<Http3Stream> stream = mStreamTransactionHash.Get(caller);
if (!stream) {
LOG3(("Http3Session::TransactionHasDataToWrite %p caller %p not found",
this, caller));
@ -1652,7 +1490,7 @@ void Http3Session::TransactionHasDataToRecv(nsAHttpTransaction* caller) {
// a signal from the http transaction to the connection that it will consume
// more
RefPtr<Http3StreamBase> stream = mStreamTransactionHash.Get(caller);
RefPtr<Http3Stream> stream = mStreamTransactionHash.Get(caller);
if (!stream) {
LOG3(("Http3Session::TransactionHasDataToRecv %p caller %p not found", this,
caller));
@ -1664,7 +1502,7 @@ void Http3Session::TransactionHasDataToRecv(nsAHttpTransaction* caller) {
ConnectSlowConsumer(stream);
}
void Http3Session::ConnectSlowConsumer(Http3StreamBase* stream) {
void Http3Session::ConnectSlowConsumer(Http3Stream* stream) {
LOG3(("Http3Session::ConnectSlowConsumer %p 0x%" PRIx64 "\n", this,
stream->StreamId()));
mSlowConsumersReadyForRead.AppendElement(stream);
@ -2058,29 +1896,4 @@ nsresult Http3Session::GetTransactionTLSSocketControl(
PRIntervalTime Http3Session::LastWriteTime() { return mLastWriteTime; }
void Http3Session::WebTransportNegotiationDone() {
for (size_t i = 0; i < mWaitingForWebTransportNegotiation.Length(); ++i) {
if (mWaitingForWebTransportNegotiation[i]) {
mReadyForWrite.Push(mWaitingForWebTransportNegotiation[i]);
}
}
mWaitingForWebTransportNegotiation.Clear();
}
//=========================================================================
// WebTransport
//=========================================================================
nsresult Http3Session::CloseWebTransport(uint64_t aSessionId, uint32_t aError,
const nsACString& aMessage) {
return mHttp3Connection->CloseWebTransport(aSessionId, aError, aMessage);
}
nsresult Http3Session::CreateWebTransportStream(
uint64_t aSessionId, WebTransportStreamType aStreamType,
uint64_t* aStreamId) {
return mHttp3Connection->CreateWebTransportStream(aSessionId, aStreamType,
aStreamId);
}
} // namespace mozilla::net

View File

@ -19,89 +19,10 @@
#include "mozilla/WeakPtr.h"
#include "nsDeque.h"
/*
* WebTransport
*
* Http3Session and the underlying neqo code support multiplexing of multiple
* WebTransport and multiplexing WebTransport sessions with regular HTTP
* traffic. Whether WebTransport sessions are polled, will be controlled by the
* nsHttpConnectionMgr.
*
* WebTransport support is negotiated using HTTP/3 setting. Before the settings
* are available all WebTransport transactions are queued in
* mWaitingForWebTransportNegotiation. The information on whether WebTransport
* is supported is received via an HTTP/3 event. The event is
* Http3Event::Tag::WebTransport with the value
* WebTransportEventExternal::Tag::Negotiated that can be true or false. If
* the WebTransport feature has been negotiated, queued transactions will be
* activated otherwise they will be canceled(i.e. WebTransportNegotiationDone).
*
* The lifetime of a WebTransport session
*
* A WebTransport lifetime consists of 2 parts:
* - WebTransport session setup
* - WebTransport session active time
*
* WebTransport session setup:
* A WebTransport session uses a regular HTTP request for negotiation.
* Therefore when a new WebTransport is started a nsHttpChannel and the
* corresponding nsHttpTransaction are created. The nsHttpTransaction is
* dispatched to a Http3Session and after the
* WebTransportEventExternal::Tag::Negotiated event it behaves almost the same
* as a regular transaction, e.g. it is added to mStreamTransactionHash and
* mStreamIdHash. For activating the session NeqoHttp3Conn::CreateWebTransport
* is called instead of NeqoHttp3Conn::Fetch(this is called for the regular
* HTTP requests). In this phase, the WebTransport session is canceled in the
* same way a regular request is canceled, by canceling the corresponding
* nsHttpChannel. If HTTP/3 connection is closed in this phase the
* corresponding nsHttpTransaction is canceled and this may cause the
* transaction to be restarted (this is the existing restart logic) or the
* error is propagated to the nsHttpChannel and its listener(via OnStartRequest
* and OnStopRequest as the regular HTTP request).
* The phase ends when a connection breaks or when the event
* Http3Event::Tag::WebTransport with the value
* WebTransportEventExternal::Tag::Session is received. The parameter
* aData(from NeqoHttp3Conn::GetEvent) contain the HTTP head of the response.
* The headers may be:
* - failed code, i.e. anything except 200. In this case, the nsHttpTransaction
* behaves the same as a normal HTTP request and the nsHttpChannel listener
* will be informed via OnStartRequest and OnStopRequest calls.
* - success code, i.e. 200. The code will be propagated to the
* nsHttpTransaction. The transaction will parse the header and call
* Http3Session::GetWebTransportSession. The function transfers WebTransport
* session into the next phase:
* - Removes nsHttpTransaction from mStreamTransactionHash.
* - Adds the stream to mWebTransportSessions
* - The nsHttpTransaction supplies Http3WebTransportSession to the
* WebTransportSessionProxy and vice versa.
* TODO remove this circular referencing.
*
* WebTransport session active time:
* During this phase the following actions are possible:
* - Cancelling a WebTransport session by the application:
* The application calls Http3WebTransportSession::CloseSession. This
* transfers Http3WebTransportSession into the CLOSE_PENDING state and calls
* Http3Session::ConnectSlowConsumer to add itself to the ready for reading
* queue. Consequently, the Http3Session will call
* Http3WebTransportSession::WriteSegments and
* Http3Session::CloseWebTransport will be called to send the closing signal
* to the peer. After this, the Http3WebTransportSession is in the state DONE
* and it will be removed from the Http3Session(the CloseStream function
* takes care of this).
* - The peer sending a session closing signal:
* Http3Session will receive a Http3Event::Tag::WebTransport event with value
* WebTransportEventExternal::Tag::SessionClosed. The
* Http3WebTransportSession::OnSessionClosed function for the corresponding
* stream wil be called. The function will inform the corresponding
* WebTransportSessionProxy by calling OnSessionClosed function. The
* Http3WebTransportSession is in the state DONE and will be removed from the
* Http3Session(the CloseStream function takes care of this).
*/
namespace mozilla::net {
class HttpConnectionUDP;
class Http3StreamBase;
class Http3Stream;
class QuicSocketControl;
// IID for the Http3Session interface
@ -137,13 +58,11 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
bool CanReuse();
// The following functions are used by Http3Stream and
// Http3WebTransportSession:
// The folowing functions are used by Http3Stream:
nsresult TryActivating(const nsACString& aMethod, const nsACString& aScheme,
const nsACString& aAuthorityHeader,
const nsACString& aPath, const nsACString& aHeaders,
uint64_t* aStreamId, Http3StreamBase* aStream);
// The folowing functions are used by Http3Stream:
uint64_t* aStreamId, Http3Stream* aStream);
void CloseSendingSide(uint64_t aStreamId);
nsresult SendRequestBody(uint64_t aStreamId, const char* buf, uint32_t count,
uint32_t* countRead);
@ -152,13 +71,7 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
nsresult ReadResponseData(uint64_t aStreamId, char* aBuf, uint32_t aCount,
uint32_t* aCountWritten, bool* aFin);
// The folowing functions are used by Http3WebTransportSession:
nsresult CloseWebTransport(uint64_t aSessionId, uint32_t aError,
const nsACString& aMessage);
nsresult CreateWebTransportStream(uint64_t aSessionId,
WebTransportStreamType aStreamType,
uint64_t* aStreamId);
void CloseStream(Http3StreamBase* aStream, nsresult aResult);
void CloseStream(Http3Stream* aStream, nsresult aResult);
void SetCleanShutdown(bool aCleanShutdown) {
mCleanShutdown = aCleanShutdown;
@ -191,8 +104,6 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
nsresult SendPriorityUpdateFrame(uint64_t aStreamId, uint8_t aPriorityUrgency,
bool aPriorityIncremental);
void ConnectSlowConsumer(Http3StreamBase* stream);
private:
~Http3Session();
@ -206,22 +117,23 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
void ProcessInput(nsIUDPSocket* socket);
nsresult ProcessEvents();
nsresult ProcessTransactionRead(uint64_t stream_id);
nsresult ProcessTransactionRead(Http3StreamBase* stream);
nsresult ProcessTransactionRead(uint64_t stream_id, uint32_t* countWritten);
nsresult ProcessTransactionRead(Http3Stream* stream, uint32_t* countWritten);
nsresult ProcessSlowConsumers();
void ConnectSlowConsumer(Http3Stream* stream);
void SetupTimer(uint64_t aTimeout);
void ResetRecvd(uint64_t aStreamId, uint64_t aError);
void QueueStream(Http3StreamBase* stream);
void RemoveStreamFromQueues(Http3StreamBase*);
void QueueStream(Http3Stream* stream);
void RemoveStreamFromQueues(Http3Stream*);
void ProcessPending();
void CallCertVerification(Maybe<nsCString> aEchPublicName);
void SetSecInfo();
void StreamReadyToWrite(Http3StreamBase* aStream);
void StreamReadyToWrite(Http3Stream* aStream);
void MaybeResumeSend();
void CloseConnectionTelemetry(CloseError& aError, bool aClosing);
@ -238,13 +150,13 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
RefPtr<NeqoHttp3Conn> mHttp3Connection;
RefPtr<nsAHttpConnection> mConnection;
nsRefPtrHashtable<nsUint64HashKey, Http3StreamBase> mStreamIdHash;
nsRefPtrHashtable<nsPtrHashKey<nsAHttpTransaction>, Http3StreamBase>
nsRefPtrHashtable<nsUint64HashKey, Http3Stream> mStreamIdHash;
nsRefPtrHashtable<nsPtrHashKey<nsAHttpTransaction>, Http3Stream>
mStreamTransactionHash;
nsDeque<Http3StreamBase> mReadyForWrite;
nsTArray<RefPtr<Http3StreamBase>> mSlowConsumersReadyForRead;
nsDeque<Http3StreamBase> mQueuedStreams;
nsDeque<Http3Stream> mReadyForWrite;
nsTArray<RefPtr<Http3Stream>> mSlowConsumersReadyForRead;
nsDeque<Http3Stream> mQueuedStreams;
enum State {
INITIALIZING,
@ -286,10 +198,10 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
uint64_t mTransactionCount = 0;
// The stream(s) that we are getting 0RTT data from.
nsTArray<WeakPtr<Http3StreamBase>> m0RTTStreams;
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<Http3StreamBase>> mCannotDo0RTTStreams;
nsTArray<WeakPtr<Http3Stream>> mCannotDo0RTTStreams;
// The following variables are needed for telemetry.
TimeStamp mConnectionIdleStart;
@ -313,18 +225,6 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
PRIntervalTime mLastWriteTime = 0;
nsCOMPtr<nsINetAddr> mNetAddr;
enum WebTransportNegotiation { DISABLED, NEGOTIATING, FAILED, SUCCEEDED };
WebTransportNegotiation mWebTransportNegotiationStatus{
WebTransportNegotiation::DISABLED};
nsTArray<WeakPtr<Http3StreamBase>> mWaitingForWebTransportNegotiation;
// 1795854 implement the case when WebTransport is not supported.
// Also, implement the case when the HTTP/3 session fails before settings
// are exchanged.
void WebTransportNegotiationDone();
nsTArray<RefPtr<Http3StreamBase>> mWebTransportSessions;
};
NS_DEFINE_STATIC_IID_ACCESSOR(Http3Session, NS_HTTP3SESSION_IID);

View File

@ -26,7 +26,8 @@ namespace net {
Http3Stream::Http3Stream(nsAHttpTransaction* httpTransaction,
Http3Session* session, const ClassOfService& cos,
uint64_t bcId)
: Http3StreamBase(httpTransaction, session),
: mSession(session),
mTransaction(httpTransaction),
mCurrentTopBrowsingContextId(bcId) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG3(("Http3Stream::Http3Stream [this=%p]", this));
@ -330,7 +331,7 @@ nsresult Http3Stream::OnWriteSegment(char* buf, uint32_t count,
return rv;
}
nsresult Http3Stream::ReadSegments() {
nsresult Http3Stream::ReadSegments(nsAHttpSegmentReader* reader) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
if (mRecvState == RECV_DONE) {
@ -420,7 +421,8 @@ nsresult Http3Stream::ReadSegments() {
return rv;
}
nsresult Http3Stream::WriteSegments() {
nsresult Http3Stream::WriteSegments(nsAHttpSegmentWriter* writer,
uint32_t count, uint32_t* countWritten) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("Http3Stream::WriteSegments [this=%p]", this));
nsresult rv = NS_OK;
@ -429,9 +431,9 @@ nsresult Http3Stream::WriteSegments() {
do {
mSocketInCondition = NS_OK;
countWrittenSingle = 0;
rv = mTransaction->WriteSegmentsAgain(
this, nsIOService::gDefaultSegmentSize, &countWrittenSingle, &again);
rv = mTransaction->WriteSegmentsAgain(this, count, &countWrittenSingle,
&again);
*countWritten += countWrittenSingle;
LOG(("Http3Stream::WriteSegments rv=0x%" PRIx32
" countWrittenSingle=%" PRIu32 " socketin=%" PRIx32 " [this=%p]",
static_cast<uint32_t>(rv), countWrittenSingle,

View File

@ -8,7 +8,6 @@
#include "nsAHttpTransaction.h"
#include "ARefBase.h"
#include "Http3StreamBase.h"
#include "mozilla/WeakPtr.h"
#include "nsIClassOfService.h"
@ -19,33 +18,37 @@ class Http3Session;
class Http3Stream final : public nsAHttpSegmentReader,
public nsAHttpSegmentWriter,
public Http3StreamBase {
public SupportsWeakPtr,
public ARefBase {
public:
NS_DECL_NSAHTTPSEGMENTREADER
NS_DECL_NSAHTTPSEGMENTWRITER
// for RefPtr
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http3Stream, override)
NS_INLINE_DECL_REFCOUNTING(Http3Stream, override)
Http3Stream(nsAHttpTransaction*, Http3Session*, const ClassOfService&,
uint64_t);
Http3WebTransportSession* GetHttp3WebTransportSession() override {
return nullptr;
}
Http3Stream* GetHttp3Stream() override { return this; }
bool HasStreamId() const { return mStreamId != UINT64_MAX; }
uint64_t StreamId() const { return mStreamId; }
nsresult TryActivating();
void TopBrowsingContextIdChanged(uint64_t id);
[[nodiscard]] nsresult ReadSegments() override;
[[nodiscard]] nsresult WriteSegments() override;
[[nodiscard]] nsresult ReadSegments(nsAHttpSegmentReader*);
[[nodiscard]] nsresult WriteSegments(nsAHttpSegmentWriter*, uint32_t,
uint32_t*);
bool Done() const override { return mRecvState == RECV_DONE; }
void SetQueued(bool aStatus) { mQueued = aStatus; }
bool Queued() const { return mQueued; }
void Close(nsresult aResult) override;
bool Done() const { return mRecvState == RECV_DONE; }
void Close(nsresult aResult);
bool RecvdData() const { return mDataReceived; }
nsAHttpTransaction* Transaction() { return mTransaction; }
bool RecvdFin() const { return mFin; }
bool RecvdReset() const { return mResetRecv; }
void SetRecvdReset() { mResetRecv = true; }
@ -53,11 +56,11 @@ class Http3Stream final : public nsAHttpSegmentReader,
void StopSending();
void SetResponseHeaders(nsTArray<uint8_t>& aResponseHeaders, bool fin,
bool interim) override;
bool interim);
// Mirrors nsAHttpTransaction
bool Do0RTT() override;
nsresult Finish0RTT(bool aRestart) override;
bool Do0RTT();
nsresult Finish0RTT(bool aRestart);
uint8_t PriorityUrgency();
bool PriorityIncremental();
@ -135,7 +138,11 @@ class Http3Stream final : public nsAHttpSegmentReader,
RECV_DONE
} mRecvState{BEFORE_HEADERS};
uint64_t mStreamId{UINT64_MAX};
Http3Session* mSession;
RefPtr<nsAHttpTransaction> mTransaction;
nsCString mFlatHttpRequestHeaders;
bool mQueued{false};
bool mDataReceived{false};
bool mResetRecv{false};
nsTArray<uint8_t> mFlatResponseHeaders;

View File

@ -1,60 +0,0 @@
/* -*- Mode: C++; tab-width: 8; 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 mozilla_net_Http3StreamBase_h
#define mozilla_net_Http3StreamBase_h
#include "nsAHttpTransaction.h"
#include "ARefBase.h"
#include "mozilla/WeakPtr.h"
#include "nsIClassOfService.h"
namespace mozilla::net {
class Http3Session;
class Http3Stream;
class Http3WebTransportSession;
class Http3StreamBase : public SupportsWeakPtr, public ARefBase {
public:
Http3StreamBase(nsAHttpTransaction* trans, Http3Session* session)
: mTransaction(trans), mSession(session) {}
virtual Http3WebTransportSession* GetHttp3WebTransportSession() = 0;
virtual Http3Stream* GetHttp3Stream() = 0;
bool HasStreamId() const { return mStreamId != UINT64_MAX; }
uint64_t StreamId() const { return mStreamId; }
[[nodiscard]] virtual nsresult ReadSegments() = 0;
[[nodiscard]] virtual nsresult WriteSegments() = 0;
virtual bool Done() const = 0;
virtual void SetResponseHeaders(nsTArray<uint8_t>& aResponseHeaders, bool fin,
bool interim) = 0;
void SetQueued(bool aStatus) { mQueued = aStatus; }
bool Queued() const { return mQueued; }
virtual void Close(nsresult aResult) = 0;
nsAHttpTransaction* Transaction() { return mTransaction; }
// Mirrors nsAHttpTransaction
virtual bool Do0RTT() { return false; }
virtual nsresult Finish0RTT(bool aRestart) { return NS_OK; }
protected:
~Http3StreamBase() = default;
uint64_t mStreamId{UINT64_MAX};
RefPtr<nsAHttpTransaction> mTransaction;
Http3Session* mSession;
bool mQueued{false};
};
} // namespace mozilla::net
#endif // mozilla_net_Http3StreamBase_h

View File

@ -1,342 +0,0 @@
/* -*- Mode: C++; tab-width: 8; 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/. */
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include "Http3WebTransportSession.h"
namespace mozilla::net {
Http3WebTransportSession::Http3WebTransportSession(nsAHttpTransaction* trans,
Http3Session* aHttp3Session)
: Http3StreamBase(trans, aHttp3Session) {}
nsresult Http3WebTransportSession::ReadSegments() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
if ((mRecvState == RECV_DONE) || (mRecvState == ACTIVE) ||
(mRecvState == CLOSE_PENDING)) {
// Don't transmit any request frames if the peer cannot respond or respone
// is already done.
LOG3((
"Http3WebTransportSession %p ReadSegments request stream aborted due to"
" response side closure\n",
this));
return NS_ERROR_ABORT;
}
nsresult rv = NS_OK;
uint32_t transactionBytes;
bool again = true;
do {
transactionBytes = 0;
rv = mSocketOutCondition = NS_OK;
LOG(("Http3WebTransportSession::ReadSegments state=%d [this=%p]",
mSendState, this));
switch (mSendState) {
case PREPARING_HEADERS: {
rv = mTransaction->ReadSegmentsAgain(
this, nsIOService::gDefaultSegmentSize, &transactionBytes, &again);
} break;
case WAITING_TO_ACTIVATE: {
// A transaction that had already generated its headers before it was
// queued at the session level (due to concurrency concerns) may not
// call onReadSegment off the ReadSegments() stack above.
LOG3(
("Http3WebTransportSession %p ReadSegments forcing OnReadSegment "
"call\n",
this));
uint32_t wasted = 0;
nsresult rv2 = OnReadSegment("", 0, &wasted);
LOG3((" OnReadSegment returned 0x%08" PRIx32,
static_cast<uint32_t>(rv2)));
} break;
default:
transactionBytes = 0;
rv = NS_OK;
break;
}
LOG(("Http3WebTransportSession::ReadSegments rv=0x%" PRIx32
" read=%u sock-cond=%" PRIx32 " again=%d [this=%p]",
static_cast<uint32_t>(rv), transactionBytes,
static_cast<uint32_t>(mSocketOutCondition), again, this));
// XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
if (rv == NS_BASE_STREAM_CLOSED && !mTransaction->IsDone()) {
rv = NS_OK;
transactionBytes = 0;
}
if (NS_FAILED(rv)) {
// if the transaction didn't want to write any more data, then
// wait for the transaction to call ResumeSend.
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
rv = NS_OK;
}
again = false;
} else if (NS_FAILED(mSocketOutCondition)) {
if (mSocketOutCondition != NS_BASE_STREAM_WOULD_BLOCK) {
rv = mSocketOutCondition;
}
again = false;
} else if (!transactionBytes) {
mTransaction->OnTransportStatus(nullptr, NS_NET_STATUS_WAITING_FOR, 0);
mSendState = SEND_DONE;
rv = NS_OK;
again = false;
}
// write more to the socket until error or end-of-request...
} while (again && gHttpHandler->Active());
return rv;
}
bool Http3WebTransportSession::ConsumeHeaders(const char* buf, uint32_t avail,
uint32_t* countUsed) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG3(("Http3WebTransportSession::ConsumeHeaders %p avail=%u.", this, avail));
mFlatHttpRequestHeaders.Append(buf, avail);
// We can use the simple double crlf because firefox is the
// only client we are parsing
int32_t endHeader = mFlatHttpRequestHeaders.Find("\r\n\r\n");
if (endHeader == kNotFound) {
// We don't have all the headers yet
LOG3(
("Http3WebTransportSession::ConsumeHeaders %p "
"Need more header bytes. Len = %zu",
this, mFlatHttpRequestHeaders.Length()));
*countUsed = avail;
return false;
}
uint32_t oldLen = mFlatHttpRequestHeaders.Length();
mFlatHttpRequestHeaders.SetLength(endHeader + 2);
*countUsed = avail - (oldLen - endHeader) + 4;
return true;
}
nsresult Http3WebTransportSession::TryActivating() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("Http3WebTransportSession::TryActivating [this=%p]", this));
nsHttpRequestHead* head = mTransaction->RequestHead();
nsAutoCString host;
nsresult rv = head->GetHeader(nsHttp::Host, host);
if (NS_FAILED(rv)) {
MOZ_ASSERT(false);
return rv;
}
nsAutoCString path;
head->Path(path);
return mSession->TryActivating(""_ns, ""_ns, host, path,
mFlatHttpRequestHeaders, &mStreamId, this);
}
nsresult Http3WebTransportSession::OnReadSegment(const char* buf,
uint32_t count,
uint32_t* countRead) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("Http3WebTransportSession::OnReadSegment count=%u state=%d [this=%p]",
count, mSendState, this));
nsresult rv = NS_OK;
switch (mSendState) {
case PREPARING_HEADERS: {
if (!ConsumeHeaders(buf, count, countRead)) {
break;
}
mSendState = WAITING_TO_ACTIVATE;
}
[[fallthrough]];
case WAITING_TO_ACTIVATE:
rv = TryActivating();
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
LOG3(
("Http3WebTransportSession::OnReadSegment %p cannot activate now. "
"queued.\n",
this));
break;
}
if (NS_FAILED(rv)) {
LOG3(
("Http3WebTransportSession::OnReadSegment %p cannot activate "
"error=0x%" PRIx32 ".",
this, static_cast<uint32_t>(rv)));
break;
}
// Successfully activated.
mTransaction->OnTransportStatus(nullptr, NS_NET_STATUS_SENDING_TO, 0);
mSendState = SEND_DONE;
break;
default:
MOZ_ASSERT(false, "We are done sending this request!");
rv = NS_ERROR_UNEXPECTED;
break;
}
mSocketOutCondition = rv;
return mSocketOutCondition;
}
nsresult Http3WebTransportSession::WriteSegments() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("Http3WebTransportSession::WriteSegments [this=%p]", this));
nsresult rv = NS_OK;
uint32_t countWrittenSingle = 0;
bool again = true;
if (mRecvState == CLOSE_PENDING) {
mSession->CloseWebTransport(mStreamId, mStatus, mReason);
mRecvState = RECV_DONE;
// This will closed the steam because the stream is Done().
return NS_OK;
}
do {
mSocketInCondition = NS_OK;
countWrittenSingle = 0;
rv = mTransaction->WriteSegmentsAgain(
this, nsIOService::gDefaultSegmentSize, &countWrittenSingle, &again);
LOG(("Http3WebTransportSession::WriteSegments rv=0x%" PRIx32
" countWrittenSingle=%" PRIu32 " socketin=%" PRIx32 " [this=%p]",
static_cast<uint32_t>(rv), countWrittenSingle,
static_cast<uint32_t>(mSocketInCondition), this));
if (mTransaction->IsDone()) {
// An HTTP transaction used for setting up a WebTransport session will
// receive only response headers and afterward, it will be marked as
// done. At this point, the session negotiation has finished and the
// WebTransport session transfers into the ACTIVE state.
mRecvState = ACTIVE;
}
if (NS_FAILED(rv)) {
// if the transaction didn't want to take any more data, then
// wait for the transaction to call ResumeRecv.
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
rv = NS_OK;
}
again = false;
} else if (NS_FAILED(mSocketInCondition)) {
if (mSocketInCondition != NS_BASE_STREAM_WOULD_BLOCK) {
rv = mSocketInCondition;
}
again = false;
}
// read more from the socket until error...
} while (again && gHttpHandler->Active());
return rv;
}
void Http3WebTransportSession::SetResponseHeaders(
nsTArray<uint8_t>& aResponseHeaders, bool fin, bool interim) {
MOZ_ASSERT(mRecvState == BEFORE_HEADERS ||
mRecvState == READING_INTERIM_HEADERS);
mFlatResponseHeaders.AppendElements(aResponseHeaders);
mRecvState = (interim) ? READING_INTERIM_HEADERS : READING_HEADERS;
}
nsresult Http3WebTransportSession::OnWriteSegment(char* buf, uint32_t count,
uint32_t* countWritten) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("Http3WebTransportSession::OnWriteSegment [this=%p, state=%d", this,
mRecvState));
nsresult rv = NS_OK;
switch (mRecvState) {
case BEFORE_HEADERS: {
*countWritten = 0;
rv = NS_BASE_STREAM_WOULD_BLOCK;
} break;
case READING_HEADERS:
case READING_INTERIM_HEADERS: {
// SetResponseHeaders should have been previously called.
MOZ_ASSERT(!mFlatResponseHeaders.IsEmpty(), "Headers empty!");
*countWritten = (mFlatResponseHeaders.Length() > count)
? count
: mFlatResponseHeaders.Length();
memcpy(buf, mFlatResponseHeaders.Elements(), *countWritten);
mFlatResponseHeaders.RemoveElementsAt(0, *countWritten);
if (mFlatResponseHeaders.Length() == 0) {
if (mRecvState == READING_INTERIM_HEADERS) {
// neqo makes sure that fin cannot be received before the final
// headers are received.
mRecvState = BEFORE_HEADERS;
} else {
mRecvState = ACTIVE;
}
}
if (*countWritten == 0) {
rv = NS_BASE_STREAM_WOULD_BLOCK;
} else {
mTransaction->OnTransportStatus(nullptr, NS_NET_STATUS_RECEIVING_FROM,
0);
}
} break;
case ACTIVE:
case CLOSE_PENDING:
case RECV_DONE:
rv = NS_ERROR_UNEXPECTED;
}
// Remember the error received from lower layers. A stream pipe may overwrite
// it.
// If rv == NS_OK this will reset mSocketInCondition.
mSocketInCondition = rv;
return rv;
}
void Http3WebTransportSession::Close(nsresult aResult) {
if (mListener) {
mListener->OnSessionClosed(0, ""_ns);
mListener = nullptr;
}
if (mTransaction) {
mTransaction->Close(aResult);
mTransaction = nullptr;
}
mRecvState = RECV_DONE;
}
void Http3WebTransportSession::OnSessionClosed(uint32_t aStatus,
nsACString& aReason) {
MOZ_ASSERT(!mTransaction);
if (mListener) {
mListener->OnSessionClosed(aStatus, aReason);
mListener = nullptr;
}
mRecvState = RECV_DONE;
}
void Http3WebTransportSession::CloseSession(uint32_t aStatus,
nsACString& aReason) {
if ((mRecvState != CLOSE_PENDING) && (mRecvState != RECV_DONE)) {
mStatus = aStatus;
mReason = aReason;
mSession->ConnectSlowConsumer(this);
mRecvState = CLOSE_PENDING;
}
mListener = nullptr;
}
void Http3WebTransportSession::TransactionIsDone(nsresult aResult) {
mTransaction->Close(aResult);
mTransaction = nullptr;
}
} // namespace mozilla::net

View File

@ -1,88 +0,0 @@
/* -*- Mode: C++; tab-width: 8; 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 mozilla_net_Http3WebTransportSession_h
#define mozilla_net_Http3WebTransportSession_h
#include "ARefBase.h"
#include "Http3StreamBase.h"
#include "nsIWebTransport.h"
#include "mozilla/WeakPtr.h"
namespace mozilla::net {
class Http3Session;
// TODO Http3WebTransportSession is very similar to Http3Stream. It should
// be built on top of it with a couple of small changes. The docs will be added
// when this is implemented.
class Http3WebTransportSession final : public Http3StreamBase,
public nsAHttpSegmentWriter,
public nsAHttpSegmentReader {
public:
NS_DECL_NSAHTTPSEGMENTWRITER
NS_DECL_NSAHTTPSEGMENTREADER
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http3WebTransportSession, override)
Http3WebTransportSession(nsAHttpTransaction*, Http3Session*);
Http3WebTransportSession* GetHttp3WebTransportSession() override {
return this;
}
Http3Stream* GetHttp3Stream() override { return nullptr; }
[[nodiscard]] nsresult ReadSegments() override;
[[nodiscard]] nsresult WriteSegments() override;
bool Done() const override { return mRecvState == RECV_DONE; }
void Close(nsresult aResult) override;
void SetResponseHeaders(nsTArray<uint8_t>& aResponseHeaders, bool fin,
bool interim) override;
void SetWebTransportSessionEventListener(
WebTransportSessionEventListener* listener) {
mListener = listener;
}
nsresult TryActivating();
void TransactionIsDone(nsresult aResult);
void CloseSession(uint32_t aStatus, nsACString& aReason);
void OnSessionClosed(uint32_t aStatus, nsACString& aReason);
private:
~Http3WebTransportSession() = default;
bool ConsumeHeaders(const char* buf, uint32_t avail, uint32_t* countUsed);
enum RecvStreamState {
BEFORE_HEADERS,
READING_HEADERS,
READING_INTERIM_HEADERS,
ACTIVE,
CLOSE_PENDING,
RECV_DONE
} mRecvState{BEFORE_HEADERS};
enum SendStreamState {
PREPARING_HEADERS,
WAITING_TO_ACTIVATE,
SEND_DONE
} mSendState{PREPARING_HEADERS};
nsCString mFlatHttpRequestHeaders;
nsTArray<uint8_t> mFlatResponseHeaders;
nsresult mSocketInCondition = NS_ERROR_NOT_INITIALIZED;
nsresult mSocketOutCondition = NS_ERROR_NOT_INITIALIZED;
RefPtr<WebTransportSessionEventListener> mListener;
uint32_t mStatus{0};
nsCString mReason;
};
} // namespace mozilla::net
#endif // mozilla_net_Http3WebTransportSession_h

View File

@ -31,7 +31,6 @@ namespace net {
class nsHttpHandler;
class ASpdySession;
class Http3WebTransportSession;
// 1dcc863e-db90-4652-a1fe-13fea0b54e46
#define HTTPCONNECTIONBASE_IID \
@ -83,11 +82,6 @@ class HttpConnectionBase : public nsSupportsWeakReference {
nsIAsyncInputStream**,
nsIAsyncOutputStream**) = 0;
Http3WebTransportSession* GetWebTransportSession(
nsAHttpTransaction* aTransaction) {
return nullptr;
}
virtual bool UsingSpdy() { return false; }
virtual bool UsingHttp3() { return false; }

View File

@ -889,10 +889,6 @@ void HttpTransactionParent::HandleAsyncAbort() {
bool HttpTransactionParent::GetSupportsHTTP3() { return mSupportsHTTP3; }
void HttpTransactionParent::SetIsForWebTransport(bool SetIsForWebTransport) {
// TODO: bug 1791727
}
// We will need to support this in the socket process (See Bug 1791027)
mozilla::TimeStamp HttpTransactionParent::GetPendingTime() {
return TimeStamp::Now();

View File

@ -165,8 +165,6 @@ class HttpTransactionShell : public nsISupports {
virtual already_AddRefed<nsHttpConnectionInfo> GetConnInfo() const = 0;
virtual bool GetSupportsHTTP3() = 0;
virtual void SetIsForWebTransport(bool aIsForWebTransport) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(HttpTransactionShell, HTTPTRANSACTIONSHELL_IID)
@ -227,8 +225,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(HttpTransactionShell, HTTPTRANSACTIONSHELL_IID)
virtual bool Http2Disabled() const override; \
virtual bool Http3Disabled() const override; \
virtual already_AddRefed<nsHttpConnectionInfo> GetConnInfo() const override; \
virtual bool GetSupportsHTTP3() override; \
virtual void SetIsForWebTransport(bool aIsForWebTransport) override;
virtual bool GetSupportsHTTP3() override;
} // namespace mozilla::net

View File

@ -5,11 +5,11 @@
#ifndef HttpWinUtils_h__
#define HttpWinUtils_h__
class nsHttpChannel;
namespace mozilla {
namespace net {
class nsHttpChannel;
void AddWindowsSSO(nsHttpChannel* channel);
} // namespace net

View File

@ -114,7 +114,6 @@ UNIFIED_SOURCES += [
"Http2StreamWebSocket.cpp",
"Http3Session.cpp",
"Http3Stream.cpp",
"Http3WebTransportSession.cpp",
"HttpAuthUtils.cpp",
"HttpBackgroundChannelChild.cpp",
"HttpBackgroundChannelParent.cpp",

View File

@ -9,7 +9,6 @@
#include "nsHttp.h"
#include "nsISupports.h"
#include "nsAHttpTransaction.h"
#include "Http3WebTransportSession.h"
#include "HttpTrafficAnalyzer.h"
class nsIAsyncInputStream;
@ -107,9 +106,6 @@ class nsAHttpConnection : public nsISupports {
nsIAsyncInputStream**,
nsIAsyncOutputStream**) = 0;
[[nodiscard]] virtual Http3WebTransportSession* GetWebTransportSession(
nsAHttpTransaction* aTransaction) = 0;
// called by a transaction to get the TLS socket control from the socket.
virtual void GetTLSSocketControl(nsISSLSocketControl**) = 0;
@ -182,8 +178,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsAHttpConnection, NS_AHTTPCONNECTION_IID)
[[nodiscard]] nsresult TakeTransport( \
nsISocketTransport**, nsIAsyncInputStream**, nsIAsyncOutputStream**) \
override; \
[[nodiscard]] Http3WebTransportSession* GetWebTransportSession( \
nsAHttpTransaction* aTransaction) override; \
bool IsPersistent() override; \
bool IsReused() override; \
void DontReuse() override; \

View File

@ -34,7 +34,6 @@
#include "nsIStreamListenerTee.h"
#include "nsISeekableStream.h"
#include "nsIProtocolProxyService2.h"
#include "nsIWebTransport.h"
#include "nsCRT.h"
#include "nsMimeTypes.h"
#include "nsNetCID.h"
@ -1342,10 +1341,6 @@ nsresult nsHttpChannel::SetupTransaction() {
mCaps &= ~NS_HTTP_ALLOW_KEEPALIVE;
}
if (mIsForWebTransport) {
mCaps |= NS_HTTP_STICKY_CONNECTION;
}
nsCOMPtr<nsIHttpPushListener> pushListener;
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
NS_GET_IID(nsIHttpPushListener),
@ -1379,7 +1374,6 @@ nsresult nsHttpChannel::SetupTransaction() {
aResult.closeReason());
};
}
mTransaction->SetIsForWebTransport(mIsForWebTransport);
rv = mTransaction->Init(
mCaps, mConnectionInfo, &mRequestHead, mUploadStream, mReqContentLength,
LoadUploadStreamHasHeaders(), GetCurrentEventTarget(), callbacks, this,
@ -1940,10 +1934,6 @@ void nsHttpChannel::ProcessAltService() {
return;
}
if (mIsForWebTransport) {
return;
}
if (!gHttpHandler->AllowAltSvc() || (mCaps & NS_HTTP_DISALLOW_SPDY)) {
return;
}
@ -5802,10 +5792,6 @@ nsHttpChannel::AsyncOpen(nsIStreamListener* aListener) {
ReleaseListeners();
return rv;
}
nsCOMPtr<WebTransportSessionEventListener> wt = do_QueryInterface(listener);
mIsForWebTransport = !!wt;
MOZ_ASSERT(
mLoadInfo->GetSecurityMode() == 0 ||
mLoadInfo->GetInitialSecurityCheckDone() ||
@ -6114,14 +6100,8 @@ nsresult nsHttpChannel::BeginConnect() {
originAttributes, host, port, true);
} else {
#endif
if (mIsForWebTransport) {
connInfo =
new nsHttpConnectionInfo(host, port, "h3"_ns, mUsername, proxyInfo,
originAttributes, isHttps, true, true);
} else {
connInfo = new nsHttpConnectionInfo(host, port, ""_ns, mUsername,
proxyInfo, originAttributes, isHttps);
}
connInfo = new nsHttpConnectionInfo(host, port, ""_ns, mUsername, proxyInfo,
originAttributes, isHttps);
#ifdef FUZZING
}
#endif
@ -6135,8 +6115,7 @@ nsresult nsHttpChannel::BeginConnect() {
RefPtr<AltSvcMapping> mapping;
if (!mConnectionInfo && LoadAllowAltSvc() && // per channel
!mIsForWebTransport && (http2Allowed || http3Allowed) &&
!(mLoadFlags & LOAD_FRESH_CONNECTION) &&
(http2Allowed || http3Allowed) && !(mLoadFlags & LOAD_FRESH_CONNECTION) &&
AltSvcMapping::AcceptableProxy(proxyInfo) &&
(scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) &&
(mapping = gHttpHandler->GetAltServiceMapping(
@ -9798,11 +9777,5 @@ nsHttpChannel::EarlyHint(const nsACString& linkHeader) {
return NS_OK;
}
WebTransportSessionEventListener*
nsHttpChannel::GetWebTransportSessionEventListener() {
nsCOMPtr<WebTransportSessionEventListener> wt = do_QueryInterface(mListener);
return wt;
}
} // namespace net
} // namespace mozilla

View File

@ -267,8 +267,6 @@ class nsHttpChannel final : public HttpBaseChannel,
true>;
[[nodiscard]] RefPtr<ChildEndpointPromise> AttachStreamFilter();
WebTransportSessionEventListener* GetWebTransportSessionEventListener();
private: // used for alternate service validation
RefPtr<TransactionObserver> mTransactionObserver;
@ -846,8 +844,6 @@ class nsHttpChannel final : public HttpBaseChannel,
RefPtr<nsIEarlyHintObserver> mEarlyHintObserver;
Maybe<nsCString> mOpenerCallingScriptLocation;
bool mIsForWebTransport{false};
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpChannel, NS_HTTPCHANNEL_IID)

View File

@ -48,18 +48,17 @@ nsHttpConnectionInfo::nsHttpConnectionInfo(
const nsACString& originHost, int32_t originPort,
const nsACString& npnToken, const nsACString& username,
nsProxyInfo* proxyInfo, const OriginAttributes& originAttributes,
bool endToEndSSL, bool aIsHttp3, bool aWebTransport)
bool endToEndSSL, bool aIsHttp3)
: mRoutedPort(443), mLessThanTls13(false) {
Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes,
endToEndSSL, aIsHttp3, aWebTransport);
endToEndSSL, aIsHttp3);
}
nsHttpConnectionInfo::nsHttpConnectionInfo(
const nsACString& originHost, int32_t originPort,
const nsACString& npnToken, const nsACString& username,
nsProxyInfo* proxyInfo, const OriginAttributes& originAttributes,
const nsACString& routedHost, int32_t routedPort, bool aIsHttp3,
bool aWebTransport)
const nsACString& routedHost, int32_t routedPort, bool aIsHttp3)
: mLessThanTls13(false) {
mEndToEndSSL = true; // so DefaultPort() works
mRoutedPort = routedPort == -1 ? DefaultPort() : routedPort;
@ -69,7 +68,7 @@ nsHttpConnectionInfo::nsHttpConnectionInfo(
mRoutedHost = routedHost;
}
Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes,
true, aIsHttp3, aWebTransport);
true, aIsHttp3);
}
void nsHttpConnectionInfo::Init(const nsACString& host, int32_t port,
@ -77,19 +76,15 @@ void nsHttpConnectionInfo::Init(const nsACString& host, int32_t port,
const nsACString& username,
nsProxyInfo* proxyInfo,
const OriginAttributes& originAttributes,
bool e2eSSL, bool aIsHttp3,
bool aWebTransport) {
bool e2eSSL, bool aIsHttp3) {
LOG(("Init nsHttpConnectionInfo @%p\n", this));
MOZ_RELEASE_ASSERT(!aWebTransport || aIsHttp3);
mUsername = username;
mProxyInfo = proxyInfo;
mEndToEndSSL = e2eSSL;
mUsingConnect = false;
mNPNToken = npnToken;
mIsHttp3 = aIsHttp3;
mWebTransport = aWebTransport;
mOriginAttributes = originAttributes;
mTlsFlags = 0x0;
mIsTrrServiceChannel = false;
@ -145,7 +140,6 @@ void nsHttpConnectionInfo::BuildHashKey() {
// byte 6 is C/. C is for be Conservative
// byte 7 is B/. B is for allowing client certs on an anonymous channel
// byte 8 is F/. F is for indicating a fallback connection
// byte 9 is W/. W is for indicating a webTransport
// Note: when adding/removing fields from this list which do not have
// corresponding data fields on the object itself, you may also need to
// modify RebuildHashKey.
@ -173,10 +167,6 @@ void nsHttpConnectionInfo::BuildHashKey() {
SetHashCharAt('S', HashKeyIndex::EndToEndSSL);
}
if (mWebTransport) {
SetHashCharAt('W', HashKeyIndex::WebTransport);
}
// NOTE: for transparent proxies (e.g., SOCKS) we need to encode the proxy
// info in the hash key (this ensures that we will continue to speak the
// right protocol even if our proxy preferences change).
@ -303,12 +293,12 @@ already_AddRefed<nsHttpConnectionInfo> nsHttpConnectionInfo::Clone() const {
if (mRoutedHost.IsEmpty()) {
clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername,
mProxyInfo, mOriginAttributes,
mEndToEndSSL, mIsHttp3, mWebTransport);
mEndToEndSSL, mIsHttp3);
} else {
MOZ_ASSERT(mEndToEndSSL);
clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername,
mProxyInfo, mOriginAttributes, mRoutedHost,
mRoutedPort, mIsHttp3, mWebTransport);
mRoutedPort, mIsHttp3);
}
// Make sure the anonymous, insecure-scheme, and private flags are transferred
@ -359,10 +349,10 @@ nsHttpConnectionInfo::CloneAndAdoptHTTPSSVCRecord(
mProxyInfo, mOriginAttributes, mEndToEndSSL, isHttp3);
} else {
MOZ_ASSERT(mEndToEndSSL);
clone = new nsHttpConnectionInfo(
mOrigin, mOriginPort, alpn ? Get<0>(*alpn) : EmptyCString(), mUsername,
mProxyInfo, mOriginAttributes, name, port ? *port : mOriginPort,
isHttp3, mWebTransport);
clone = new nsHttpConnectionInfo(mOrigin, mOriginPort,
alpn ? Get<0>(*alpn) : EmptyCString(),
mUsername, mProxyInfo, mOriginAttributes,
name, port ? *port : mOriginPort, isHttp3);
}
// Make sure the anonymous, insecure-scheme, and private flags are transferred
@ -417,7 +407,6 @@ void nsHttpConnectionInfo::SerializeHttpConnectionInfo(
aArgs.isHttp3() = aInfo->IsHttp3();
aArgs.hasIPHintAddress() = aInfo->HasIPHintAddress();
aArgs.echConfig() = aInfo->GetEchConfig();
aArgs.webTransport() = aInfo->GetWebTransport();
if (!aInfo->ProxyInfo()) {
return;
@ -439,14 +428,13 @@ nsHttpConnectionInfo::DeserializeHttpConnectionInfoCloneArgs(
cinfo = new nsHttpConnectionInfo(
aInfoArgs.host(), aInfoArgs.port(), aInfoArgs.npnToken(),
aInfoArgs.username(), pi, aInfoArgs.originAttributes(),
aInfoArgs.endToEndSSL(), aInfoArgs.isHttp3(), aInfoArgs.webTransport());
aInfoArgs.endToEndSSL(), aInfoArgs.isHttp3());
} else {
MOZ_ASSERT(aInfoArgs.endToEndSSL());
cinfo = new nsHttpConnectionInfo(
aInfoArgs.host(), aInfoArgs.port(), aInfoArgs.npnToken(),
aInfoArgs.username(), pi, aInfoArgs.originAttributes(),
aInfoArgs.routedHost(), aInfoArgs.routedPort(), aInfoArgs.isHttp3(),
aInfoArgs.webTransport());
aInfoArgs.routedHost(), aInfoArgs.routedPort(), aInfoArgs.isHttp3());
}
// Make sure the anonymous, insecure-scheme, and private flags are transferred
@ -474,7 +462,7 @@ void nsHttpConnectionInfo::CloneAsDirectRoute(nsHttpConnectionInfo** outCI) {
RefPtr<nsHttpConnectionInfo> clone = new nsHttpConnectionInfo(
mOrigin, mOriginPort,
(mRoutedHost.IsEmpty() && !mIsHttp3) ? mNPNToken : ""_ns, mUsername,
mProxyInfo, mOriginAttributes, mEndToEndSSL, false, mWebTransport);
mProxyInfo, mOriginAttributes, mEndToEndSSL);
// Make sure the anonymous, insecure-scheme, and private flags are transferred
clone->SetAnonymous(GetAnonymous());
clone->SetPrivate(GetPrivate());
@ -505,8 +493,7 @@ nsresult nsHttpConnectionInfo::CreateWildCard(nsHttpConnectionInfo** outParam) {
RefPtr<nsHttpConnectionInfo> clone;
clone = new nsHttpConnectionInfo("*"_ns, 0, mNPNToken, mUsername, mProxyInfo,
mOriginAttributes, true, mIsHttp3,
mWebTransport);
mOriginAttributes, true, mIsHttp3);
// Make sure the anonymous and private flags are transferred!
clone->SetAnonymous(GetAnonymous());
clone->SetPrivate(GetPrivate());
@ -535,20 +522,11 @@ void nsHttpConnectionInfo::SetIPv6Disabled(bool aNoIPv6) {
}
}
void nsHttpConnectionInfo::SetWebTransport(bool aWebTransport) {
if (mWebTransport != aWebTransport) {
mWebTransport = aWebTransport;
RebuildHashKey();
}
}
void nsHttpConnectionInfo::SetTlsFlags(uint32_t aTlsFlags) {
mTlsFlags = aTlsFlags;
const uint32_t tlsFlagsLength = 8;
const uint32_t tlsFlagsIndex =
UnderlyingIndex(HashKeyIndex::End) + strlen("[tlsflags0x");
mHashKey.Replace(tlsFlagsIndex, tlsFlagsLength,
nsPrintfCString("%08x", mTlsFlags));
mHashKey.Replace(tlsFlagsIndex, 8, nsPrintfCString("%08x", mTlsFlags));
}
bool nsHttpConnectionInfo::UsingProxy() {

View File

@ -45,8 +45,7 @@ class nsHttpConnectionInfo final : public ARefBase {
const nsACString& npnToken, const nsACString& username,
nsProxyInfo* proxyInfo,
const OriginAttributes& originAttributes,
bool endToEndSSL = false, bool aIsHttp3 = false,
bool aWebTransport = false);
bool endToEndSSL = false, bool aIsHttp3 = false);
// this version must use TLS and you may supply separate
// connection (aka routing) information than the authenticated
@ -56,7 +55,7 @@ class nsHttpConnectionInfo final : public ARefBase {
nsProxyInfo* proxyInfo,
const OriginAttributes& originAttributes,
const nsACString& routedHost, int32_t routedPort,
bool aIsHttp3, bool aWebTransport);
bool aIsHttp3);
static void SerializeHttpConnectionInfo(nsHttpConnectionInfo* aInfo,
HttpConnectionInfoCloneArgs& aArgs);
@ -85,7 +84,6 @@ class nsHttpConnectionInfo final : public ARefBase {
BeConservative,
AnonymousAllowClientCert,
FallbackConnection,
WebTransport,
End,
};
constexpr inline auto UnderlyingIndex(HashKeyIndex aIndex) const {
@ -219,9 +217,6 @@ class nsHttpConnectionInfo final : public ARefBase {
void SetIPv6Disabled(bool aNoIPv6);
bool GetIPv6Disabled() const { return mIPv6Disabled; }
void SetWebTransport(bool aWebTransport);
bool GetWebTransport() const { return mWebTransport; }
const nsCString& GetNPNToken() { return mNPNToken; }
const nsCString& GetUsername() { return mUsername; }
@ -267,7 +262,7 @@ class nsHttpConnectionInfo final : public ARefBase {
void Init(const nsACString& host, int32_t port, const nsACString& npnToken,
const nsACString& username, nsProxyInfo* proxyInfo,
const OriginAttributes& originAttributes, bool e2eSSL,
bool aIsHttp3, bool aWebTransport);
bool aIsHttp3);
void SetOriginServer(const nsACString& host, int32_t port);
nsCString::char_type GetHashCharAt(HashKeyIndex aIndex) const {
return mHashKey.CharAt(UnderlyingIndex(aIndex));
@ -302,7 +297,6 @@ class nsHttpConnectionInfo final : public ARefBase {
// tls1.3. If the tls version is till not know or it
// is 1.3 or greater the value will be false.
bool mIsHttp3 = false;
bool mWebTransport = false;
bool mHasIPHintAddress = false;
nsCString mEchConfig;

View File

@ -411,7 +411,7 @@ void nsHttpTransaction::OnPendingQueueInserted(
}
// Don't create mHttp3BackupTimer if HTTPS RR is in play.
if (mConnInfo->IsHttp3() && !mOrigConnInfo && !mConnInfo->GetWebTransport()) {
if (mConnInfo->IsHttp3() && !mOrigConnInfo) {
// Backup timer should only be created once.
if (!mHttp3BackupTimerCreated) {
CreateAndStartTimer(mHttp3BackupTimer, this,
@ -434,13 +434,6 @@ nsresult nsHttpTransaction::AsyncRead(nsIStreamListener* listener,
transactionPump.forget(pump);
MutexAutoLock lock(mLock);
mEarlyHintObserver = do_QueryInterface(listener);
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(listener);
if (httpChannel) {
mWebTransportSessionEventListener =
httpChannel->GetWebTransportSessionEventListener();
}
return NS_OK;
}
@ -1357,7 +1350,6 @@ void nsHttpTransaction::Close(nsresult reason) {
{
MutexAutoLock lock(mLock);
mEarlyHintObserver = nullptr;
mWebTransportSessionEventListener = nullptr;
}
if (!mClosed) {
@ -2186,22 +2178,6 @@ nsresult nsHttpTransaction::HandleContentStart() {
// check if this is a no-content response
switch (mResponseHead->Status()) {
case 200: {
if (!mIsForWebTransport) {
break;
}
RefPtr<Http3WebTransportSession> wtSession =
mConnection->GetWebTransportSession(this);
if (wtSession) {
mWebTransportSessionEventListener->OnSessionReadyInternal(wtSession);
wtSession->SetWebTransportSessionEventListener(
mWebTransportSessionEventListener);
}
mWebTransportSessionEventListener = nullptr;
}
// Fall through to WebSocket cases (nsHttpTransaction behaviar is the
// same):
[[fallthrough]];
case 101:
mPreserveStream = true;
[[fallthrough]]; // to other no content cases:
@ -3501,8 +3477,4 @@ void nsHttpTransaction::GetHashKeyOfConnectionEntry(nsACString& aResult) {
aResult.Assign(mHashKeyOfConnectionEntry);
}
void nsHttpTransaction::SetIsForWebTransport(bool aIsForWebTransport) {
mIsForWebTransport = aIsForWebTransport;
}
} // namespace mozilla::net

View File

@ -24,7 +24,6 @@
#include "nsIInterfaceRequestor.h"
#include "nsISSLSocketControl.h"
#include "nsITimer.h"
#include "nsIWebTransport.h"
#include "nsTHashMap.h"
#include "nsThreadUtils.h"
@ -181,8 +180,6 @@ class nsHttpTransaction final : public nsAHttpTransaction,
void GetHashKeyOfConnectionEntry(nsACString& aResult);
bool IsForWebTransport() { return mIsForWebTransport; }
private:
friend class DeleteHttpTransaction;
virtual ~nsHttpTransaction();
@ -551,7 +548,6 @@ class nsHttpTransaction final : public nsAHttpTransaction,
nsTHashMap<nsUint32HashKey, uint32_t> mEchRetryCounterMap;
bool mSupportsHTTP3 = false;
Atomic<bool, Relaxed> mIsForWebTransport{false};
bool mEarlyDataWasAvailable = false;
bool ShouldRestartOn0RttError(nsresult reason);
@ -563,8 +559,6 @@ class nsHttpTransaction final : public nsAHttpTransaction,
// be associated with the connection entry whose hash key is not the same as
// this transaction's.
nsCString mHashKeyOfConnectionEntry;
nsCOMPtr<WebTransportSessionEventListener> mWebTransportSessionEventListener;
};
} // namespace mozilla::net

View File

@ -7,4 +7,4 @@
DIRS += ["about", "data", "file"]
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
DIRS += ["gio"]
DIRS += ["http", "res", "viewsource", "websocket", "webtransport"]
DIRS += ["http", "res", "viewsource", "websocket"]

View File

@ -1,21 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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 WebTransportLog_h
#define WebTransportLog_h
#include "mozilla/Logging.h"
#include "mozilla/net/NeckoChild.h"
namespace mozilla::net {
extern LazyLogModule webTransportLog;
} // namespace mozilla::net
#undef LOG
#define LOG(args) \
MOZ_LOG(mozilla::net::webTransportLog, mozilla::LogLevel::Debug, args)
#endif

View File

@ -1,545 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "WebTransportLog.h"
#include "Http3WebTransportSession.h"
#include "WebTransportSessionProxy.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIHttpChannel.h"
#include "nsIRequest.h"
#include "nsNetUtil.h"
#include "nsSocketTransportService2.h"
#include "mozilla/Logging.h"
namespace mozilla::net {
LazyLogModule webTransportLog("nsWebTransport");
NS_IMPL_ISUPPORTS(WebTransportSessionProxy, WebTransportSessionEventListener,
nsIWebTransport, nsIRedirectResultListener, nsIStreamListener,
nsIChannelEventSink, nsIInterfaceRequestor);
WebTransportSessionProxy::WebTransportSessionProxy()
: mMutex("WebTransportSessionProxy::mMutex") {
LOG(("WebTransportSessionProxy constructor"));
}
WebTransportSessionProxy::~WebTransportSessionProxy() {
if (OnSocketThread()) {
return;
}
MutexAutoLock lock(mMutex);
if ((mState != WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED) &&
(mState != WebTransportSessionProxyState::ACTIVE) &&
(mState != WebTransportSessionProxyState::SESSION_CLOSE_PENDING)) {
return;
}
MOZ_ASSERT(mState != WebTransportSessionProxyState::SESSION_CLOSE_PENDING,
"We can not be in the SESSION_CLOSE_PENDING state in destructor, "
"because should e an runnable that holds reference to this"
"object.");
Unused << gSocketTransportService->Dispatch(NS_NewRunnableFunction(
"WebTransportSessionProxy::ProxyHttp3WebTransportSessionRelease",
[self{std::move(mWebTransportSession)}]() {}));
}
//-----------------------------------------------------------------------------
// WebTransportSessionProxy::nsIWebTransport
//-----------------------------------------------------------------------------
nsresult WebTransportSessionProxy::AsyncConnect(
nsIURI* aURI, nsIPrincipal* aPrincipal, uint32_t aSecurityFlags,
WebTransportSessionEventListener* aListener) {
MOZ_ASSERT(NS_IsMainThread());
LOG(("WebTransportSessionProxy::AsyncConnect"));
mListener = aListener;
nsSecurityFlags flags = nsILoadInfo::SEC_COOKIES_OMIT | aSecurityFlags;
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL |
nsIRequest::LOAD_BYPASS_CACHE |
nsIRequest::INHIBIT_CACHING;
nsresult rv = NS_NewChannel(getter_AddRefs(mChannel), aURI, aPrincipal, flags,
nsContentPolicyType::TYPE_OTHER,
/* aCookieJarSettings */ nullptr,
/* aPerformanceStorage */ nullptr,
/* aLoadGroup */ nullptr,
/* aCallbacks */ this, loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
// configure HTTP specific stuff
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
if (!httpChannel) {
mChannel = nullptr;
return NS_ERROR_ABORT;
}
{
MutexAutoLock lock(mMutex);
ChangeState(WebTransportSessionProxyState::NEGOTIATING);
}
rv = mChannel->AsyncOpen(this);
if (NS_FAILED(rv)) {
MutexAutoLock lock(mMutex);
ChangeState(WebTransportSessionProxyState::DONE);
}
return rv;
}
NS_IMETHODIMP
WebTransportSessionProxy::GetStats() { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
WebTransportSessionProxy::CloseSession(uint32_t status,
const nsACString& reason) {
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
mCloseStatus = status;
mReason = reason;
mListener = nullptr;
switch (mState) {
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::DONE:
return NS_ERROR_NOT_INITIALIZED;
case WebTransportSessionProxyState::NEGOTIATING:
mChannel->Cancel(NS_ERROR_ABORT);
mChannel = nullptr;
ChangeState(WebTransportSessionProxyState::DONE);
break;
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED:
mChannel->Cancel(NS_ERROR_ABORT);
mChannel = nullptr;
ChangeState(WebTransportSessionProxyState::SESSION_CLOSE_PENDING);
CloseSessionInternal();
break;
case WebTransportSessionProxyState::ACTIVE:
ChangeState(WebTransportSessionProxyState::SESSION_CLOSE_PENDING);
CloseSessionInternal();
break;
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
ChangeState(WebTransportSessionProxyState::DONE);
break;
case SESSION_CLOSE_PENDING:
break;
}
return NS_OK;
}
void WebTransportSessionProxy::CloseSessionInternal() {
if (!OnSocketThread()) {
mMutex.AssertCurrentThreadOwns();
RefPtr<WebTransportSessionProxy> self(this);
Unused << gSocketTransportService->Dispatch(NS_NewRunnableFunction(
"WebTransportSessionProxy::CallCloseWebTransportSession",
[self{std::move(self)}]() { self->CloseSessionInternal(); }));
return;
}
RefPtr<Http3WebTransportSession> wt;
uint32_t closeStatus = 0;
nsCString reason;
{
MutexAutoLock lock(mMutex);
if (mState == WebTransportSessionProxyState::SESSION_CLOSE_PENDING) {
MOZ_ASSERT(mWebTransportSession);
wt = mWebTransportSession;
mWebTransportSession = nullptr;
closeStatus = mCloseStatus;
reason = mReason;
ChangeState(WebTransportSessionProxyState::DONE);
} else {
MOZ_ASSERT(mState == WebTransportSessionProxyState::DONE);
}
}
if (wt) {
wt->CloseSession(closeStatus, reason);
}
}
NS_IMETHODIMP
WebTransportSessionProxy::CreateOutgoingUnidirectionalStream(
nsIWebTransportStreamCallback* callback) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebTransportSessionProxy::CreateOutgoingBidirectionalStream(
nsIWebTransportStreamCallback* callback) {
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
// WebTransportSessionProxy::nsIStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
WebTransportSessionProxy::OnStartRequest(nsIRequest* aRequest) {
MOZ_ASSERT(NS_IsMainThread());
LOG(("WebTransportSessionProxy::OnStartRequest\n"));
nsCOMPtr<WebTransportSessionEventListener> listener;
nsAutoCString reason;
uint32_t closeStatus = 0;
{
MutexAutoLock lock(mMutex);
switch (mState) {
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::DONE:
case WebTransportSessionProxyState::ACTIVE:
case WebTransportSessionProxyState::SESSION_CLOSE_PENDING:
MOZ_ASSERT(false, "OnStartRequest cannot be called in this state.");
break;
case WebTransportSessionProxyState::NEGOTIATING:
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
listener = mListener;
mListener = nullptr;
mChannel = nullptr;
reason = mReason;
closeStatus = mCloseStatus;
ChangeState(WebTransportSessionProxyState::DONE);
break;
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED: {
uint32_t status;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
if (!httpChannel ||
NS_FAILED(httpChannel->GetResponseStatus(&status)) ||
status != 200) {
listener = mListener;
mListener = nullptr;
mChannel = nullptr;
mReason = ""_ns;
reason = ""_ns;
mCloseStatus =
0; // TODO: find a better error. Currently error code 0 is used
ChangeState(WebTransportSessionProxyState::SESSION_CLOSE_PENDING);
CloseSessionInternal(); // TODO: find a better error. Currently error
// code 0 is used.
}
// The success cases will be handled in OnStopRequest.
} break;
}
}
if (listener) {
listener->OnSessionClosed(closeStatus, reason);
}
return NS_OK;
}
NS_IMETHODIMP
WebTransportSessionProxy::OnDataAvailable(nsIRequest* aRequest,
nsIInputStream* aStream,
uint64_t aOffset, uint32_t aCount) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(
false, "WebTransportSessionProxy::OnDataAvailable should not be called");
return NS_OK;
}
NS_IMETHODIMP
WebTransportSessionProxy::OnStopRequest(nsIRequest* aRequest,
nsresult aStatus) {
MOZ_ASSERT(NS_IsMainThread());
mChannel = nullptr;
nsCOMPtr<WebTransportSessionEventListener> listener;
nsAutoCString reason;
uint32_t closeStatus = 0;
uint64_t sessionId;
bool succeeded = false;
{
MutexAutoLock lock(mMutex);
switch (mState) {
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::ACTIVE:
case WebTransportSessionProxyState::NEGOTIATING:
MOZ_ASSERT(false, "OnStotRequest cannot be called in this state.");
break;
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
reason = mReason;
closeStatus = mCloseStatus;
listener = mListener;
mListener = nullptr;
ChangeState(WebTransportSessionProxyState::DONE);
break;
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED:
if (NS_FAILED(aStatus)) {
listener = mListener;
mListener = nullptr;
mReason = ""_ns;
reason = ""_ns;
mCloseStatus = 0;
ChangeState(WebTransportSessionProxyState::SESSION_CLOSE_PENDING);
CloseSessionInternal(); // TODO: find a better error. Currently error
// code 0 is used.
} else {
succeeded = true;
sessionId = mSessionId;
listener = mListener;
ChangeState(WebTransportSessionProxyState::ACTIVE);
}
break;
case WebTransportSessionProxyState::SESSION_CLOSE_PENDING:
case WebTransportSessionProxyState::DONE:
break;
}
}
if (listener) {
if (succeeded) {
listener->OnSessionReady(sessionId);
} else {
listener->OnSessionClosed(closeStatus,
reason); // TODO: find a better error.
// Currently error code 0 is used.
}
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// WebTransportSessionProxy::nsIChannelEventSink
//-----------------------------------------------------------------------------
NS_IMETHODIMP
WebTransportSessionProxy::AsyncOnChannelRedirect(
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* callback) {
nsCOMPtr<nsIURI> newURI;
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
NS_ENSURE_SUCCESS(rv, rv);
rv = aNewChannel->GetURI(getter_AddRefs(newURI));
if (NS_FAILED(rv)) {
callback->OnRedirectVerifyCallback(rv);
return NS_OK;
}
// abort the request if redirecting to insecure context
if (!newURI->SchemeIs("https")) {
callback->OnRedirectVerifyCallback(NS_ERROR_ABORT);
return NS_OK;
}
// Assign to mChannel after we get notification about success of the
// redirect in OnRedirectResult.
mRedirectChannel = aNewChannel;
callback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
//-----------------------------------------------------------------------------
// WebTransportSessionProxy::nsIRedirectResultListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
WebTransportSessionProxy::OnRedirectResult(bool aProceeding) {
if (aProceeding && mRedirectChannel) {
mChannel = mRedirectChannel;
}
mRedirectChannel = nullptr;
return NS_OK;
}
//-----------------------------------------------------------------------------
// WebTransportSessionProxy::nsIInterfaceRequestor
//-----------------------------------------------------------------------------
NS_IMETHODIMP
WebTransportSessionProxy::GetInterface(const nsIID& aIID, void** aResult) {
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
NS_ADDREF_THIS();
*aResult = static_cast<nsIChannelEventSink*>(this);
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) {
NS_ADDREF_THIS();
*aResult = static_cast<nsIRedirectResultListener*>(this);
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}
//-----------------------------------------------------------------------------
// WebTransportSessionProxy::WebTransportSessionEventListener
//-----------------------------------------------------------------------------
// This function is called when the Http3WebTransportSession is ready. After
// this call WebTransportSessionProxy is responsible for the
// Http3WebTransportSession, i.e. it is responsible for closing it.
// The listener of the WebTransportSessionProxy will be informed during
// OnStopRequest call.
NS_IMETHODIMP
WebTransportSessionProxy::OnSessionReadyInternal(
Http3WebTransportSession* aSession) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("WebTransportSessionProxy::OnSessionReadyInternal"));
MutexAutoLock lock(mMutex);
switch (mState) {
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
case WebTransportSessionProxyState::ACTIVE:
case WebTransportSessionProxyState::SESSION_CLOSE_PENDING:
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED:
MOZ_ASSERT(false,
"OnSessionReadyInternal cannot be called in this state.");
return NS_ERROR_ABORT;
case WebTransportSessionProxyState::NEGOTIATING:
mWebTransportSession = aSession;
mSessionId = aSession->StreamId();
ChangeState(WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED);
break;
case WebTransportSessionProxyState::DONE:
// The session has been canceled. We do not need to set
// mWebTransportSession.
break;
}
return NS_OK;
}
NS_IMETHODIMP
WebTransportSessionProxy::OnSessionReady(uint64_t ready) {
MOZ_ASSERT(false, "Should not b called");
return NS_OK;
}
NS_IMETHODIMP
WebTransportSessionProxy::OnSessionClosed(uint32_t status,
const nsACString& reason) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("WebTransportSessionProxy::OnSessionClosed"));
MutexAutoLock lock(mMutex);
switch (mState) {
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::NEGOTIATING:
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
MOZ_ASSERT(false, "OnSessionClosed cannot be called in this state.");
return NS_ERROR_ABORT;
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED:
case WebTransportSessionProxyState::ACTIVE: {
mCloseStatus = status;
mReason = reason;
mWebTransportSession = nullptr;
ChangeState(WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING);
RefPtr<WebTransportSessionProxy> self(this);
Unused << NS_DispatchToMainThread(NS_NewRunnableFunction(
"WebTransportSessionProxy::CallOnSessionClose",
[self{std::move(self)}]() { self->CallOnSessionClosed(); }));
} break;
case WebTransportSessionProxyState::SESSION_CLOSE_PENDING:
ChangeState(WebTransportSessionProxyState::DONE);
break;
case WebTransportSessionProxyState::DONE:
// The session has been canceled. We do not need to set
// mWebTransportSession.
break;
}
return NS_OK;
}
void WebTransportSessionProxy::CallOnSessionClosed() {
MOZ_ASSERT(NS_IsMainThread(), "not on socket thread");
nsCOMPtr<WebTransportSessionEventListener> listener;
nsAutoCString reason;
uint32_t closeStatus = 0;
{
MutexAutoLock lock(mMutex);
switch (mState) {
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::NEGOTIATING:
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED:
case WebTransportSessionProxyState::ACTIVE:
case WebTransportSessionProxyState::SESSION_CLOSE_PENDING:
MOZ_ASSERT(false,
"CallOnSessionClosed cannot be called in this state.");
break;
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
listener = mListener;
mListener = nullptr;
reason = mReason;
closeStatus = mCloseStatus;
ChangeState(WebTransportSessionProxyState::DONE);
break;
case WebTransportSessionProxyState::DONE:
break;
}
}
if (listener) {
listener->OnSessionClosed(closeStatus, reason);
}
}
void WebTransportSessionProxy::ChangeState(
WebTransportSessionProxyState newState) {
mMutex.AssertCurrentThreadOwns();
LOG(("WebTransportSessionProxy::ChangeState %d -> %d [this=%p]", mState,
newState, this));
switch (newState) {
case WebTransportSessionProxyState::INIT:
MOZ_ASSERT(false, "Cannot change into INIT sate.");
break;
case WebTransportSessionProxyState::NEGOTIATING:
MOZ_ASSERT(mState == WebTransportSessionProxyState::INIT,
"Only from INIT can be change into NEGOTIATING");
MOZ_ASSERT(mChannel);
MOZ_ASSERT(mListener);
break;
case WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED:
MOZ_ASSERT(
mState == WebTransportSessionProxyState::NEGOTIATING,
"Only from NEGOTIATING can be change into NEGOTIATING_SUCCEEDED");
MOZ_ASSERT(mChannel);
MOZ_ASSERT(mWebTransportSession);
MOZ_ASSERT(mListener);
break;
case WebTransportSessionProxyState::ACTIVE:
MOZ_ASSERT(mState == WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED,
"Only from NEGOTIATING_SUCCEEDED can be change into ACTIVE");
MOZ_ASSERT(!mChannel);
MOZ_ASSERT(mWebTransportSession);
MOZ_ASSERT(mListener);
break;
case WebTransportSessionProxyState::SESSION_CLOSE_PENDING:
MOZ_ASSERT(
(mState == WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED) ||
(mState == WebTransportSessionProxyState::ACTIVE),
"Only from NEGOTIATING_SUCCEEDED and ACTIVE can be change into"
" SESSION_CLOSE_PENDING");
MOZ_ASSERT(!mChannel);
MOZ_ASSERT(mWebTransportSession);
MOZ_ASSERT(!mListener);
break;
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
MOZ_ASSERT(
(mState == WebTransportSessionProxyState::NEGOTIATING_SUCCEEDED) ||
(mState == WebTransportSessionProxyState::ACTIVE),
"Only from NEGOTIATING_SUCCEEDED and ACTIVE can be change into"
" CLOSE_CALLBACK_PENDING");
MOZ_ASSERT(!mWebTransportSession);
MOZ_ASSERT(mListener);
break;
case WebTransportSessionProxyState::DONE:
MOZ_ASSERT(
(mState == WebTransportSessionProxyState::NEGOTIATING) ||
(mState ==
WebTransportSessionProxyState::SESSION_CLOSE_PENDING) ||
(mState == WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING),
"Only from NEGOTIATING, SESSION_CLOSE_PENDING and "
"CLOSE_CALLBACK_PENDING can be change into DONE");
MOZ_ASSERT(!mChannel);
MOZ_ASSERT(!mWebTransportSession);
MOZ_ASSERT(!mListener);
break;
}
mState = newState;
}
} // namespace mozilla::net

View File

@ -1,168 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 mozilla_net_WebTransportProxy_h
#define mozilla_net_WebTransportProxy_h
#include "nsIChannelEventSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIRedirectResultListener.h"
#include "nsIStreamListener.h"
#include "nsIWebTransport.h"
/*
* WebTransportSessionProxy is introduced to enable the creation of a
* Http3WebTransportSession and coordination of actions that are performed on
* the main thread and on the socket thread.
*
* mChannel, mRedirectChannel, and mListener are used only on the main thread.
*
* mWebTransportSession is used only on the socket thread.
*
* mState and mSessionId are used on both threads, socket and main thread and it
* is only used with a lock.
*
*
* WebTransportSessionProxyState:
* - INIT: before AsyncConnect is called.
*
* - NEGOTIATING: It is set during AsyncConnect. During this state HttpChannel
* is open but OnStartRequest has not been called yet. This state can
* transfer into:
* - NEGOTIATING_SUCCEEDED: when a Http3WebTransportSession has been
* negotiated.
* - DONE: when a WebTransport session has been canceled.
*
* - NEGOTIATING_SUCCEEDED: It is set during parsing of
* Http3WebTransportSession response when the response has been successful.
* mWebTransport is set to the Http3WebTransportSession at the same time the
* session changes to this state. This state can transfer into:
* - ACTIVE: during the OnStopRequest call if the WebTransport has not been
* canceled or failed for other reason, e.g. a browser shutdown or content
* blocking policies.
* - SESSION_CLOSE_PENDING: if the WebTransport has been canceled via an API
* call or content blocking policies. (the main thread initiated close).
* - CLOSE_CALLBACK_PENDING: if Http3WebTransportSession has been canceled
* due to a shutdown or a server closing a session. (the socket thread
* initiated close).
*
* - ACTIVE: In this state the session is negotiated and ready to use. This
* state can transfer into:
* - SESSION_CLOSE_PENDING: if the WebTransport has been canceled via an API
* call(nsIWebTransport::closeSession) or content blocking policies. (the
* main thread initiated close).
* - CLOSE_CALLBACK_PENDING: if Http3WebTransportSession has been canceled
* due to a shutdown or a server closing a session. (the socket thread
* initiated close).
*
* - CLOSE_CALLBACK_PENDING: This is the socket thread initiated close. In this
* state, the Http3WebTransportSession has been closed and a
* CallOnSessionClosed call is dispatched to the main thread to call the
* appropriate listener.
*
* - SESSION_CLOSE_PENDING: This is the main thread initiated close. In this
* state, the WebTransport has been closed via an API call
* (nsIWebTransport::closeSession) and a CloseSessionInternal call is
* dispatched to the socket thread to close the appropriate
* Http3WebTransportSession.
*
* - DONE: everything has been cleaned up on both threads.
*
*
* AsyncConnect creates mChannel on the main thread. Redirect callbacks are also
* performed on the main thread (mRedirectChannel set and access only on the
* main thread). Before this point, there are no activities on the socket thread
* and Http3WebTransportSession is nullptr. mChannel is going to create a
* nsHttpTransaction. The transaction will be dispatched on a nsAHttpConnection,
* i.e. currently only the HTTP/3 version is implemented, therefore this will be
* a HttpConnectionUDP and a Http3Session. The Http3Session creates a
* Http3WebTransportSession. Until a response is received
* Http3WebTransportSession is only accessed by Http3Session. During parsing of
* a successful received from a server on the socket thread,
* WebTransportSessionProxy::mWebTransportSession will take a reference to
* Http3WebTransportSession and mState will be set to NEGOTIATING_SUCCEEDED.
* From now on WebTransportSessionProxy is responsible for closing
* Http3WebTransportSession if the closing of the session is initiated on the
* main thread. OnStartRequest and OnStopRequest will be called on the main
* thread. The session negotiation can have 2 outcomes:
* - If both calls, i.e. OnStartRequest an OnStopRequest, indicate that the
* request has succeeded and mState is NEGOTIATING_SUCCEEDED, the
* mListener->OnSessionReady will be called during OnStopRequest.
* - Otherwise, mListener->OnSessionClosed will be called, the state transferred
* into SESSION_CLOSE_PENDING, and CloseSessionInternal will be dispatched to
* the socket thread.
*
* CloseSession is called on the main thread. If the session is already closed
* it returns an error. If the session is in state NEGOTIATING or
* NEGOTIATING_SUCCEEDED mChannel will be canceled. If the session is in state
* NEGOTIATING_SUCCEEDED or ACTIVE the state transferred into
* SESSION_CLOSE_PENDING, and CloseSessionInternal will be dispatched to the
* socket thread
*
* OnSessionReadyInternal is called on the socket thread. If mState is
* NEGOTIATING the state will be set to NEGOTIATING_SUCCEEDED and mWebTransport
* will be set to the newly negotiated Http3WebTransportSession. If mState is
* DONE, the Http3WebTransportSession will be close.
*
* OnSessionClosed is called on the socket thread. mState will be set to
* CLOSE_CALLBACK_PENDING and CallOnSessionClosed will be dispatched to the main
* thread.
*
* mWebTransport is set during states NEGOTIATING_SUCCEEDED, ACTIVE and
* SESSION_CLOSE_PENDING.
*/
namespace mozilla::net {
class WebTransportSessionProxy final : public nsIWebTransport,
public WebTransportSessionEventListener,
public nsIStreamListener,
public nsIChannelEventSink,
public nsIRedirectResultListener,
public nsIInterfaceRequestor {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWEBTRANSPORT
NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIREDIRECTRESULTLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
WebTransportSessionProxy();
private:
~WebTransportSessionProxy();
void CloseSessionInternal();
void CallOnSessionClosed();
enum WebTransportSessionProxyState {
INIT,
NEGOTIATING,
NEGOTIATING_SUCCEEDED,
ACTIVE,
CLOSE_CALLBACK_PENDING,
SESSION_CLOSE_PENDING,
DONE,
};
mozilla::Mutex mMutex;
WebTransportSessionProxyState mState MOZ_GUARDED_BY(mMutex) =
WebTransportSessionProxyState::INIT;
void ChangeState(WebTransportSessionProxyState newState);
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIChannel> mRedirectChannel;
nsCOMPtr<WebTransportSessionEventListener> mListener;
RefPtr<Http3WebTransportSession> mWebTransportSession;
uint64_t mSessionId MOZ_GUARDED_BY(mMutex) = UINT64_MAX;
uint32_t mCloseStatus MOZ_GUARDED_BY(mMutex) = 0;
nsCString mReason MOZ_GUARDED_BY(mMutex);
};
} // namespace mozilla::net
#endif // mozilla_net_WebTransportProxy_h

View File

@ -1,31 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
with Files("**"):
BUG_COMPONENT = ("Core", "Networking: WebTransport")
XPIDL_SOURCES += [
"nsIWebTransport.idl",
]
XPIDL_MODULE = "necko_webtransport"
EXPORTS.mozilla.net += [
"WebTransportSessionProxy.h",
]
UNIFIED_SOURCES += [
"WebTransportSessionProxy.cpp",
]
FINAL_LIBRARY = "xul"
LOCAL_INCLUDES += [
"/netwerk/base",
"/netwerk/protocol/http",
]
include("/ipc/chromium/chromium-config.mozbuild")

View File

@ -1,76 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
#include "nsIURI.idl"
#include "nsIPrincipal.idl"
interface WebTransportSessionEventListener;
interface nsIWebTransportStreamCallback;
%{C++
namespace mozilla::net {
class Http3WebTransportSession;
}
%}
[ptr] native Http3WebTransportSessionPtr(mozilla::net::Http3WebTransportSession);
[builtinclass, scriptable, uuid(c20d6e77-8cb1-4838-a88d-fff826080aa3)]
interface nsIWebTransport : nsISupports {
// When called, perform steps in "Initialization WebTransport over HTTP".
void asyncConnect(in nsIURI aURI,
in nsIPrincipal aLoadingPrincipal,
in unsigned long aSecurityFlags,
in WebTransportSessionEventListener aListener);
// Asynchronously get states.
void getStats();
// Close the session.
void closeSession(in uint32_t aErrorCode,
in ACString aReason);
// Create and open a new WebTransport stream. Returns a nsICancelable
// object, so the consumer can cancel this operation.
void createOutgoingBidirectionalStream(in nsIWebTransportStreamCallback aListener);
void createOutgoingUnidirectionalStream(in nsIWebTransportStreamCallback aListener);
// bool sendDatagram(in AUTF8String aDatagram);
};
// Events related to a WebTransport session.
[scriptable, uuid(0e3cb269-f318-43c8-959e-897f57894b71)]
interface WebTransportSessionEventListener : nsISupports {
// This is used to let the consumer of nsIWebTransport know that the
// underlying WebTransportSession object is ready to use.
void onSessionReady(in uint64_t aSessionId);
// This is used internally to pass the reference of WebTransportSession
// object to WebTransportSessionProxy.
void onSessionReadyInternal(in Http3WebTransportSessionPtr aSession);
void onSessionClosed(in uint32_t aErrorCode,
in ACString aReason);
// When a new stream has been received.
// void onIncomingBidirectionalStreamAvailable(in nsIWebTransportBidirectionalStream aStream);
// void onIncomingUnidirectionalStreamAvailable(in nsIWebTransportReceiveStream aStream);
// When a new stream has been opened.
// void onOutgoingBidirectionalStreamAvailable(in nsIWebTransportBidirectionalStream aStream);
// void onOutgoingUnidirectionalStreamAvailable(in nsIWebTransportSendStream aStream);
// When a new datagram has been received.
// void onDatagramReceived(in AUTF8String aDatagram);
// void onStatsAvailable(in WebTransportStats aStats);
};
// This interface is used as a callback when creating an outgoing
// unidirectional or bidirectional stream.
[scriptable, uuid(c6eeff1d-599b-40a8-9157-c7a40c3d51a2)]
interface nsIWebTransportStreamCallback : nsISupports {
// void onStreamReady(in nsIWebTransportSendStream aStream);
void onError(in uint8_t aError);
};

View File

@ -17,12 +17,12 @@ class NeqoHttp3Conn final {
const NetAddr& aLocalAddr, const NetAddr& aRemoteAddr,
uint32_t aMaxTableSize, uint16_t aMaxBlockedStreams,
uint64_t aMaxData, uint64_t aMaxStreamData,
bool aVersionNegotiation, bool aWebTransport,
const nsACString& aQlogDir, NeqoHttp3Conn** aConn) {
return neqo_http3conn_new(
&aOrigin, &aAlpn, &aLocalAddr, &aRemoteAddr, aMaxTableSize,
aMaxBlockedStreams, aMaxData, aMaxStreamData, aVersionNegotiation,
aWebTransport, &aQlogDir, (const mozilla::net::NeqoHttp3Conn**)aConn);
bool aVersionNegotiation, const nsACString& aQlogDir,
NeqoHttp3Conn** aConn) {
return neqo_http3conn_new(&aOrigin, &aAlpn, &aLocalAddr, &aRemoteAddr,
aMaxTableSize, aMaxBlockedStreams, aMaxData,
aMaxStreamData, aVersionNegotiation, &aQlogDir,
(const mozilla::net::NeqoHttp3Conn**)aConn);
}
void Close(uint64_t aError) { neqo_http3conn_close(this, aError); }
@ -107,26 +107,6 @@ class NeqoHttp3Conn final {
return neqo_http3conn_get_stats(this, aStats);
}
nsresult CreateWebTransport(const nsACString& aHost, const nsACString& aPath,
const nsACString& aHeaders,
uint64_t* aSessionId) {
return neqo_http3conn_webtransport_create_session(this, &aHost, &aPath,
&aHeaders, aSessionId);
}
nsresult CloseWebTransport(uint64_t aSessionId, uint32_t aError,
const nsACString& aMessage) {
return neqo_http3conn_webtransport_close_session(this, aSessionId, aError,
&aMessage);
}
nsresult CreateWebTransportStream(uint64_t aSessionId,
WebTransportStreamType aStreamType,
uint64_t* aStreamId) {
return neqo_http3conn_webtransport_create_stream(this, aSessionId,
aStreamType, aStreamId);
}
private:
NeqoHttp3Conn() = delete;
~NeqoHttp3Conn() = delete;

View File

@ -7,10 +7,8 @@ use libc::{AF_INET, AF_INET6};
use neqo_common::event::Provider;
use neqo_common::{self as common, qlog::NeqoQlog, qwarn, Datagram, Header, Role};
use neqo_crypto::{init, PRErrorCode};
use neqo_http3::{
features::extended_connect::SessionCloseReason, Error as Http3Error, Http3Client,
Http3ClientEvent, Http3Parameters, Http3State, Priority, WebTransportEvent,
};
use neqo_http3::{Error as Http3Error, Priority};
use neqo_http3::{Http3Client, Http3ClientEvent, Http3Parameters, Http3State};
use neqo_transport::{
stream_id::StreamType, CongestionControlAlgorithm, ConnectionParameters,
Error as TransportError, Output, RandomConnectionIdGenerator, StreamId, Version,
@ -95,7 +93,6 @@ impl NeqoHttp3Conn {
max_data: u64,
max_stream_data: u64,
version_negotiation: bool,
webtransport: bool,
qlog_dir: &nsACString,
) -> Result<RefPtr<NeqoHttp3Conn>, nsresult> {
// Nss init.
@ -141,8 +138,7 @@ impl NeqoHttp3Conn {
.max_table_size_decoder(max_table_size)
.max_blocked_streams(max_blocked_streams)
.max_concurrent_push_streams(0)
.connection_parameters(params)
.webtransport(webtransport);
.connection_parameters(params);
let mut conn = match Http3Client::new(
origin_conv,
@ -233,7 +229,6 @@ pub extern "C" fn neqo_http3conn_new(
max_data: u64,
max_stream_data: u64,
version_negotiation: bool,
webtransport: bool,
qlog_dir: &nsACString,
result: &mut *const NeqoHttp3Conn,
) -> nsresult {
@ -249,7 +244,6 @@ pub extern "C" fn neqo_http3conn_new(
max_data,
max_stream_data,
version_negotiation,
webtransport,
qlog_dir,
) {
Ok(http3_conn) => {
@ -339,14 +333,25 @@ fn is_excluded_header(name: &str) -> bool {
}
}
fn parse_headers(headers: &nsACString) -> Result<Vec<Header>, nsresult> {
#[no_mangle]
pub extern "C" fn neqo_http3conn_fetch(
conn: &mut NeqoHttp3Conn,
method: &nsACString,
scheme: &nsACString,
host: &nsACString,
path: &nsACString,
headers: &nsACString,
stream_id: &mut u64,
urgency: u8,
incremental: bool,
) -> nsresult {
let mut hdrs = Vec::new();
// this is only used for headers built by Firefox.
// Firefox supplies all headers already prepared for sending over http1.
// They need to be split into (String, String) pairs.
match str::from_utf8(headers) {
Err(_) => {
return Err(NS_ERROR_INVALID_ARG);
return NS_ERROR_INVALID_ARG;
}
Ok(h) => {
for elem in h.split("\r\n").skip(1) {
@ -374,27 +379,7 @@ fn parse_headers(headers: &nsACString) -> Result<Vec<Header>, nsresult> {
}
}
}
Ok(hdrs)
}
#[no_mangle]
pub extern "C" fn neqo_http3conn_fetch(
conn: &mut NeqoHttp3Conn,
method: &nsACString,
scheme: &nsACString,
host: &nsACString,
path: &nsACString,
headers: &nsACString,
stream_id: &mut u64,
urgency: u8,
incremental: bool,
) -> nsresult {
let hdrs = match parse_headers(headers) {
Err(e) => {
return e;
}
Ok(h) => h,
};
let method_tmp = match str::from_utf8(method) {
Ok(m) => m,
Err(_) => {
@ -612,101 +597,6 @@ pub extern "C" fn neqo_http3conn_close_stream(
}
}
// WebTransport streams can be unidirectional and bidirectional.
// It is mapped to and from neqo's StreamType enum.
#[repr(C)]
pub enum WebTransportStreamType {
BiDi,
UniDi,
}
impl From<StreamType> for WebTransportStreamType {
fn from(t: StreamType) -> WebTransportStreamType {
match t {
StreamType::BiDi => WebTransportStreamType::BiDi,
StreamType::UniDi => WebTransportStreamType::UniDi,
}
}
}
impl From<WebTransportStreamType> for StreamType {
fn from(t: WebTransportStreamType) -> StreamType {
match t {
WebTransportStreamType::BiDi => StreamType::BiDi,
WebTransportStreamType::UniDi => StreamType::UniDi,
}
}
}
#[repr(C)]
pub enum SessionCloseReasonExternal {
Error(u64),
Status(u16),
Clean(u32),
}
impl SessionCloseReasonExternal {
fn new(reason: SessionCloseReason, data: &mut ThinVec<u8>) -> SessionCloseReasonExternal {
match reason {
SessionCloseReason::Error(e) => SessionCloseReasonExternal::Error(e),
SessionCloseReason::Status(s) => SessionCloseReasonExternal::Status(s),
SessionCloseReason::Clean { error, message } => {
data.extend_from_slice(message.as_ref());
SessionCloseReasonExternal::Clean(error)
}
}
}
}
#[repr(C)]
pub enum WebTransportEventExternal {
Negotiated(bool),
Session(u64),
SessionClosed {
stream_id: u64,
reason: SessionCloseReasonExternal,
},
NewStream {
stream_id: u64,
stream_type: WebTransportStreamType,
session_id: u64,
},
}
impl WebTransportEventExternal {
fn new(event: WebTransportEvent, data: &mut ThinVec<u8>) -> WebTransportEventExternal {
match event {
WebTransportEvent::Negotiated(n) => WebTransportEventExternal::Negotiated(n),
WebTransportEvent::Session { stream_id, status } => {
data.extend_from_slice(b"HTTP/3 ");
data.extend_from_slice(&status.to_string().as_bytes());
data.extend_from_slice(b"\r\n\r\n");
WebTransportEventExternal::Session(stream_id.as_u64())
}
WebTransportEvent::SessionClosed { stream_id, reason } => match reason {
SessionCloseReason::Status(status) => {
data.extend_from_slice(b"HTTP/3 ");
data.extend_from_slice(&status.to_string().as_bytes());
data.extend_from_slice(b"\r\n\r\n");
WebTransportEventExternal::Session(stream_id.as_u64())
}
_ => WebTransportEventExternal::SessionClosed {
stream_id: stream_id.as_u64(),
reason: SessionCloseReasonExternal::new(reason, data),
},
},
WebTransportEvent::NewStream {
stream_id,
session_id,
} => WebTransportEventExternal::NewStream {
stream_id: stream_id.as_u64(),
stream_type: stream_id.stream_type().into(),
session_id: session_id.as_u64(),
},
}
}
}
#[repr(C)]
pub enum Http3Event {
/// A request stream has space for more data to be sent.
@ -770,7 +660,6 @@ pub enum Http3Event {
expire_in: u64, // microseconds
},
EchFallbackAuthenticationNeeded,
WebTransport(WebTransportEventExternal),
NoEvent,
}
@ -948,9 +837,7 @@ pub extern "C" fn neqo_http3conn_event(
data.extend_from_slice(public_name.as_ref());
Http3Event::EchFallbackAuthenticationNeeded
}
Http3ClientEvent::WebTransport(e) => {
Http3Event::WebTransport(WebTransportEventExternal::new(e, data))
}
Http3ClientEvent::WebTransport(_) => Http3Event::NoEvent,
};
if !matches!(fe, Http3Event::NoEvent) {
@ -1146,86 +1033,3 @@ pub extern "C" fn neqo_http3conn_get_stats(conn: &mut NeqoHttp3Conn, stats: &mut
stats.pto_ack = t_stats.pto_ack;
stats.pto_counts = t_stats.pto_counts;
}
#[no_mangle]
pub extern "C" fn neqo_http3conn_webtransport_create_session(
conn: &mut NeqoHttp3Conn,
host: &nsACString,
path: &nsACString,
headers: &nsACString,
stream_id: &mut u64,
) -> nsresult {
let hdrs = match parse_headers(headers) {
Err(e) => {
return e;
}
Ok(h) => h,
};
let host_tmp = match str::from_utf8(host) {
Ok(h) => h,
Err(_) => {
return NS_ERROR_INVALID_ARG;
}
};
let path_tmp = match str::from_utf8(path) {
Ok(p) => p,
Err(_) => {
return NS_ERROR_INVALID_ARG;
}
};
match conn.conn.webtransport_create_session(
Instant::now(),
&("https", host_tmp, path_tmp),
&hdrs,
) {
Ok(id) => {
*stream_id = id.as_u64();
NS_OK
}
Err(Http3Error::StreamLimitError) => NS_BASE_STREAM_WOULD_BLOCK,
Err(_) => NS_ERROR_UNEXPECTED,
}
}
#[no_mangle]
pub extern "C" fn neqo_http3conn_webtransport_close_session(
conn: &mut NeqoHttp3Conn,
session_id: u64,
error: u32,
message: &nsACString,
) -> nsresult {
let message_tmp = match str::from_utf8(message) {
Ok(p) => p,
Err(_) => {
return NS_ERROR_INVALID_ARG;
}
};
match conn
.conn
.webtransport_close_session(StreamId::from(session_id), error, message_tmp)
{
Ok(()) => NS_OK,
Err(_) => NS_ERROR_INVALID_ARG,
}
}
#[no_mangle]
pub extern "C" fn neqo_http3conn_webtransport_create_stream(
conn: &mut NeqoHttp3Conn,
session_id: u64,
stream_type: WebTransportStreamType,
stream_id: &mut u64,
) -> nsresult {
match conn
.conn
.webtransport_create_stream(StreamId::from(session_id), stream_type.into())
{
Ok(id) => {
*stream_id = id.as_u64();
NS_OK
}
Err(Http3Error::StreamLimitError) => NS_BASE_STREAM_WOULD_BLOCK,
Err(_) => NS_ERROR_UNEXPECTED,
}
}

View File

@ -10,7 +10,6 @@ use neqo_common::{event::Provider, qdebug, qinfo, qtrace, Datagram, Header};
use neqo_crypto::{generate_ech_keys, init_db, AllowZeroRtt, AntiReplay};
use neqo_http3::{
Error, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent,
WebTransportRequest, WebTransportServerEvent,
};
use neqo_transport::server::Server;
use neqo_transport::{ConnectionEvent, ConnectionParameters, Output, RandomConnectionIdGenerator};
@ -28,7 +27,6 @@ use core::fmt::Display;
use mio::net::UdpSocket;
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::timer::{Builder, Timeout, Timer};
use std::cmp::{max, min};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::collections::HashSet;
@ -54,9 +52,6 @@ const HTTP_RESPONSE_WITH_WRONG_FRAME: &[u8] = &[
trait HttpServer: Display {
fn process(&mut self, dgram: Option<Datagram>) -> Output;
fn process_events(&mut self);
fn get_timeout(&self) -> Option<Duration> {
None
}
}
struct Http3TestServer {
@ -66,7 +61,6 @@ struct Http3TestServer {
posts: HashMap<Http3OrWebTransportStream, usize>,
responses: HashMap<Http3OrWebTransportStream, Vec<u8>>,
current_connection_hash: u64,
sessions_to_close: HashMap<Instant, Vec<WebTransportRequest>>,
}
impl ::std::fmt::Display for Http3TestServer {
@ -82,7 +76,6 @@ impl Http3TestServer {
posts: HashMap::new(),
responses: HashMap::new(),
current_connection_hash: 0,
sessions_to_close: HashMap::new(),
}
}
@ -117,18 +110,6 @@ impl Http3TestServer {
}
}
}
fn maybe_close_session(&mut self) {
let now = Instant::now();
for (expires, sessions) in self.sessions_to_close.iter_mut() {
if *expires <= now {
for s in sessions.iter_mut() {
s.close_session(0, "").unwrap();
}
}
}
self.sessions_to_close.retain(|expires, _| *expires >= now);
}
}
impl HttpServer for Http3TestServer {
@ -137,8 +118,6 @@ impl HttpServer for Http3TestServer {
}
fn process_events(&mut self) {
self.maybe_close_session();
while let Some(event) = self.server.next_event() {
qtrace!("Event: {:?}", event);
match event {
@ -366,69 +345,11 @@ impl HttpServer for Http3TestServer {
}
Http3ServerEvent::PriorityUpdate { .. }
| Http3ServerEvent::StreamReset { .. }
| Http3ServerEvent::StreamStopSending { .. } => {}
Http3ServerEvent::WebTransport(WebTransportServerEvent::NewSession {
mut session,
headers,
}) => {
qdebug!(
"WebTransportServerEvent::NewSession {:?} {:?}",
session,
headers
);
let path_hdr = headers.iter().find(|&h| h.name() == ":path");
match path_hdr {
Some(ph) if !ph.value().is_empty() => {
let path = ph.value();
qtrace!("Serve request {}", path);
if path == "/success" {
session.response(true).unwrap();
} else if path == "/reject" {
session.response(false).unwrap();
} else if path == "/closeafter0ms" {
session.response(true).unwrap();
} else if path == "/closeafter100ms" {
session.response(true).unwrap();
let expires = Instant::now() + Duration::from_millis(100);
if !self.sessions_to_close.contains_key(&expires) {
self.sessions_to_close.insert(expires, Vec::new());
}
self.sessions_to_close
.get_mut(&expires)
.unwrap()
.push(session);
} else {
session.response(true).unwrap();
}
}
_ => {
session.response(false).unwrap();
}
}
}
Http3ServerEvent::WebTransport(WebTransportServerEvent::SessionClosed {
session,
reason,
}) => {
qdebug!(
"WebTransportServerEvent::SessionClosed {:?} {:?}",
session,
reason
);
}
Http3ServerEvent::WebTransport(WebTransportServerEvent::NewStream(id)) => {
qdebug!("WebTransportServerEvent::NewStream {:?}", id);
}
| Http3ServerEvent::StreamStopSending { .. }
| Http3ServerEvent::WebTransport(_) => {}
}
}
}
fn get_timeout(&self) -> Option<Duration> {
if let Some(next) = self.sessions_to_close.keys().min() {
return Some(max(*next - Instant::now(), Duration::from_millis(0)));
}
None
}
}
impl HttpServer for Server {
@ -504,10 +425,7 @@ fn process(
emit_packet(socket, dgram);
true
}
Output::Callback(mut new_timeout) => {
if let Some(t) = server.get_timeout() {
new_timeout = min(new_timeout, t);
}
Output::Callback(new_timeout) => {
if let Some(svr_timeout) = svr_timeout {
timer.cancel_timeout(svr_timeout);
}
@ -652,8 +570,7 @@ impl ServersRunner {
Http3Parameters::default()
.max_table_size_encoder(MAX_TABLE_SIZE)
.max_table_size_decoder(MAX_TABLE_SIZE)
.max_blocked_streams(MAX_BLOCKED_STREAMS)
.webtransport(true),
.max_blocked_streams(MAX_BLOCKED_STREAMS),
None,
)
.expect("We cannot make a server!"),

View File

@ -1,117 +0,0 @@
//
// Simple WebTransport test
//
"use strict";
var h3Port;
var host;
let WebTransportListener = function() {};
WebTransportListener.prototype = {
onSessionReady(sessionId) {
info("SessionId " + sessionId);
this.ready();
},
onSessionClosed(errorCode, reason) {
info("Error: " + errorCode + " reason: " + reason);
this.closed();
},
QueryInterface: ChromeUtils.generateQI(["WebTransportSessionEventListener"]),
};
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.dns.localDomains");
});
add_task(async function setup() {
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com");
h3Port = env.get("MOZHTTP3_PORT");
Assert.notEqual(h3Port, null);
Assert.notEqual(h3Port, "");
host = "foo.example.com:" + h3Port;
do_get_profile();
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
// `../unit/` so that unit_ipc tests can use as well
addCertFromFile(certdb, "../unit/http2-ca.pem", "CTu,u,u");
});
add_task(async function test_connect_wt() {
let webTransport = NetUtil.newWebTransport();
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.ready = resolve;
webTransport.asyncConnect(
NetUtil.newURI("https://" + host + "/success"),
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
webTransport.closeSession(0, "");
});
add_task(async function test_reject() {
let webTransport = NetUtil.newWebTransport();
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.closed = resolve;
webTransport.asyncConnect(
NetUtil.newURI("https://" + host + "/reject"),
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
});
async function test_closed(path) {
let webTransport = NetUtil.newWebTransport();
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
let pReady = new Promise(resolve => {
listener.ready = resolve;
});
let pClose = new Promise(resolve => {
listener.closed = resolve;
});
webTransport.asyncConnect(
NetUtil.newURI("https://" + host + path),
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
await pReady;
await pClose;
}
add_task(async function test_closed_0ms() {
test_closed("/closeafter0ms");
});
add_task(async function test_closed_100ms() {
test_closed("/closeafter100ms");
});

View File

@ -646,7 +646,3 @@ run-sequentially = node server exceptions dont replay well
[test_pac_reload_after_network_change.js]
[test_proxy_cancel.js]
[test_connection_based_auth.js]
[test_webtransport_simple.js]
skip-if =
os == 'android'
socketprocess_networking