215 lines
8 KiB
C++
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
|