Plack::Handler::H2
A high-performance HTTP/2 server handler for Plack, built with C++ and utilizing nghttp2, libevent, and OpenSSL.
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:
sudo apt-get install libnghttp2-dev libevent-dev libssl-dev g++ make
CentOS/RHEL:
sudo yum install nghttp2-devel libevent-devel openssl-devel gcc-c++ make
macOS:
brew install nghttp2 libevent openssl
Build and Install the Module
From CPAN (when available):
cpanm Plack::Handler::H2
From source:
perl Makefile.PL
make
make test
make install
Usage
Basic Example
Create a PSGI application file (app.psgi):
my $app = sub {
my $env = shift;
return [
200,
['Content-Type' => 'text/plain'],
['Hello, HTTP/2 World!']
];
};
Run with plackup:
# 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):
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("<html><body>");
$writer->write("<h1>Streaming Response</h1>");
sleep 1; # Simulate processing
$writer->write("<p>This data arrives progressively.</p>");
$writer->write("</body></html>");
# Close the stream
$writer->close();
};
};
Run with plackup:
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:
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:
-
H2.pm: High-level Perl interface
- PSGI handler implementation
- Configuration management
- Self-signed certificate generation
- Streaming response coordination
-
H2.xs: XS bindings layer
- Efficient Perl-to-C++ interface
- Type conversion and marshalling
- Function wrappers for core operations
-
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:
# Using Let's Encrypt (example)
certbot certonly --standalone -d yourdomain.com
Then run with plackup:
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:
# Auto-generates self-signed certificate
plackup -s H2 --port=8443 app.psgi
Or generate your own self-signed certificate:
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
Testing
Run the test suite:
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(nothttp://)
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_sizeparameter (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 rawley@molluscsoftware.com
See Also
- Plack - PSGI toolkit and server adapters
- PSGI Specification - Perl Web Server Gateway Interface
- nghttp2 - HTTP/2 C library
- libevent - Event notification library
- HTTP/2 Specification (RFC 7540) - The HTTP/2 protocol
- HTTP/2 (RFC 9113) - Updated HTTP/2 specification