TsgcWebTransportSession › Events › OnWriteData
Transport hook. The session-level fallback writer, used only by streams that have no per-stream writer of their own.
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);
| Name | Type | Description |
|---|---|---|
Sender | TObject | The 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. |
aData | const TBytes | The 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. |
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.
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.
// 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;