1
0
Fork 0
firefox/netwerk/protocol/http/Http2WebTransportSession.h
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

215 lines
8 KiB
C++

/* -*- 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_Http2WebTransportSession_h
#define mozilla_net_Http2WebTransportSession_h
#include "CapsuleParser.h"
#include "Http2StreamTunnel.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Queue.h"
#include "nsRefPtrHashtable.h"
#include "nsTHashMap.h"
#include "nsHashKeys.h"
#include "WebTransportFlowControl.h"
#include "WebTransportSessionBase.h"
#include "WebTransportStreamBase.h"
namespace mozilla::net {
class CapsuleEncoder;
class Http2WebTransportStream;
// A handler used exclusively by Http2WebTransportSessionImpl for capsule I/O,
// primarily responsible for sending capsules.
class CapsuleIOHandler {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual void HasCapsuleToSend() = 0;
virtual void SetSentFin() = 0;
virtual void StartReading() = 0;
virtual void OnCapsuleParseFailure(nsresult aError) = 0;
protected:
virtual ~CapsuleIOHandler() = default;
};
struct Http2WebTransportInitialSettings {
// Initial session-level data limit.
uint32_t mInitialMaxData = 0;
// Initial stream-level data limit for outgoing unidirectional streams.
uint32_t mInitialMaxStreamDataUni = 0;
// Initial stream-level data limit for outgoing bidirectional streams.
uint32_t mInitialMaxStreamDataBidi = 0;
// Initial max unidirectional streams per session.
uint32_t mInitialMaxStreamsUni = 0;
// Initial max bidirectional streams per session.
uint32_t mInitialMaxStreamsBidi = 0;
// Initial limit on unidirectional streams that the peer creates.
uint32_t mInitialLocalMaxStreamsUnidi = 16;
// Initial limit on bidirectional streams that the peer creates.
uint32_t mInitialLocalMaxStreamsBidi = 16;
// Initial flow control limit for receiving data on unidirectional streams
// that the peer creates.
uint32_t mInitialLocalMaxStreamDataUnidi = 0x100000;
// Initial flow control limit for receiving data on bidirectional streams
// that the peer creates.
uint32_t mInitialLocalMaxStreamDataBidi = 0x100000;
// Initial session-level flow control limit.
uint64_t mInitialLocalMaxData = 0x3FFFFFFFFFFFFFFF;
};
enum class CapsuleTransmissionPriority : uint8_t {
Critical = 0,
Important = 1,
High = 2,
Normal = 3,
Low = 4,
};
// Core implementation of the logic behind Http2WebTransportSession.
// It's designed to be independently instantiated, which makes it easier to
// test.
class Http2WebTransportSessionImpl final : public WebTransportSessionBase,
public CapsuleParser::Listener {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http2WebTransportSessionImpl, override)
explicit Http2WebTransportSessionImpl(
CapsuleIOHandler* aHandler, Http2WebTransportInitialSettings aSettings);
void CloseSession(uint32_t aStatus, const nsACString& aReason) override;
uint64_t GetStreamId() const override;
void GetMaxDatagramSize() override;
void SendDatagram(nsTArray<uint8_t>&& aData, uint64_t aTrackingId) override;
void CreateOutgoingBidirectionalStream(
std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&&
aCallback) override;
void CreateOutgoingUnidirectionalStream(
std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&&
aCallback) override;
bool OnCapsule(Capsule&& aCapsule) override;
void OnCapsuleParseFailure(nsresult aError) override;
void StartReading() override;
void Close(nsresult aReason);
void OnStreamClosed(Http2WebTransportStream* aStream);
void PrepareCapsulesToSend(
mozilla::Queue<UniquePtr<CapsuleEncoder>>& aOutput);
SenderFlowControlSession& SessionDataFc() { return mSessionDataFc; }
ReceiverFlowControlSession& ReceiverFc() { return mReceiverFc; }
void StreamHasCapsuleToSend();
void OnStreamDataSent(StreamId aId, size_t aCount);
void OnError(uint64_t aError);
private:
virtual ~Http2WebTransportSessionImpl();
void CreateOutgoingStreamInternal(
StreamId aStreamId,
std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&&
aCallback);
class PendingStreamCallback {
public:
explicit PendingStreamCallback(
std::function<void(
Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&& aCallback)
: mCallback(std::move(aCallback)) {}
std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>
TakeCallback() {
return std::move(mCallback);
}
private:
std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>
mCallback;
};
void ProcessPendingStreamCallbacks(
mozilla::Queue<UniquePtr<PendingStreamCallback>>& aCallbacks,
WebTransportStreamType aStreamType);
bool ProcessIncomingStreamCapsule(Capsule&& aCapsule, StreamId aID,
WebTransportStreamType aStreamType);
void SendMaintenanceCapsules(CapsuleTransmissionPriority aPriority);
already_AddRefed<Http2WebTransportStream> GetStream(StreamId aId);
bool HandleMaxStreamDataCapsule(StreamId aId, Capsule&& aCapsule);
bool HandleStreamStopSendingCapsule(StreamId aId, Capsule&& aCapsule);
bool HandleStreamResetCapsule(StreamId aId, Capsule&& aCapsule);
class CapsuleQueue final {
public:
CapsuleQueue();
mozilla::Queue<UniquePtr<CapsuleEncoder>>& operator[](
CapsuleTransmissionPriority aPriority);
private:
mozilla::Queue<UniquePtr<CapsuleEncoder>> mCritical;
mozilla::Queue<UniquePtr<CapsuleEncoder>> mImportant;
mozilla::Queue<UniquePtr<CapsuleEncoder>> mHigh;
mozilla::Queue<UniquePtr<CapsuleEncoder>> mNormal;
mozilla::Queue<UniquePtr<CapsuleEncoder>> mLow;
};
void EnqueueOutCapsule(CapsuleTransmissionPriority aPriority,
UniquePtr<CapsuleEncoder>&& aData);
uint64_t mStreamId = 0;
nsRefPtrHashtable<nsUint64HashKey, Http2WebTransportStream> mOutgoingStreams;
nsRefPtrHashtable<nsUint64HashKey, Http2WebTransportStream> mIncomingStreams;
mozilla::Queue<UniquePtr<PendingStreamCallback>> mBidiPendingStreamCallbacks;
mozilla::Queue<UniquePtr<PendingStreamCallback>> mUnidiPendingStreamCallbacks;
Http2WebTransportInitialSettings mSettings;
LocalStreamLimits mLocalStreamsFlowControl;
RemoteStreamLimits mRemoteStreamsFlowControl;
RefPtr<CapsuleIOHandler> mHandler;
CapsuleQueue mCapsuleQueue;
SenderFlowControlSession mSessionDataFc;
ReceiverFlowControlSession mReceiverFc;
};
class Http2WebTransportSession final : public Http2StreamTunnel,
public nsIOutputStreamCallback,
public nsIInputStreamCallback,
public CapsuleIOHandler {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIOUTPUTSTREAMCALLBACK
NS_DECL_NSIINPUTSTREAMCALLBACK
Http2WebTransportSession(Http2Session* aSession, int32_t aPriority,
uint64_t aBcId,
nsHttpConnectionInfo* aConnectionInfo,
Http2WebTransportInitialSettings aSettings);
Http2WebTransportSession* GetHttp2WebTransportSession() override {
return this;
}
Http2WebTransportSessionImpl* GetHttp2WebTransportSessionImpl() {
return mImpl;
}
void CloseStream(nsresult aReason) override;
void HasCapsuleToSend() override;
void SetSentFin() override;
void StartReading() override;
void OnCapsuleParseFailure(nsresult aError) override;
private:
virtual ~Http2WebTransportSession();
nsresult GenerateHeaders(nsCString& aCompressedData,
uint8_t& aFirstFrameFlags) override;
size_t mWriteOffset{0};
mozilla::Queue<UniquePtr<CapsuleEncoder>> mOutgoingQueue;
RefPtr<Http2WebTransportSessionImpl> mImpl;
UniquePtr<CapsuleParser> mCapsuleParser;
UniquePtr<CapsuleEncoder> mCurrentOutCapsule;
};
} // namespace mozilla::net
#endif // mozilla_net_Http2WebTransportSession_h