sgcQUIC em cinco minutos

QUIC e HTTP/3 em Object Pascal nativo, sobre o mecanismo QUIC que está dentro do OpenSSL. Acompanham quatro componentes. O caminho mais curto até algo funcionando é o cliente HTTP/3, então esta página faz uma requisição, lê o código de status e é precisa sobre qual OpenSSL você precisa.

QUIC RFC 9000 e HTTP/3 RFC 9114
OpenSSL 3.2 ou posterior para o cliente
Edição All-Access

O que a primeira requisição precisa

Um componente, uma URL e duas bibliotecas OpenSSL ao lado do seu executável.

Componente

TsgcHTTP3Client na página SGC QUIC da paleta, declarado em sgcQUIC.pas. A página também traz TsgcQUICClient, TsgcQUICServer e TsgcHTTP3Server.

Unit

sgcQUIC para o componente. Adicione sgcHTTP3_Classes para TsgcHTTP3Response e sgcHTTP_AltSvc se você tratar o evento Alt-Svc.

A chamada

Get(aURL) retorna o corpo como uma string e gera uma exceção em caso de falha. O código de status e os cabeçalhos chegam separadamente, em OnResponse.

O requisito de OpenSSL

O cliente precisa da API QUIC do OpenSSL 3.2 ou posterior, ou de uma compilação quictls. O servidor precisa da 3.5 ou posterior, porque chama uma API que só existe nela. Distribua libcrypto-3.dll e libssl-3.dll ao lado do seu executável, como faz toda pasta de demo.

Requisitos e edições

A coluna de edição é o define que controla o código, com a linha em que ele aparece em Source/sgcVer.inc.

O quê Valor
IDE Do Delphi 7 ao RAD Studio 13, e do C++Builder 2007 ao 13. Não há um download separado do sgcQUIC: os componentes estão no grupo de pacotes do sgcWebSockets.
Cláusula uses sgcQUIC, mais sgcHTTP3_Classes para o objeto de resposta e sgcHTTP_AltSvc para os tipos Alt-Svc.
Define do pacote SGC_PACK_QUIC é definido na linha 872, dentro do bloco {$IFDEF SGC_EDT_ALL} que vai da linha 870 à linha 874. Ou seja, All-Access.
Defines de recursos Dentro do bloco {$IFDEF SGC_PACK_QUIC}, nas linhas 894 a 899: SGC_QUIC na linha 896, SGC_HTTP3 na linha 897 e SGC_WEBTRANSPORT na linha 898. Os três ficam dentro de um {$IFDEF SGC_INDY_LIB} na linha 895, então uma compilação sem a biblioteca Indy personalizada não recebe nenhum deles.
OpenSSL, cliente 3.2 ou posterior, ou uma compilação quictls. A própria biblioteca informa isso: o erro gerado quando o QUIC não está disponível diz QUIC is not available. Requires quictls/openssl or OpenSSL 3.2+.
OpenSSL, servidor 3.5 ou posterior. O servidor QUIC chama SSL_new_listener, e o erro gerado quando ela está ausente diz QUIC Server requires OpenSSL 3.5 or later. O msquic não é usado e não é necessário.
Plataformas Nenhuma restrição de plataforma no escopo da unit em sgcQUIC.pas, sgcQUIC_Client.pas, sgcHTTP3_Client.pas ou sgcHTTP3_Server.pas, e os quatro componentes são registrados com ComponentPlatforms(0). A unit do servidor seleciona a API de sockets por plataforma, com um ramo para Windows e outro para POSIX.

Não tem certeza de que o mecanismo está presente em tempo de execução? Chame IsOpenSSL_QUIC_Available, que retorna se o OpenSSL que você carregou expõe o método de cliente QUIC. O demo de cliente QUIC que acompanha o pacote registra isso na inicialização exatamente por esse motivo.

Instale e encontre a página da paleta

Não há um instalador separado do sgcQUIC. Os componentes chegam com o sgcWebSockets e aparecem quando a edição os habilita.

1. Descompacte

Descompacte o download do sgcWebSockets em uma pasta, chamada de {$DIR} abaixo.

2. Caminho da biblioteca

Tools, Options, Library. Adicione {$DIR}\source e a pasta lib da sua IDE, por exemplo {$DIR}\libD13\$(Platform).

3. Compile os pacotes

Abra o grupo de pacotes da versão da sua IDE em {$DIR}\Packages\. Compile primeiro o .dpk de runtime e depois instale o de design-time, o dcl. Não existe um pacote específico do QUIC.

4. Confira a paleta

Aparece uma página chamada SGC QUIC com TsgcQUICClient, TsgcQUICServer, TsgcHTTP3Client e TsgcHTTP3Server. Se a página não aparecer, a compilação não é All-Access, porque SGC_PACK_QUIC só é definido na linha 872, dentro desse bloco.

5. Coloque o OpenSSL ao lado do exe

Copie libcrypto-3.dll e libssl-3.dll para ao lado do seu executável, 3.2 ou posterior para um cliente e 3.5 ou posterior para um servidor. Toda pasta em Demos\22.QUIC_Protocol as inclui, então você pode copiar de lá.

Uma requisição HTTP/3

Crie o cliente, conecte três eventos, chame Get. A resposta volta como uma string e o código de status chega em OnResponse.

FHTTP3Client.pas
uses
  Classes, SysUtils,
  // sgc
  sgcQUIC, sgcHTTP3_Classes;

procedure TfrmHTTP3Client.FormCreate(Sender: TObject);
begin
  FClient := TsgcHTTP3Client.Create(nil);
  FClient.OnConnect := OnH3Connect;
  FClient.OnError := OnH3Error;
  FClient.OnResponse := OnH3Response;
  FClient.TLSOptions.VerifyCertificate := True;
  FClient.ConnectTimeout := 10000;
  FClient.ReadTimeout := 30000;
  FClient.UserAgent := 'sgcWebSockets/HTTP3Client';
end;

procedure TfrmHTTP3Client.btnGetClick(Sender: TObject);
var
  vResult: string;
begin
  try
    // the target comes from the URL, because Host and Port
    // are read-only on this component
    vResult := FClient.Get('https://www.google.com/');
    memoBody.Lines.Text := vResult;
    DoLog('Response received: ' + IntToStr(Length(vResult)) + ' bytes');
  except
    on E: Exception do
      DoLog('Error: ' + E.Message);
  end;
end;

Post, Put e Delete têm o mesmo formato, e cada um tem uma sobrecarga com stream para um corpo que você não quer manter em uma string. Connect(const aHost: string; aPort: Integer = 443) abre a conexão antes da primeira requisição quando você quer separar as duas etapas.

FHTTP3Client.pas
// OnConnect and OnDisconnect are plain TNotifyEvent on this
// component: one parameter, no connection object.
procedure TfrmHTTP3Client.OnH3Connect(Sender: TObject);
begin
  DoLog('Connected to ' + FClient.Host + ':' + IntToStr(FClient.Port));
end;

procedure TfrmHTTP3Client.OnH3Error(Sender: TObject; const aError: string);
begin
  DoLog('Error: ' + aError);
end;

procedure TfrmHTTP3Client.OnH3Response(Sender: TObject;
  const aResponse: TsgcHTTP3Response);
begin
  DoLog('Status: ' + IntToStr(aResponse.StatusCode));
  memoHeaders.Lines.Assign(aResponse.Headers);
end;

Ler FClient.Host e FClient.Port dentro de OnConnect é exatamente para o que essas duas propriedades servem. Elas informam a conexão, não a configuram.

FQUICClient.pas
uses
  Classes, SysUtils,
  // sgc
  sgcIdSSLOpenSSLHeaders;

procedure TfrmQUICClient.FormCreate(Sender: TObject);
begin
  DoLog('OpenSSL QUIC Support:');
  DoLog('  quictls API: ' +
    BoolToStr(IsOpenSSL_QUIC_TLS_Available, True));
  DoLog('  Builtin QUIC (3.2+): ' +
    BoolToStr(IsOpenSSL_QUIC_Available, True));
end;

Execute isto uma vez antes de qualquer outra coisa. Se os dois retornarem false, o OpenSSL ao lado do seu executável não tem QUIC, e toda falha de conexão depois disso é sintoma desse único fato, e não da rede.

As duas primeiras abas vêm do demo que acompanha o pacote, Demos\22.QUIC_Protocol\03.HTTP3_Client\FHTTP3Client.pas, com os controles do formulário substituídos por literais. A terceira é a verificação de disponibilidade em tempo de execução de 01.QUIC_Client\FQUICClient.pas. Há seis demos de QUIC nessa pasta, incluindo um par de WebTransport.

Leia o código de status, não apenas o corpo

Get retorna o corpo. O objeto de resposta traz todo o resto, e ele chega em um evento próprio.

O valor de retorno

Get retorna o corpo da resposta como uma string e gera uma exceção em caso de falha, por isso o demo o envolve em um try except. Um corpo com o tamanho esperado é a primeira prova.

OnResponse

procedure(Sender: TObject; const aResponse: TsgcHTTP3Response). StatusCode é o número que você realmente quer, Headers é um TStringList e GetDataAsString devolve o corpo novamente a partir do objeto de resposta.

OnConnect

Um TNotifyEvent simples. Se ele dispara, o QUIC negociou e a sessão HTTP/3 foi aberta, que é a parte com maior chance de falhar na primeira execução.

Antes de culpar o código

IsOpenSSL_QUIC_Available responde à única pergunta que vale a pena fazer primeiro. O QUIC também roda sobre UDP 443, e uma rede que permite TCP 443 não necessariamente permite isso.

O que costuma dar errado na primeira vez

Seis problemas respondem por quase toda primeira requisição que falha.

Não é possível atribuir a Host ou Port

Elas são somente leitura em TsgcHTTP3Client, declaradas como property Host: string read FHost e property Port: Integer read FPort. Informam onde o cliente está conectado. Para escolher um destino, passe uma URL completa para Get ou chame Connect(aHost, aPort).

O QUIC não está disponível

O OpenSSL que você carregou é antigo demais ou foi compilado sem QUIC. O cliente precisa da 3.2 ou posterior, ou de quictls. Verifique em tempo de execução com IsOpenSSL_QUIC_Available antes de culpar a rede.

O servidor não inicia

O servidor QUIC precisa do OpenSSL 3.5 ou posterior, porque chama SSL_new_listener. Uma compilação 3.2 basta para o cliente e não para o servidor, e a mensagem de erro diz isso explicitamente.

Aridade errada em OnConnect

OnConnect e OnDisconnect neste componente são TNotifyEvent simples, então o manipulador recebe apenas Sender: TObject. Eles não entregam um objeto de conexão, ao contrário dos componentes WebSocket.

O UDP está bloqueado

O QUIC roda sobre UDP na porta 443, e muitas redes corporativas permitem TCP 443 e descartam UDP 443. Se um navegador consegue alcançar o host por HTTP/3 e seu aplicativo não, suspeite do firewall antes do código.

A página da paleta não aparece

SGC_PACK_QUIC só é definido na linha 872, dentro do bloco All-Access. Ele também exige SGC_INDY_LIB, porque todo o bloco do pacote nas linhas 894 a 899 fica dentro dessa proteção.

Além da primeira requisição

Quatro direções, todas dentro do mesmo pacote.

Execute um servidor HTTP/3

TsgcHTTP3Server serve HTTP/3 diretamente sobre QUIC. Lembre-se do requisito mínimo de OpenSSL 3.5 no lado do servidor.

Componente servidor HTTP/3

QUIC puro, sem HTTP

TsgcQUICClient e TsgcQUICServer oferecem streams QUIC sem a camada HTTP/3, que é o que você quer para um protocolo personalizado que precisa de multiplexação sem bloqueio de head of line.

Cliente QUIC e servidor QUIC

WebTransport

Streams bidirecionais e datagramas para um navegador sobre HTTP/3, controlados por SGC_WEBTRANSPORT na linha 898. Acompanham dois demos.

Recursos do sgcQUIC

Descubra o HTTP/3 a partir do HTTP/2

Um servidor anuncia o HTTP/3 com um cabeçalho Alt-Svc. Trate OnAltSvc e você pode atualizar uma conexão existente para QUIC quando a origem oferecer.

Cliente HTTP/2

Referência, demos e documentação

Os projetos de demo acompanham o download, em Demos\22.QUIC_Protocol. São seis.

Componente cliente HTTP/3 O que TsgcHTTP3Client expõe, propriedade por propriedade.
Componente servidor HTTP/3 O lado do servidor, incluindo o requisito de OpenSSL 3.5.
Componente cliente QUIC Streams QUIC puros, sem a camada HTTP/3.
Recursos do sgcQUIC QPACK, 0-RTT, migração de conexão, WebTransport e o resto.
Baixe a versão de avaliação Um instalador por versão da IDE, com os componentes QUIC já incluídos.
Ajuda online A referência gerada, sempre alinhada com a versão atual.

Leitura relacionada: os componentes cliente e servidor QUIC e os componentes HTTP/3. Se você está escolhendo entre transportes, o guia de transportes em tempo real os compara. Cada produto tem seu próprio início rápido, listado na página de primeiros passos.

Perguntas sobre o início rápido do sgcQUIC

TsgcHTTP3Client, da unit sgcQUIC, na página SGC QUIC da paleta. Adicione sgcHTTP3_Classes para TsgcHTTP3Response, que é o tipo de parâmetro de OnResponse, e sgcHTTP_AltSvc se você tratar OnAltSvc. A página da paleta também traz TsgcQUICClient, TsgcQUICServer e TsgcHTTP3Server.
Depende de qual lado você está construindo. O cliente precisa da API QUIC adicionada no OpenSSL 3.2, ou de uma compilação quictls, e a biblioteca diz isso na mensagem que gera: QUIC is not available. Requires quictls/openssl or OpenSSL 3.2+. O servidor precisa da 3.5 ou posterior, porque chama SSL_new_listener, e sua mensagem de erro cita essa versão explicitamente. Distribua libcrypto-3.dll e libssl-3.dll ao lado do seu executável. O msquic não é usado.
Porque elas são somente leitura. TsgcHTTP3Client as declara como property Host: string read FHost e property Port: Integer read FPort, então informam a conexão atual em vez de configurá-la. Passe uma URL completa para Get, Post, Put ou Delete, ou chame antes Connect(const aHost: string; aPort: Integer = 443).
Um TNotifyEvent simples, ou seja, procedure(Sender: TObject). O mesmo vale para OnDisconnect. Isso difere dos componentes WebSocket, cujos eventos entregam um TsgcWSConnection, e é uma fonte comum de erro de compilação logo no início. OnResponse é procedure(Sender: TObject; const aResponse: TsgcHTTP3Response) e OnError é procedure(Sender: TObject; const aError: string).
A partir do objeto de resposta em OnResponse. TsgcHTTP3Response expõe StatusCode, Headers como um TStringList e GetDataAsString para o corpo. O método Get em si retorna apenas o corpo como string, e é por isso que o demo também conecta OnResponse.
SGC_PACK_QUIC é definido na linha 872 de sgcVer.inc, dentro do bloco {$IFDEF SGC_EDT_ALL} que vai da linha 870 à linha 874. Ou seja, All-Access. O próprio bloco do pacote, linhas 894 a 899, também fica dentro de um {$IFDEF SGC_INDY_LIB}, então a biblioteca Indy personalizada também precisa fazer parte da compilação. Dentro desse bloco, SGC_QUIC é a linha 896, SGC_HTTP3 é a linha 897 e SGC_WEBTRANSPORT é a linha 898.
Não. O instalador de avaliação é por versão da IDE e já contém os componentes QUIC e HTTP/3, e não há um arquivo de pacote específico do QUIC. Instale o sgcWebSockets e a página SGC QUIC da paleta aparece quando a edição a habilita.
Sim, e você deveria. IsOpenSSL_QUIC_Available retorna se o OpenSSL carregado expõe o método de cliente QUIC, e IsOpenSSL_QUIC_TLS_Available faz o mesmo para os callbacks TLS do QUIC. O demo de cliente QUIC que acompanha o pacote grava os dois em seu log na inicialização, o que transforma uma falha de conexão misteriosa em uma resposta de uma linha.
Melhor custo-benefício: All-AccessTodos os produtos da eSeGeCe, com Suporte Premium incluído, a partir de €1,059/ano.
Ver preços do All-Access

Pronto para experimentar o HTTP/3 a partir do Delphi?

Baixe a versão de avaliação e execute o demo do cliente HTTP/3 contra uma origem real.