# Plack::Handler::H2 A high-performance HTTP/2 server handler for Plack, built with C++ and utilizing nghttp2, libevent, and OpenSSL. [![Test Install](https://github.com/rawleyfowler/perl-Plack-Handler-H2/actions/workflows/test.yaml/badge.svg)](https://github.com/rawleyfowler/perl-Plack-Handler-H2/actions/workflows/test.yaml) ## Description Plack::Handler::H2 is a high performance PSGI/Plack handler that implements HTTP/2 server functionality using native C++ code with Perl XS bindings. It leverages industry-standard libraries to provide efficient, asynchronous HTTP/2 request handling with TLS/SSL support. ## Features - **Full HTTP/2 Protocol Support**: Complete HTTP/2 implementation using nghttp2 - **High Performance**: Native C++ implementation with minimal overhead - **PSGI Compliant**: Full compatibility with PSGI specification ## Dependencies ### System Libraries - **nghttp2**: HTTP/2 C library (version 1.x) - **libevent2**: Event notification library (version 2.x) - **OpenSSL**: TLS/SSL cryptographic library (version 1.1.1 or 3.0+) - **C++ Compiler**: GCC 7+, Clang 5+, or equivalent with C++17 support ### Perl Modules - Perl 5.024 or higher, with XS support - Plack 1.0+ - File::Temp 0.22+ - XSLoader (core module) ## Installation ### Install System Dependencies **Ubuntu/Debian:** ```bash sudo apt-get install libnghttp2-dev libevent-dev libssl-dev g++ make ``` **CentOS/RHEL:** ```bash sudo yum install nghttp2-devel libevent-devel openssl-devel gcc-c++ make ``` **macOS:** ```bash brew install nghttp2 libevent openssl ``` ### Build and Install the Module From CPAN (when available): ```bash cpanm Plack::Handler::H2 ``` From source: ```bash perl Makefile.PL make make test make install ``` ## Usage ### Basic Example Create a PSGI application file (`app.psgi`): ```perl my $app = sub { my $env = shift; return [ 200, ['Content-Type' => 'text/plain'], ['Hello, HTTP/2 World!'] ]; }; ``` Run with plackup: ```bash # With custom certificates plackup -s H2 \ --ssl-cert-file=/path/to/server.crt \ --ssl-key-file=/path/to/server.key \ --port=8443 \ app.psgi # Development mode (auto-generates self-signed certificate) plackup -s H2 --port=8443 app.psgi ``` ### Streaming Response Example Create a streaming PSGI application (`streaming.psgi`): ```perl my $app = sub { my $env = shift; return sub { my $responder = shift; # Send headers and get writer my $writer = $responder->([ 200, ['Content-Type' => 'text/html'] ]); # Stream data in chunks $writer->write(""); $writer->write("

Streaming Response

"); sleep 1; # Simulate processing $writer->write("

This data arrives progressively.

"); $writer->write(""); # Close the stream $writer->close(); }; }; ``` Run with plackup: ```bash plackup -s H2 --port=8443 streaming.psgi ``` ### Configuration Options When using plackup, you can pass options via command-line flags: - **--ssl-cert-file** (optional): Path to SSL certificate file (PEM format) - If not provided, generates self-signed certificate automatically - **--ssl-key-file** (optional): Path to SSL private key file (PEM format) - Required if --ssl-cert-file is provided - **--host** (optional): IP address to bind to (default: `0.0.0.0`) - **--port** (optional): Port number to listen on (default: `5000`) - **--timeout** (optional): General timeout in seconds (default: `120`) - **--read-timeout** (optional): Read timeout in seconds (default: `60`) - **--write-timeout** (optional): Write timeout in seconds (default: `60`) - **--request-timeout** (optional): Request timeout in seconds (default: `30`) - **--max-request-body-size** (optional): Maximum request body size in bytes (default: `10485760` = 10MB) Example with custom configuration: ```bash plackup -s H2 \ --host=127.0.0.1 \ --port=8443 \ --ssl-cert-file=server.crt \ --ssl-key-file=server.key \ --max-request-body-size=20971520 \ app.psgi ``` **Note**: For programmatic use cases where plackup is not suitable, you can instantiate the handler directly with `Plack::Handler::H2->new()`, but this is only recommended for advanced use cases. ## Architecture The module consists of three main layers: 1. **H2.pm**: High-level Perl interface - PSGI handler implementation - Configuration management - Self-signed certificate generation - Streaming response coordination 2. **H2.xs**: XS bindings layer - Efficient Perl-to-C++ interface - Type conversion and marshalling - Function wrappers for core operations 3. **plack_handler_h2.cc/h**: Core C++ implementation - nghttp2 integration for HTTP/2 protocol - libevent event loop for async I/O - OpenSSL for TLS/SSL and ALPN - Request/response handling - Stream multiplexing - Memory-efficient body handling (auto-switches to temp files for large bodies) ## Examples The `example/` directory contains several working examples: - **example.pl**: Basic PSGI app with form handling - **example_streamed.pl**: Streaming response demonstration - **example_streamed_2.pl**: Delayed response pattern - **example_dancer2.pl**: Dancer2 framework integration - **example_mojo.pl**: Mojolicious::Lite integration ## SSL/TLS Configuration ### Production Use For production, obtain valid certificates from a trusted Certificate Authority: ```bash # Using Let's Encrypt (example) certbot certonly --standalone -d yourdomain.com ``` Then run with plackup: ```bash plackup -s H2 \ --ssl-cert-file=/etc/letsencrypt/live/yourdomain.com/fullchain.pem \ --ssl-key-file=/etc/letsencrypt/live/yourdomain.com/privkey.pem \ --port=443 \ --host=0.0.0.0 \ app.psgi ``` ### Development, or Internal Use For development and testing, simply run plackup without certificate options to auto-generate self-signed certificates: ```bash # Auto-generates self-signed certificate plackup -s H2 --port=8443 app.psgi ``` Or generate your own self-signed certificate: ```bash openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt \ -days 365 -nodes -subj "/CN=localhost" plackup -s H2 \ --ssl-cert-file=server.crt \ --ssl-key-file=server.key \ --port=8443 \ app.psgi ``` **Note**: Browsers will display security warnings for self-signed certificates. You'll need to accept the security exception to proceed. ## Performance The handler is designed for high performance: - Native C++ implementation minimizes overhead - Stream multiplexing allows concurrent request processing - Automatic buffering strategy for request bodies (memory for small, temp files for large) - HTTP/2 header compression reduces bandwidth See `benchmark/` directory for benchmarking tools to compare with other Plack handlers. ## Testing Run the test suite: ```bash make test ``` Tests cover: - Module loading - Writer API - Handler configuration - Streaming responses - Delayed responses - Integration tests (requires curl with HTTP/2 support) ## Platform Support Supported operating systems: - Linux (Ubuntu, Debian, CentOS, RHEL, etc.) - macOS - FreeBSD - OpenBSD **Windows**: Not currently supported due to libevent requirements. ## Requirements Summary - Perl 5.024 or higher - C++17 compatible compiler (GCC 7+, Clang 5+, or equivalent) - nghttp2 1.x - libevent 2.x - OpenSSL 1.1.1 or 3.0+ ## Version Current version: **0.0.1** ## Troubleshooting ### "Could not create SSL_CTX" - Verify OpenSSL is properly installed - Check that certificate and key files are readable - Ensure certificate and key match ### "Could not read certificate file" / "Could not read private key file" - Verify file paths are correct and absolute - Check file permissions (should be readable by the process) - Ensure files are in PEM format - Check for proper line endings (UNIX style) ### Connection refused / Connection errors - Verify the server is listening on the correct address and port - For localhost testing, try `https://localhost:PORT` (not `http://`) ### Browser shows "NET::ERR_CERT_AUTHORITY_INVALID" - This is normal for self-signed certificates - Click "Advanced" and "Proceed to localhost (unsafe)" to continue - For production, use certificates from a trusted CA ### Large request bodies failing - Adjust `max_request_body_size` parameter (default 10MB) - The handler automatically uses temp files for bodies > 1MB ### Roadmap - ACME certificate handling built in ## License This software is released under the BSD 3-Clause License. See the LICENSE file for details. ## Authors Rawley Fowler ## See Also - [Plack](https://metacpan.org/pod/Plack) - PSGI toolkit and server adapters - [PSGI Specification](https://metacpan.org/pod/PSGI) - Perl Web Server Gateway Interface - [nghttp2](https://nghttp2.org/) - HTTP/2 C library - [libevent](https://libevent.org/) - Event notification library - [HTTP/2 Specification (RFC 7540)](https://tools.ietf.org/html/rfc7540) - The HTTP/2 protocol - [HTTP/2 (RFC 9113)](https://www.rfc-editor.org/rfc/rfc9113.html) - Updated HTTP/2 specification