Sisk

Cadente

Esta página foi traduzida automaticamente do inglês. Ler o original

Cadente é uma implementação experimental gerenciada de listener HTTP/1.1 para o Sisk. Ela serve como substituta do System.Net.HttpListener padrão, oferecendo maior controle e flexibilidade, especialmente em plataformas não Windows.

Visão geral #

Por padrão, o Sisk usa HttpListener (do System.Net) como seu mecanismo subjacente de servidor HTTP. Embora o HttpListener seja estável e performático no Windows (onde utiliza o driver kernel-mode HTTP.sys), sua implementação no Linux e macOS é gerenciada e historicamente apresenta limitações, como a falta de suporte nativo a SSL (exigindo um proxy reverso como o Nginx) e características de desempenho variáveis.

Cadente tem como objetivo resolver esses problemas fornecendo um servidor HTTP/1.1 totalmente gerenciado escrito em C#. Seus principais objetivos são:

  • Suporte nativo a SSL: Funciona em todas as plataformas sem necessidade de proxies externos ou configuração complexa.
  • Consistência multiplataforma: Comportamento idêntico no Windows, Linux e macOS.
  • Desempenho: Projetado para ser uma alternativa de alto desempenho ao HttpListener gerenciado.
  • Independência: Desacoplado do System.Net.HttpListener, isolando o Sisk de possíveis futuras descontinuações ou falta de manutenção desse componente no .NET.

Aviso

Status Experimental

Cadente está atualmente em estágio experimental (Beta). Ainda não é recomendado para ambientes de produção críticos. A API e o comportamento podem mudar.

Instalação #

Cadente está disponível como um pacote separado. Para usá-lo com o Sisk, você precisa do pacote Sisk.Cadente.CoreEngine.

Bash
dotnet add package Sisk.Cadente.CoreEngine

Sisk.Cadente e Sisk.Cadente.CoreEngine têm como alvo .NET 9 e .NET 10. Eles não podem ser usados em projetos que visam .NET 8, embora Sisk.HttpServer o suporte.

Usando com Sisk #

Para usar o Cadente como o mecanismo HTTP da sua aplicação Sisk, você precisa configurar o HttpServer para usar CadenteHttpServerEngine em vez do mecanismo padrão.

O CadenteHttpServerEngine adapta o HttpHost do Cadente à abstração HttpServerEngine exigida pelo Sisk.

C#
using Sisk.Core.Http;
using Sisk.Cadente.CoreEngine;

using var host = HttpServer.CreateBuilder()
    .UseEngine<CadenteHttpServerEngine>()
    .UseSsl(certificate: CertificateHelper.CreateTrustedDevelopmentCertificate("localhost"))
    .Build();

await host.StartAsync();

Quando um host de escuta está configurado com SSL, HttpServer.ListeningPrefixes relata seus endereços com o esquema https. Se um cliente enviar HTTP simples para uma porta configurada com SSL, o Cadente responde com um redirecionamento 301 Moved Permanently para o endereço https do mesmo host e caminho.

Configuração avançada #

Você pode personalizar a instância subjacente de HttpHost passando uma ação de configuração ao construtor CadenteHttpServerEngine. Isso é útil para configurar tempos limite ou outras definições de baixo nível.

C#
using var engine = new CadenteHttpServerEngine(host =>
{
    // Configura tempos limite de leitura/gravação do cliente
    host.TimeoutManager.ClientReadTimeout = TimeSpan.FromSeconds(30);
    host.TimeoutManager.ClientWriteTimeout = TimeSpan.FromSeconds(30);
});

Uso autônomo #

Embora seja projetado principalmente para o Sisk, o Cadente pode ser usado como um servidor HTTP autônomo (similar ao HttpListener).

C#
using Sisk.Cadente;

var host = new HttpHost(15000)
{
    Handler = new MyHostHandler()
};

host.Start();
Thread.Sleep(-1);

class MyHostHandler : HttpHostHandler
{
    public override async Task OnContextCreatedAsync(HttpHost host, HttpHostContext context)
    {
        context.Response.StatusCode = 200;

        using var stream = await context.Response.GetResponseStreamAsync(chunked: true);
        using var writer = new StreamWriter(stream);
        await writer.WriteLineAsync("Hello, world!");
    }
}

Quando o corpo da resposta é pequeno e já está na memória, WriteInlineContent e WriteInlineContentAsync escrevem os cabeçalhos e o corpo em uma única operação. A resposta deve ter um cabeçalho Content-Length:

C#
byte[] body = "Hello, world!"u8.ToArray();

context.Response.StatusCode = 200;
context.Response.Headers.Set(new HttpHeader("Content-Length", body.Length.ToString()));
await context.Response.WriteInlineContentAsync(body);

Validação de requisição #

Cadente valida a estrutura da requisição antes que ela chegue ao manipulador. Desde a versão 1.7, ele:

  • suporta requisições em pipeline em conexões keep-alive;
  • rejeita métodos de requisição que não são tokens HTTP válidos e alvos de requisição que contêm bytes fora do intervalo ASCII visível (%x21-7E);
  • rejeita requisições cujo Transfer-Encoding seja diferente de um único valor chunked, e requisições com cabeçalhos Content-Length conflitantes;
  • responde com 431 Request Header Fields Too Large e fecha a conexão quando a linha de requisição e os cabeçalhos excedem 8 KB.

Requisições inválidas são respondidas com um erro e a conexão é fechada, sem chamar o manipulador.

Digite para pesquisar na documentação e na referência da API.