1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
/* -*- 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
|