TsgcWebTransportSession › Events › OnWriteData

OnWriteData Event

Transport hook. The session-level fallback writer, used only by streams that have no per-stream writer of their own.

Syntax

property OnWriteData: TsgcWebTransportWriteEvent read FOnWriteData write FOnWriteData;

// event type
TsgcWebTransportWriteEvent = procedure(Sender: TObject;
  const aData: TBytes) of object;

// handler signature
procedure MyWriteData(Sender: TObject; const aData: TBytes);

Parameters

NameTypeDescription
SenderTObjectThe TsgcWebTransportSession that is writing. Note this is the session, not the stream the bytes came from: that information is not passed, which is exactly why this writer cannot target a specific stream.
aDataconst TBytesThe raw bytes to put on the connection, exactly as they should appear on the wire. Any WebTransport stream header is already included by the caller.

Default Value

Unassigned on a bare session. Both the HTTP/3 client and the HTTP/3 server assign it before you see the session; the client points it at the default CONNECT stream of the QUIC connection.

Remarks

Do not assign this from application code. It is a transport hook that the HTTP/3 client and server already fill in. It is documented for custom-transport authors.

It is a fallback, and in normal operation it is never used. Every stream has its own writer, TsgcWebTransportStream.OnWriteBytes. OpenStream starts a new stream on a session-level default writer that forwards here, then raises OnOpenStream, and the transport replaces the writer with one bound to a real QUIC stream. From that point the stream's bytes bypass OnWriteData entirely. It only carries traffic when a stream ends up with no per-stream writer, which in the shipping HTTP/3 client and server means the QUIC stream could not be opened.

It cannot target a stream, and that is the point. The handler receives the session and a byte array, and nothing else. Bytes from any number of streams arrive here indistinguishable from one another. That models a single multiplexed transport stream, which is fine as a degraded path but is not WebTransport: real sessions need each stream on its own QUIC stream so they stay independent and free from head-of-line blocking. Treat traffic arriving here as a sign that a stream did not get its own QUIC stream.

A handler should write aData to the connection unchanged. Do not add framing: whatever the session or stream layer needed is already in the array.

This member is currently available in the Delphi/C++Builder implementation only. The .NET class has an equivalent internal WriteDataHook property, not assignable from application code. It is used slightly differently there: the managed OpenStream binds it directly as the new stream's writer when no OpenStreamHook is set, rather than routing through a session-level dispatcher.

Example


// What a custom QUIC transport assigns. This mirrors the library's own
// TsgcHTTP3Client_Base.DoWebTransportWriteData. Applications never do this.
procedure TMyTransport.WireSession(const aSession: TsgcWebTransportSession);
begin
  aSession.OnOpenStream := DoOpenStream;         // gives streams real writers
  aSession.OnWriteData := DoWriteData;           // fallback if that fails
  aSession.OnSendDatagramData := DoSendDatagram;
end;

procedure TMyTransport.DoWriteData(Sender: TObject; const aData: TBytes);
begin
  // Session-level fallback: no stream context is available here, so all we
  // can do is put the bytes on the connection's default (CONNECT) stream.
  GetQUICComponent.Write(FHost, FPort, aData);
end;

Back to Events