TsgcWebTransportSession › Ereignisse › OnOpenStream
Transport-Hook. Erlaubt dem Transport, den echten QUIC-Stream anzulegen, der einem OpenStream-Aufruf zugrunde liegt. Wird vom HTTP/3-Client und -Server bereits zugewiesen.
property OnOpenStream: TsgcWebTransportOpenStreamEvent read FOnOpenStream write FOnOpenStream;
// event type
TsgcWebTransportOpenStreamEvent = procedure(Sender: TObject;
const aStream: TsgcWebTransportStream) of object;
// handler signature
procedure MyOpenStream(Sender: TObject; const aStream: TsgcWebTransportStream);
| Name | Typ | Beschreibung |
|---|---|---|
Sender | TObject | Die TsgcWebTransportSession, die den Stream öffnet. |
aStream | const TsgcWebTransportStream | Der frisch erstellte Stream, in den noch nicht geschrieben wurde und der noch nicht in der Liste der Sitzung steht. Unidirectional ist bereits gesetzt und teilt dem Handler mit, welche Art von QUIC-Stream zu belegen ist. StreamId ist -1 und wartet darauf, ausgefüllt zu werden. Vom Handler wird erwartet, dass er StreamId und OnWriteBytes setzt. |
Bei einer nackten Sitzung nicht zugewiesen. Sowohl der HTTP/3-Client als auch der HTTP/3-Server weisen es zu, bevor Sie die Sitzung überhaupt zu sehen bekommen.
Weisen Sie dies nicht aus Anwendungscode zu. Es ist ein Transport-Hook, der nur deshalb als Ereignis deklariert ist, weil eine einfache Pascal-Klasse auf diese Weise einen Callback entgegennimmt. Sowohl TsgcHTTP3Client.WebTransportConnect als auch der Sitzungsannahmepfad des Servers weisen ihn zu, und ihre Zuweisung zu überschreiben zerstört die Sitzung: Streams würden keine echten QUIC-Streams mehr erhalten, und jeder Schreibvorgang würde auf den Fallback-Writer auf Sitzungsebene zurückfallen. Er ist dokumentiert, weil ein benutzerdefinierter QUIC-Transport ihn bereitstellen muss.
Wann es ausgelöst wird. Aus OpenStream heraus, nachdem das Stream-Objekt existiert, aber bevor sein WebTransport-Header geschrieben wird. Genau dieser Zeitpunkt ist der springende Punkt: Der Handler erstellt den zugrunde liegenden QUIC-Stream und bindet einen Writer pro Stream, sodass der Header und danach alles Weitere auf dem richtigen Stream landet.
Was ein Handler tun muss. Zwei Dinge:
aStream.Unidirectional angegebenen Richtung und weisen Sie dessen ID aStream.StreamId zu. Ohne dies behält der Stream -1, und FindStreamById kann ihn nie zuordnen, sodass eingehende Daten nicht an ihn weitergeleitet werden können.aStream.OnWriteBytes einen Writer zu, der genau diesen QUIC-Stream anspricht.
Der Handler darf nicht in den Stream schreiben und darf ihn nicht zur Sitzung hinzufügen; OpenStream erledigt beides, sobald der Handler zurückkehrt.
Wenn der Handler nichts tut oder das Ereignis nicht zugewiesen ist, funktioniert OpenStream weiterhin, gewissermaßen. Der Stream behält seinen Standard-Writer, der Bytes über das OnWriteData auf Sitzungsebene leitet, und behält StreamId = -1. Das bildet einen einzelnen multiplexten Transport-Stream ab: brauchbar für einen trivialen Transport, unbrauchbar für echtes WebTransport, bei dem jeder Stream unabhängig sein muss. Die eigenen Handler der Bibliothek erledigen immer die vollständige Arbeit und tolerieren einen QUIC-Stream, der sich nicht öffnen lässt, indem sie den Stream auf dem Fallback-Writer belassen, statt eine Ausnahme auszulösen.
Dieses Member ist derzeit nur in der Delphi/C++Builder-Implementierung verfügbar. Die .NET-Klasse besitzt eine äquivalente Eigenschaft internal OpenStreamHook, die Anwendungscode nicht zuweisen kann und die sich in einem Punkt unterscheidet: Die verwaltete Sitzung vergibt die Stream-ID selbst, bevor sie den Hook aufruft, sodass ein .NET-Hook nur den Writer bindet.
// What a custom QUIC transport assigns. This mirrors the library's own
// TsgcHTTP3Client_Base.DoWebTransportOpenStream. Applications never do this.
procedure TMyTransport.WireSession(const aSession: TsgcWebTransportSession);
begin
aSession.OnOpenStream := DoOpenStream;
aSession.OnWriteData := DoWriteData;
end;
procedure TMyTransport.DoOpenStream(Sender: TObject;
const aStream: TsgcWebTransportStream);
var
oQStream: TsgcSSLQUICStream;
begin
if not Assigned(aStream) then
Exit;
// Create the real QUIC stream of the requested direction, then bind a
// per-stream writer so the 0x54/0x41 + SessionId header that OpenStream
// is about to write, and every later byte, go to THIS QUIC stream.
oQStream := GetQUICComponent.OpenStream(FHost, FPort, aStream.Unidirectional);
if Assigned(oQStream) then
begin
aStream.StreamId := oQStream.StreamId;
aStream.OnWriteBytes := DoStreamWriteBytes;
end;
// If the QUIC stream could not be opened, leave the stream on the
// session-level fallback writer rather than raising.
end;