# Cadente

Source: https://docs.sisk-framework.org/ja/docs/cadente.html

Cadente は Sisk 用の実験的なマネージド HTTP/1.1 リスナー実装です。デフォルトの `System.Net.HttpListener` の代替として機能し、特に非 Windows プラットフォームで、より高い制御性と柔軟性を提供します。

## 概要

デフォルトでは、Sisk は基盤となる HTTP サーバーエンジンとして `HttpListener`（`System.Net` から）を使用します。`HttpListener` は Windows 上ではカーネルモードの HTTP.sys ドライバーを利用し、安定かつ高性能ですが、Linux や macOS での実装はマネージドであり、歴史的にネイティブ SSL サポートがない（Nginx などのリバースプロキシが必要）や、パフォーマンス特性が一定でないといった制限がありました。

Cadente はこれらの問題を解決するために、C# で書かれた完全マネージドの HTTP/1.1 サーバーを提供します。その主な目標は次のとおりです：

- **ネイティブ SSL サポート:** 外部プロキシや複雑な設定を必要とせず、すべてのプラットフォームで動作します。
- **クロスプラットフォームの一貫性:** Windows、Linux、macOS で同一の動作を保証します。
- **パフォーマンス:** マネージド `HttpListener` の高性能な代替として設計されています。
- **独立性:** `System.Net.HttpListener` から分離され、.NET における将来的な非推奨化やメンテナンス停止の影響から Sisk を保護します。

> [!WARNING]
> **実験的ステータス**
> 
> Cadente は現在実験段階（ベータ）にあります。重要な本番環境での使用はまだ推奨されません。API や動作は変更される可能性があります。

## インストール

Cadente は別パッケージとして提供されています。Sisk で使用するには `Sisk.Cadente.CoreEngine` パッケージが必要です。

```bash
dotnet add package Sisk.Cadente.CoreEngine
```

`Sisk.Cadente` と `Sisk.Cadente.CoreEngine` は .NET 9 および .NET 10 を対象としています。`Sisk.HttpServer` が .NET 8 をサポートしているにもかかわらず、.NET 8 を対象としたプロジェクトでは使用できません。

## Sisk での使用

Cadente を Sisk アプリケーションの HTTP エンジンとして使用するには、デフォルトエンジンの代わりに `CadenteHttpServerEngine` を使用するように `HttpServer` を構成する必要があります。

`CadenteHttpServerEngine` は Cadente の `HttpHost` を Sisk が必要とする `HttpServerEngine` 抽象に適合させます。

```csharp
using Sisk.Core.Http;
using Sisk.Cadente.CoreEngine;

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

await host.StartAsync();
```

リスニングホストが SSL で構成されている場合、[HttpServer.ListeningPrefixes](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServer.ListeningPrefixes.md) は `https` スキームのアドレスを報告します。クライアントが SSL 構成されたポートにプレーン HTTP を送信した場合、Cadente は同じホストとパスの `https` アドレスへ `301 Moved Permanently` リダイレクトで応答します。

### 高度な構成

`CadenteHttpServerEngine` コンストラクタにセットアップアクションを渡すことで、基盤となる `HttpHost` インスタンスをカスタマイズできます。タイムアウトやその他の低レベル設定を構成する際に便利です。

```csharp
using var engine = new CadenteHttpServerEngine(host =>
{
    // クライアントの読み取り/書き込みタイムアウトを設定
    host.TimeoutManager.ClientReadTimeout = TimeSpan.FromSeconds(30);
    host.TimeoutManager.ClientWriteTimeout = TimeSpan.FromSeconds(30);
});
```

## スタンドアロン使用

主に Sisk 用に設計されていますが、Cadente はスタンドアロンの HTTP サーバーとしても使用できます（`HttpListener` に似ています）。

```csharp
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!");
    }
}
```

レスポンスボディが小さくメモリ上にある場合、`WriteInlineContent` と `WriteInlineContentAsync` はヘッダーとボディを一度の操作で書き込みます。レスポンスには `Content-Length` ヘッダーが必要です：

```csharp
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);
```

## リクエストの検証

Cadente はハンドラに到達する前にリクエストのフレーミングを検証します。バージョン 1.7 以降、以下を行います：

- キープアライブ接続上でパイプライン化されたリクエストをサポートします；
- 有効な HTTP トークンでないリクエストメソッドや、表示可能な ASCII 範囲（`%x21-7E`）外のバイトを含むリクエストターゲットを拒否します；
- `Transfer-Encoding` が単一の `chunked` 以外の場合や、矛盾する `Content-Length` ヘッダーがあるリクエストを拒否します；
- リクエストラインとヘッダーが 8 KB を超えると `431 Request Header Fields Too Large` で応答し、接続を閉じます。

無効なリクエストにはエラーで応答し、ハンドラは呼び出されずに接続が閉じられます。
