TsgcHTTP3Server › Events › OnH3TunnelData
Fires when payload arrives on an established CONNECT tunnel stream.
property OnH3TunnelData: TsgcHTTP3ServerTunnelDataEvent;
// TsgcHTTP3ServerTunnelDataEvent = procedure(Sender: TObject; const aConnection: TsgcQUICServerConnection; aStreamId: Int64; const aData: TBytes) of object
—
| Name | Type | Description |
|---|---|---|
Sender | TObject | The TsgcHTTP3Server instance that raised the event. |
aConnection | const TsgcQUICServerConnection | QUIC connection that owns the tunnel. Pass it back to TunnelSend to reply. |
aStreamId | Int64 | Identifier of the CONNECT request stream acting as the tunnel. Identifies which tunnel the bytes belong to when a connection has several. |
aData | const TBytes | Payload of the DATA frame, that is, the tunneled bytes exactly as the peer framed them. |
OnH3TunnelData is the read side of an HTTP/3 tunnel (RFC 9114 section 4.4, and Extended CONNECT per RFC 9220). A request stream becomes a tunnel when a CONNECT request is answered with a 2xx status from OnH3Request. From that point the server keeps the stream open and stops interpreting DATA frames on it as a request body: every DATA frame is delivered here instead, and the stream never completes into another OnH3Request.
The event therefore only fires on streams that have already been accepted as tunnels. It never fires for a CONNECT you rejected with a non-2xx status, since such a stream is answered and finished like any ordinary request.
Each event delivers one DATA frame. HTTP/3 does not promise that a peer's logical message maps to one frame, so a protocol carried over the tunnel must define its own message boundaries rather than assuming one event equals one message. Reply on the same tunnel with TunnelSend, passing the aConnection and aStreamId received here.
An exception raised inside the handler is caught and discarded by the server so a failing tunnel handler cannot drop the connection. This means errors are silent: handle and log them inside the handler if you need to see them.
The event is raised on the server's background listener thread, the same thread that reads the QUIC connection, so it must not touch the UI directly and it should return quickly, since the connection is not being serviced while the handler runs.
This member is currently available in the Delphi/C++Builder implementation only.
oServer.OnH3Request := OnH3RequestEvent;
oServer.OnH3TunnelData := OnH3TunnelDataEvent;
procedure OnH3RequestEvent(Sender: TObject; const aConnection:
TsgcQUICServerConnection; const aRequest: TsgcHTTP3Request;
const aResponse: TsgcHTTP3Response);
begin
// a 2xx answer to a CONNECT turns the stream into a tunnel
if aRequest.Method = h3meConnect then
aResponse.StatusCode := 200
else
aResponse.StatusCode := 404;
end;
procedure OnH3TunnelDataEvent(Sender: TObject; const aConnection:
TsgcQUICServerConnection; aStreamId: Int64; const aData: TBytes);
begin
Log('tunnel ' + IntToStr(aStreamId) + ': ' + IntToStr(Length(aData)) + ' bytes');
// echo the payload back through the same tunnel
TsgcHTTP3Server(Sender).TunnelSend(aConnection, aStreamId, aData);
end;