Protoc...:Server(3pm)
π NAME π
okay bestie, gather round, because this is Protocol::HTTP2::Server β it's the HTTP/2 server situation, from the User Contributed Perl Documentation, section 3pm. Yes, that's the whole name. Slay.
β¨ SYNOPSIS β¨
so first things first, you gotta bring the whole friend group β here's the vibe:
use Protocol::HTTP2::Server;
# You must create tcp server yourself
use AnyEvent;
use AnyEvent::Socket;
use AnyEvent::Handle;
my $w = AnyEvent->condvar;
# Plain-text HTTP/2 connection
tcp_server 'localhost', 8000, sub {
my ( $fh, $peer_host, $peer_port ) = @_;
my $handle;
$handle = AnyEvent::Handle->new(
fh => $fh,
autocork => 1,
on_error => sub {
$_[0]->destroy;
print "connection error\n";
},
on_eof => sub {
$handle->destroy;
}
);
# Create Protocol::HTTP2::Server object
my $server;
$server = Protocol::HTTP2::Server->new(
on_request => sub {
my ( $stream_id, $headers, $data ) = @_;
my $message = "hello, world!";
# Response to client
$server->response(
':status' => 200,
stream_id => $stream_id,
# HTTP/1.1 Headers
headers => [
'server' => 'perl-Protocol-HTTP2/0.13',
'content-length' => length($message),
'cache-control' => 'max-age=3600',
'date' => 'Fri, 18 Apr 2014 07:27:11 GMT',
'last-modified' => 'Thu, 27 Feb 2014 10:30:37 GMT',
],
# Content
data => $message,
);
},
);
# First send settings to peer
while ( my $frame = $server->next_frame ) {
$handle->push_write($frame);
}
# Receive clients frames
# Reply to client
$handle->on_read(
sub {
my $handle = shift;
$server->feed( $handle->{rbuf} );
$handle->{rbuf} = undef;
while ( my $frame = $server->next_frame ) {
$handle->push_write($frame);
}
$handle->push_shutdown if $server->shutdown;
}
);
};
$w->recv;
πΈ heads up bestie: you have to create the tcp server yourself. the module is not gonna do it for you, it's not your mom.
π DESCRIPTION π
Protocol::HTTP2::Server is an HTTP/2 server library. Its whole thing β its main character energy, if you will β is letting you build http2-server implementations on top of whatever event loop you're obsessed with. Bring your own loop, she brings the protocol. Periodt.
also, side quest: go look at Shuvgey β https://github.com/vlet/Shuvgey β it's an AnyEvent HTTP/2 Server for PSGI built on top of Protocol::HTTP2::Server. iconic behavior fr fr π¦
π METHODS π
β new
Initialize a brand new server object. Baby's first server.
my $server = Protocol::HTTP2::Client->new( %options );
π okay so it literally says Protocol::HTTP2::Client right there in the docs. Not a typo on my part, bestie β that's what's written. Copy it as-is and don't @ me.
Available options, aka the little menu of customization:
on_request => sub {...}β this is the callback that fires whenever a client's request comes in. Stream ID, headers array ref, and the body of the request all get handed to you. Look at her go:
on_request => sub {
# Stream ID, headers array reference and body of request
my ( $stream_id, $headers, $data ) = @_;
my $message = "hello, world!";
$server->response(
':status' => 200,
stream_id => $stream_id,
headers => [
'server' => 'perl-Protocol-HTTP2/0.13',
'content-length' => length($message),
],
data => $message,
);
...
},
upgrade => 0|1β uses HTTP/1.1 Upgrade to level up the protocol from HTTP/1.1 to HTTP/2. Upgrade is only possible on a plain (non-tls) connection, so don't try it with the fancy stuff on.
See Starting HTTP/2 for "http" URIs β https://tools.ietf.org/html/rfc7540#section-3.2
on_error => sub {...}β callback that gets invoked whenever protocol errors happen. Your "oop" handler.
on_error => sub {
my $error = shift;
...
},
on_change_state => sub {...}β callback invoked every single time an http/2 stream changes its state. Like a read receipt for stream states.
See Stream States β https://tools.ietf.org/html/rfc7540#section-5.1
on_change_state => sub {
my ( $stream_id, $previous_state, $current_state ) = @_;
...
},
π response
Prepare a response. Getting your reply ready to send out into the world.
my $message = "hello, world!";
$server->response(
# HTTP/2 status
':status' => 200,
# Stream ID
stream_id => $stream_id,
# HTTP/1.1 headers
headers => [
'server' => 'perl-Protocol-HTTP2/0.01',
'content-length' => length($message),
],
# Body of response
data => $message,
);
π¦ response_stream
Use this one when the body of the response isn't ready yet, or when the server is gonna stream that data out piece by piece. Slow reveal, very dramatic. π
# P::H::Server::Stream object
my $server_stream;
$server_stream = $server->response_stream(
# HTTP/2 status
':status' => 200,
# Stream ID
stream_id => $stream_id,
# HTTP/1.1 headers
headers => [
'server' => 'perl-Protocol-HTTP2/0.01',
],
# Callback if client abort this stream
on_cancel => sub {
...
}
);
# Send partial data
$server_stream->send($chunk_of_data);
$server_stream->send($chunk_of_data);
## 3 ways to finish stream:
#
# The best: send last chunk and close stream in one action
$server_stream->last($chunk_of_data);
# Close the stream (will send empty frame)
$server_stream->close();
# Destroy object (will send empty frame)
undef $server_stream
π push
Prepare a Push Promise. See Server Push β https://tools.ietf.org/html/rfc7540#section-8.2
# Example of push inside of on_request callback
on_request => sub {
my ( $stream_id, $headers, $data ) = @_;
my %h = (@$headers);
# Push promise (must be before response)
if ( $h{':path'} eq '/index.html' ) {
# index.html contain styles.css resource, so server can push
# "/style.css" to client before it request it to increase speed
# of loading of whole page
$server->push(
':authority' => 'localhost:8000',
':method' => 'GET',
':path' => '/style.css',
':scheme' => 'http',
stream_id => $stream_id,
);
}
$server->response(...);
...
}
π«Ά not me telling you the push promise must be before response. That's not a suggestion, that's the rules.
πΈ shutdown
Get the connection status, bestie:
0β active1β closed (you can terminate connection)
π next_frame
get the next frame to send over the connection to the client. Returns:
undefβ on error0β nothing to send- binary string β encoded frame
# Example
while ( my $frame = $server->next_frame ) {
syswrite $fh, $frame;
}
π§ feed
Feed the decoder with chunks of the client's request. Snack time for the decoder. π½οΈ
sysread $fh, $binary_data, 4096;
$server->feed($binary_data);
π ping
Send a ping frame to the client, aka the "hey bestie u still there??" of keep-alive:
$server->ping
or
$server->ping($payload);
The payload can be an arbitrary binary string, and it must contain 8 octets. If you leave the payload argument out, the server will just send random data. Surprise! π
and that's the whole page, bestie β go build something iconic with it. πβ¨
this whole lil' document came from perl v5.42.3, dated 2026-09-04, and it lives in the Protoc...:Server(3pm) neighborhood of your man pages. mwah. π
π¦ where this page comes from
- fedora 43: perl-Protocol-HTTP2 1.14-1.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- fedora 44: perl-Protocol-HTTP2 1.14-1.fc44 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms