diff --git a/README.md b/README.md index 3928e1d..c86a3ea 100644 --- a/README.md +++ b/README.md @@ -109,13 +109,13 @@ A _provider_ is the HTTP transport that owns the socket and hands requests to yo | ----------------------------------------------------------------------------------------------- | ----------------------- | :------------------: | :-------------------------: | | **Indy** _(Delphi default for self-hosted)_ | _(none)_ |    ✔️ |     n/a | | **`fphttpserver`** _(FPC default for self-hosted)_ | _(none)_ |    n/a |     ✔️ | -| 🆕 **[horse-provider-crosssocket](https://github.com/freitasjca/horse-provider-crosssocket)** | `HORSE_CROSSSOCKET` |    ✔️ |     ✔️ | +| 🆕 **[horse-provider-crosssocket](https://github.com/freitasjca/horse-provider-crosssocket)** | `HORSE_PROVIDER_CROSSSOCKET` |    ✔️ |     ✔️ | | 🆕 **[horse-provider-mormot](https://github.com/freitasjca/horse-provider-mormot)** | `HORSE_PROVIDER_MORMOT` |    ✔️ |     ✔️ | | 🆕 **[horse-provider-ics](https://github.com/freitasjca/horse-provider-ics)** _(Delphi; Win + Linux/macOS)_ | `HORSE_PROVIDER_ICS` |    ✔️ |     ❌ | | 🆕 **[HTTP.sys](./doc/httpsys.md)** _(Windows kernel-mode driver for ultra-low latency)_ | `HORSE_PROVIDER_HTTPSYS` |    ✔️ |     ✔️ | | 🆕 **[epoll](./doc/epoll.md)** _(Linux-native asynchronous event loop)_ | `HORSE_PROVIDER_EPOLL` |    ✔️ |     ✔️ | -| 🆕 **[horse-provider-ics](https://github.com/freitasjca/horse-provider-ics)** _(Delphi; Win + Linux/macOS)_ | `HORSE_PROVIDER_ICS` |    ✔️ |     ❌ | | 🆕 **[IOCP](./doc/iocp.md)** _(Windows-native asynchronous I/O completion ports)_ | `HORSE_PROVIDER_IOCP` |    ✔️ |     ✔️ | +| 🆕 **[horse-provider-nghttp2](https://github.com/freitasjca/horse-provider-nghttp2)** _(HTTP/2 + gRPC; requires [Delphi-nghttp2](https://github.com/freitasjca/Delphi-nghttp2))_ | `HORSE_PROVIDER_NGHTTP2` |    ✔️ |     ✔️ | > **Note** — Apache / ISAPI / CGI / FastCGI Application types (below) do **not** use any of these Providers. The host process (Apache, IIS, the web server) owns the socket; Horse runs in-process. See [Providers & Application types](./doc/providers.md) for the full model. @@ -123,6 +123,8 @@ A _provider_ is the HTTP transport that owns the socket and hands requests to yo > **OverbyteICS installation** — the ICS Provider requires [OverbyteICS](https://wiki.overbyte.eu/wiki/index.php/ICS_Download) (v9.x). **Install ICS following the official ICS instructions** — download/clone ICS and add its `Source/` folder to your project search path (ICS is not Boss-installable). For TLS, the OpenSSL libraries ship with ICS (DLLs on Windows, `.so` on Linux). The ICS Provider is **Delphi only — Windows and POSIX (Linux64 / macOS)** via ICS's own `Ics.Posix.*` message pump (on Linux use `HORSE_APPTYPE_DAEMON` + `THorseICSLinuxDaemonApp.Run`); a **Lazarus/FPC** port is not viable — ICS's POSIX layer rides the Delphi POSIX RTL and ICS compiles out OpenSSL under FPC. Its distinctive value is ICS's OpenSSL 3.x / 4.x stack (TLS 1.3, SNI, mTLS). See [horse-provider-ics](https://github.com/freitasjca/horse-provider-ics) for setup, the A–K test suite, and known limitations. +> **Delphi-nghttp2 installation** — `boss install github.com/freitasjca/horse-provider-nghttp2` pulls the provider and its [`Delphi-nghttp2`](https://github.com/freitasjca/Delphi-nghttp2) dependency automatically. At runtime, **libnghttp2 ≥ 1.59** must be present (dynamic-loaded — no link-time dependency): on Windows, download the prebuilt DLL from the [curl for Windows bundle](https://curl.se/windows/); on Linux, `sudo apt install libnghttp2-14`; on macOS, `brew install nghttp2`. For TLS and gRPC, OpenSSL 3.x or 1.1 is auto-detected. **FPC trunk 3.3.1 required** (FPC 3.2.2 is a hard blocker). See [horse-provider-nghttp2](https://github.com/freitasjca/horse-provider-nghttp2) for the full setup guide, TLS/mTLS config, and gRPC samples. + > **HttpSys** — **no install**: the `Horse.Provider.HttpSys` unit ships with Horse and binds directly to Windows' `httpapi.dll` (http.sys), so there's no external library. Set `HORSE_PROVIDER_HTTPSYS` (Windows; Delphi or Lazarus). Because http.sys is a kernel-mode, machine-wide HTTP stack, binding a non-`localhost` host or a privileged port needs a one-time URL reservation (`netsh http add urlacl url=http://+:9000/ user=Everyone`) or Administrator rights; HTTPS uses the Windows certificate store via `netsh http add sslcert`. It is mutually exclusive with the CrossSocket / mORMot / ICS Providers (one transport per build). > **IOCP** — **no install**: the `Horse.Provider.IOCP` unit ships with Horse and binds directly to Windows' input/output completion ports using Winsock2 API for extremely high performance and scalability on Windows self-hosted application types. Set `HORSE_PROVIDER_IOCP` (Windows; Delphi or Lazarus). It is mutually exclusive with Indy, HttpSys and other socket providers (one transport per build). @@ -199,6 +201,7 @@ This is a list of middlewares that are created by the Horse community, please cr | [isaquepinheiro/horse-jsonbr](https://github.com/HashLoad/JSONBr) |    ✔️ |     ❌ | | [IagooCesaar/Horse-JsonInterceptor](https://github.com/IagooCesaar/Horse-JsonInterceptor) |    ✔️ |     ❌ | | [dliocode/horse-datalogger](https://github.com/dliocode/horse-datalogger) |    ✔️ |     ❌ | +| [marcobreveglieri/horse-prometheus-metrics](https://github.com/marcobreveglieri/horse-prometheus-metrics) |    ✔️ |     ❌ | | [weslleycapelari/horse-documentation](https://github.com/weslleycapelari/horse-documentation) |    ✔️ |     ❌ | | [weslleycapelari/horse-validator](https://github.com/weslleycapelari/horse-validator) |    ✔️ |     ❌ | | [regyssilveira/horse-rate-limit](https://github.com/regyssilveira/horse-rate-limit) |    ✔️ |     ✔️ | diff --git a/README.pt-BR.md b/README.pt-BR.md index 4fa8986..dbc0c6f 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -109,13 +109,13 @@ Um _provider_ é o transporte HTTP que é dono do socket e entrega requisições | ----------------------------------------------------------------------------------------------- | ----------------------- | :------------------: | :-------------------------: | | **Indy** _(padrão Delphi para self-hosted)_ | _(nenhum)_ |    ✔️ |     n/a | | **`fphttpserver`** _(padrão FPC para self-hosted)_ | _(nenhum)_ |    n/a |     ✔️ | -| 🆕 **[horse-provider-crosssocket](https://github.com/freitasjca/horse-provider-crosssocket)** | `HORSE_CROSSSOCKET` |    ✔️ |     ✔️ | +| 🆕 **[horse-provider-crosssocket](https://github.com/freitasjca/horse-provider-crosssocket)** | `HORSE_PROVIDER_CROSSSOCKET` |    ✔️ |     ✔️ | | 🆕 **[horse-provider-mormot](https://github.com/freitasjca/horse-provider-mormot)** | `HORSE_PROVIDER_MORMOT` |    ✔️ |     ✔️ | | 🆕 **[horse-provider-ics](https://github.com/freitasjca/horse-provider-ics)** _(Delphi; Win + Linux/macOS)_ | `HORSE_PROVIDER_ICS` |    ✔️ |     ❌ | | 🆕 **[HTTP.sys](./doc/httpsys.pt-BR.md)** _(driver de modo kernel do Windows para ultra-baixa latência)_ | `HORSE_PROVIDER_HTTPSYS` |    ✔️ |     ✔️ | | 🆕 **[epoll](./doc/epoll.pt-BR.md)** _(event loop assíncrono nativo do Linux)_ | `HORSE_PROVIDER_EPOLL` |    ✔️ |     ✔️ | -| 🆕 **[horse-provider-ics](https://github.com/freitasjca/horse-provider-ics)** _(Delphi; Win + Linux/macOS)_ | `HORSE_PROVIDER_ICS` |    ✔️ |     ❌ | | 🆕 **[IOCP](./doc/iocp.pt-BR.md)** _(portas de conclusão de E/S assíncronas nativas do Windows)_ | `HORSE_PROVIDER_IOCP` |    ✔️ |     ✔️ | +| 🆕 **[horse-provider-nghttp2](https://github.com/freitasjca/horse-provider-nghttp2)** _(HTTP/2 + gRPC; requer [Delphi-nghttp2](https://github.com/freitasjca/Delphi-nghttp2))_ | `HORSE_PROVIDER_NGHTTP2` |    ✔️ |     ✔️ | > **Nota** — Os tipos de aplicação Apache / ISAPI / CGI / FastCGI (abaixo) **não** usam nenhum desses Providers. O processo host (Apache, IIS, o webserver) é dono do socket; o Horse roda in-process. Veja [Providers e Tipos de aplicação](./doc/providers.pt-BR.md) para o modelo completo. @@ -123,6 +123,8 @@ Um _provider_ é o transporte HTTP que é dono do socket e entrega requisições > **Instalação do OverbyteICS** — o Provider ICS requer o [OverbyteICS](https://wiki.overbyte.eu/wiki/index.php/ICS_Download) (v9.x). **Instale o ICS seguindo as instruções oficiais do ICS** — baixe/clone o ICS e adicione a pasta `Source/` ao _search path_ do seu projeto (o ICS não é instalável via Boss). Para TLS, as bibliotecas OpenSSL acompanham o ICS (DLLs no Windows, `.so` no Linux). O Provider ICS é **somente Delphi — Windows e POSIX (Linux64 / macOS)** via o pump de mensagens próprio do ICS (`Ics.Posix.*`) (no Linux use `HORSE_APPTYPE_DAEMON` + `THorseICSLinuxDaemonApp.Run`); um port para **Lazarus/FPC não é viável** — a camada POSIX do ICS usa a RTL POSIX do Delphi e o ICS desativa o OpenSSL no FPC. Seu diferencial é a pilha OpenSSL 3.x / 4.x do ICS (TLS 1.3, SNI, mTLS). Veja [horse-provider-ics](https://github.com/freitasjca/horse-provider-ics) para configuração, a suíte de testes A–K e limitações conhecidas. +> **Instalação do Delphi-nghttp2** — `boss install github.com/freitasjca/horse-provider-nghttp2` instala o provider e sua dependência [`Delphi-nghttp2`](https://github.com/freitasjca/Delphi-nghttp2) automaticamente. Em tempo de execução, **libnghttp2 ≥ 1.59** deve estar disponível (carregada dinamicamente — sem dependência em tempo de link): no Windows, baixe a DLL pré-compilada do [pacote curl for Windows](https://curl.se/windows/); no Linux, `sudo apt install libnghttp2-14`; no macOS, `brew install nghttp2`. Para TLS e gRPC, o OpenSSL 3.x ou 1.1 é detectado automaticamente em tempo de execução. **FPC trunk 3.3.1 obrigatório** (FPC 3.2.2 é um bloqueador definitivo). Veja [horse-provider-nghttp2](https://github.com/freitasjca/horse-provider-nghttp2) para o guia completo de configuração, TLS/mTLS e exemplos de gRPC. + > **HttpSys** — **sem instalação**: a unit `Horse.Provider.HttpSys` acompanha o Horse e usa diretamente a `httpapi.dll` do Windows (http.sys), portanto não há biblioteca externa. Defina `HORSE_PROVIDER_HTTPSYS` (Windows; Delphi ou Lazarus). Como o http.sys é uma pilha HTTP em modo kernel e de escopo da máquina, vincular um host diferente de `localhost` ou uma porta privilegiada exige uma reserva de URL única (`netsh http add urlacl url=http://+:9000/ user=Everyone`) ou direitos de Administrador; o HTTPS usa o repositório de certificados do Windows via `netsh http add sslcert`. É mutuamente exclusivo com os Providers CrossSocket / mORMot / ICS (um transporte por build). > **IOCP** — **sem instalação**: a unit `Horse.Provider.IOCP` acompanha o Horse e se vincula diretamente às portas de conclusão de E/S (Input/Output Completion Ports) do Windows utilizando a API Winsock2 para altíssimo desempenho e escalabilidade em tipos de aplicação self-hosted no Windows. Defina `HORSE_PROVIDER_IOCP` (Windows; Delphi ou Lazarus). É mutuamente exclusivo com Indy, HttpSys e outros providers de socket (um transporte por build). @@ -199,6 +201,7 @@ Esta é uma lista de middlewares criados pela comunidade Horse — abra um PR se | [isaquepinheiro/horse-jsonbr](https://github.com/HashLoad/JSONBr) |    ✔️ |     ❌ | | [IagooCesaar/Horse-JsonInterceptor](https://github.com/IagooCesaar/Horse-JsonInterceptor) |    ✔️ |     ❌ | | [dliocode/horse-datalogger](https://github.com/dliocode/horse-datalogger) |    ✔️ |     ❌ | +| [marcobreveglieri/horse-prometheus-metrics](https://github.com/marcobreveglieri/horse-prometheus-metrics) |    ✔️ |     ❌ | | [weslleycapelari/horse-documentation](https://github.com/weslleycapelari/horse-documentation) |    ✔️ |     ❌ | | [weslleycapelari/horse-validator](https://github.com/weslleycapelari/horse-validator) |    ✔️ |     ❌ | | [regyssilveira/horse-rate-limit](https://github.com/regyssilveira/horse-rate-limit) |    ✔️ |     ✔️ | diff --git a/src/Horse.pas b/src/Horse.pas index 1814648..af84d38 100644 --- a/src/Horse.pas +++ b/src/Horse.pas @@ -113,6 +113,7 @@ {$IFDEF HORSE_ISAPI} {$DEFINE HORSE_HOST_ISAPI} {$ENDIF} {$IFDEF HORSE_CGI} {$DEFINE HORSE_HOST_CGI} {$ENDIF} {$IFDEF HORSE_FCGI} {$DEFINE HORSE_HOST_FCGI} {$ENDIF} +{$IFDEF HORSE_NGHTTP2} {$DEFINE HORSE_PROVIDER_NGHTTP2} {$ENDIF} { =========================================================================== PATCH-HORSE-1 — Architecturally-impossible combination guard (expanded) @@ -183,6 +184,21 @@ {$IFEND} {$IFEND} +{$IF DEFINED(HORSE_PROVIDER_NGHTTP2)} + {$IF DEFINED(HORSE_HOST_ISAPI)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 cannot combine with HORSE_HOST_ISAPI — IIS owns the socket; a self-hosted Provider cannot coexist.'} + {$ENDIF} + {$IF DEFINED(HORSE_HOST_APACHE)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 cannot combine with HORSE_HOST_APACHE — Apache owns the socket; a self-hosted Provider cannot coexist.'} + {$ENDIF} + {$IF DEFINED(HORSE_HOST_CGI)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 cannot combine with HORSE_HOST_CGI — the web server owns the socket; a self-hosted Provider cannot coexist.'} + {$ENDIF} + {$IF DEFINED(HORSE_HOST_FCGI)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 cannot combine with HORSE_HOST_FCGI — FastCGI talks to a web server; a self-hosted Provider cannot coexist.'} + {$ENDIF} +{$IFEND} + { Rule 2 — cross-platform Application-type mismatch } {$IF DEFINED(HORSE_APPTYPE_VCL) and DEFINED(FPC)} {$MESSAGE FATAL 'HORSE_APPTYPE_VCL is Delphi-only — use HORSE_APPTYPE_LCL for Lazarus/FPC.'} @@ -196,7 +212,7 @@ { Rule 3 — HORSE_NOPROVIDER × anything else } {$IF DEFINED(HORSE_NOPROVIDER)} - {$IF DEFINED(HORSE_PROVIDER_CROSSSOCKET) or DEFINED(HORSE_PROVIDER_MORMOT) or DEFINED(HORSE_PROVIDER_ICS) or DEFINED(HORSE_APPTYPE_VCL) or DEFINED(HORSE_APPTYPE_DAEMON) or DEFINED(HORSE_APPTYPE_LCL) or DEFINED(HORSE_HOST_APACHE) or DEFINED(HORSE_HOST_ISAPI) or DEFINED(HORSE_HOST_CGI) or DEFINED(HORSE_HOST_FCGI)} + {$IF DEFINED(HORSE_PROVIDER_CROSSSOCKET) or DEFINED(HORSE_PROVIDER_MORMOT) or DEFINED(HORSE_PROVIDER_ICS) or DEFINED(HORSE_PROVIDER_NGHTTP2) or DEFINED(HORSE_APPTYPE_VCL) or DEFINED(HORSE_APPTYPE_DAEMON) or DEFINED(HORSE_APPTYPE_LCL) or DEFINED(HORSE_HOST_APACHE) or DEFINED(HORSE_HOST_ISAPI) or DEFINED(HORSE_HOST_CGI) or DEFINED(HORSE_HOST_FCGI)} {$MESSAGE FATAL 'HORSE_NOPROVIDER is mutually exclusive with all HORSE_PROVIDER_*, HORSE_APPTYPE_*, and HORSE_HOST_* defines — remove one.'} {$IFEND} {$IFEND} @@ -211,10 +227,19 @@ {$IF DEFINED(HORSE_PROVIDER_MORMOT) and DEFINED(HORSE_PROVIDER_ICS)} {$MESSAGE FATAL 'HORSE_PROVIDER_MORMOT and HORSE_PROVIDER_ICS are mutually exclusive — pick exactly one transport Provider per build.'} {$IFEND} -{$IF DEFINED(HORSE_PROVIDER_HTTPSYS) and (DEFINED(HORSE_PROVIDER_CROSSSOCKET) or DEFINED(HORSE_PROVIDER_MORMOT))} +{$IF DEFINED(HORSE_PROVIDER_NGHTTP2) and DEFINED(HORSE_PROVIDER_CROSSSOCKET)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 and HORSE_PROVIDER_CROSSSOCKET are mutually exclusive — pick exactly one transport Provider per build.'} +{$IFEND} +{$IF DEFINED(HORSE_PROVIDER_NGHTTP2) and DEFINED(HORSE_PROVIDER_MORMOT)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 and HORSE_PROVIDER_MORMOT are mutually exclusive — pick exactly one transport Provider per build.'} +{$IFEND} +{$IF DEFINED(HORSE_PROVIDER_NGHTTP2) and DEFINED(HORSE_PROVIDER_ICS)} + {$MESSAGE FATAL 'HORSE_PROVIDER_NGHTTP2 and HORSE_PROVIDER_ICS are mutually exclusive — pick exactly one transport Provider per build.'} +{$IFEND} +{$IF DEFINED(HORSE_PROVIDER_HTTPSYS) and (DEFINED(HORSE_PROVIDER_CROSSSOCKET) or DEFINED(HORSE_PROVIDER_MORMOT) or DEFINED(HORSE_PROVIDER_NGHTTP2))} {$MESSAGE FATAL 'HORSE_PROVIDER_HTTPSYS is mutually exclusive with other transport Providers — pick exactly one per build.'} {$IFEND} -{$IF DEFINED(HORSE_PROVIDER_EPOLL) and (DEFINED(HORSE_PROVIDER_CROSSSOCKET) or DEFINED(HORSE_PROVIDER_MORMOT) or DEFINED(HORSE_PROVIDER_HTTPSYS))} +{$IF DEFINED(HORSE_PROVIDER_EPOLL) and (DEFINED(HORSE_PROVIDER_CROSSSOCKET) or DEFINED(HORSE_PROVIDER_MORMOT) or DEFINED(HORSE_PROVIDER_HTTPSYS) or DEFINED(HORSE_PROVIDER_NGHTTP2))} {$MESSAGE FATAL 'HORSE_PROVIDER_EPOLL is mutually exclusive with other transport Providers — pick exactly one per build.'} {$IFEND} { =========================================================================== } @@ -266,6 +291,13 @@ interface {$ELSE} {$MESSAGE ERROR 'HORSE_PROVIDER_IOCP is only supported on Windows.'} {$ENDIF} + {$ELSEIF DEFINED(HORSE_PROVIDER_NGHTTP2)} + { FPC branch of the nghttp2 selector. Cross-product FPC units + (Nghttp2.FPC.Daemon, Nghttp2.FPC.LCL, Nghttp2.FPC.HTTPApplication) + aren't shipped in v2.0 — HORSE_APPTYPE_* on FPC currently falls through + to the plain console-shape provider. Add them in a follow-up when + FPC/Lazarus deployments materialise. } + Horse.Provider.Nghttp2, {$ELSEIF DEFINED(HORSE_APPTYPE_DAEMON)} Horse.Provider.FPC.Daemon, {$ELSEIF DEFINED(HORSE_APPTYPE_LCL)} @@ -334,6 +366,15 @@ interface {$ELSE} Horse.Provider.ICS, { Console-shape — Delphi default for ICS } {$ENDIF} +{$ELSEIF DEFINED(HORSE_PROVIDER_NGHTTP2)} + System.SysUtils, + {$IF DEFINED(HORSE_APPTYPE_VCL)} + Horse.Provider.Nghttp2.VCL, { Windows GUI host — auto-Listen from FormCreate } + {$ELSEIF DEFINED(HORSE_APPTYPE_DAEMON)} + Horse.Provider.Nghttp2.Daemon, { Windows Service (TService) or Linux daemon (SIGTERM handler) } + {$ELSE} + Horse.Provider.Nghttp2, { Console-shape — Delphi default for nghttp2 } + {$ENDIF} {$ELSE} System.SysUtils, Horse.Provider.Console, @@ -481,6 +522,8 @@ interface {$ELSE} THorseProvider = Horse.Provider.ICS.THorseProviderICS; {$ENDIF} +{$ELSEIF DEFINED(HORSE_PROVIDER_NGHTTP2)} + THorseProvider = Horse.Provider.Nghttp2.THorseProviderNghttp2; {$ELSEIF DEFINED(HORSE_APPTYPE_DAEMON)} THorseProvider = {$IF DEFINED(FPC)}