TsgcHTTP3Server › Events › OnH3TunnelData

OnH3TunnelData Event

Fires when payload arrives on an established CONNECT tunnel stream.

Syntax

property OnH3TunnelData: TsgcHTTP3ServerTunnelDataEvent;
// TsgcHTTP3ServerTunnelDataEvent = procedure(Sender: TObject; const aConnection: TsgcQUICServerConnection; aStreamId: Int64; const aData: TBytes) of object

Default Value

—

Parameters

NameTypeDescription
SenderTObjectThe TsgcHTTP3Server instance that raised the event.
aConnectionconst TsgcQUICServerConnectionQUIC connection that owns the tunnel. Pass it back to TunnelSend to reply.
aStreamIdInt64Identifier of the CONNECT request stream acting as the tunnel. Identifies which tunnel the bytes belong to when a connection has several.
aDataconst TBytesPayload of the DATA frame, that is, the tunneled bytes exactly as the peer framed them.

Remarks

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.

Example


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;

Back to Events