Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 <functional>
#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 WebTransportStreamCallbackWrapper;
class WebTransportSessionProxy final
: public nsIWebTransport,
public WebTransportSessionEventListener,
public WebTransportSessionEventListenerInternal,
public WebTransportConnectionSettings,
public nsIStreamListener,
public nsIChannelEventSink,
public nsIRedirectResultListener,
public nsIInterfaceRequestor {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWEBTRANSPORT
NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENER
NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENERINTERNAL
NS_DECL_WEBTRANSPORTCONNECTIONSETTINGS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIREDIRECTRESULTLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
WebTransportSessionProxy();
private:
~WebTransportSessionProxy();
void CloseSessionInternal();
void CloseSessionInternalLocked();
void CallOnSessionClosed();
void CallOnSessionClosedLocked();
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);
void CreateStreamInternal(nsIWebTransportStreamCallback* callback,
bool aBidi);
void DoCreateStream(WebTransportStreamCallbackWrapper* aCallback,
Http3WebTransportSession* aSession, bool aBidi);
void SendDatagramInternal(const RefPtr<Http3WebTransportSession>& aSession,
nsTArray<uint8_t>&& aData, uint64_t aTrackingId);
void NotifyDatagramReceived(nsTArray<uint8_t>&& aData);
void GetMaxDatagramSizeInternal(
const RefPtr<Http3WebTransportSession>& aSession);
void OnMaxDatagramSizeInternal(uint64_t aSize);
void OnOutgoingDatagramOutComeInternal(
uint64_t aId, WebTransportSessionEventListener::DatagramOutcome aOutCome);
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIChannel> mRedirectChannel;
nsCOMPtr<WebTransportSessionEventListener> mListener MOZ_GUARDED_BY(mMutex);
RefPtr<Http3WebTransportSession> mWebTransportSession MOZ_GUARDED_BY(mMutex);
uint64_t mSessionId MOZ_GUARDED_BY(mMutex) = UINT64_MAX;
uint32_t mCloseStatus MOZ_GUARDED_BY(mMutex) = 0;
nsCString mReason MOZ_GUARDED_BY(mMutex);
bool mCleanly MOZ_GUARDED_BY(mMutex) = false;
bool mStopRequestCalled MOZ_GUARDED_BY(mMutex) = false;
// This is used to store events happened before OnSessionReady.
// Note that these events will be dispatched to the socket thread.
nsTArray<std::function<void()>> mPendingEvents MOZ_GUARDED_BY(mMutex);
nsTArray<std::function<void(nsresult)>> mPendingCreateStreamEvents
MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIEventTarget> mTarget MOZ_GUARDED_BY(mMutex);
nsTArray<RefPtr<nsIWebTransportHash>> mServerCertHashes;
bool mDedicatedConnection; // for WebTranport
};
} // namespace mozilla::net
#endif // mozilla_net_WebTransportProxy_h