Protocol::HTTP2
/ http2-perl
という実装があるようです。ただ http2-perl
は h2-04 準拠なので Older Implementations に入れられており、実質 Protocol::HTTP2
一択です。以前発表した時は Protocol::HTTP2
は draft-17 だったのですが、現在は h2 になっているのできちんと開発は続いているようですね。
How to Use Protocol::HTTP2
Protocol::HTTP2
を実際に使ってみましょう。今回はクライアントを Protocol::HTTP2
を使って Perl で書き、nghttp2 のサーバーに繋いでみます。コードは GitHub にあげてあります。
on_change_state
や on_error
にコールバックを登録しておきます。
my $client = Protocol::HTTP2::Client->new(
on_change_state => sub {
my ( $stream*id, $previous_state, $current_state ) = @*;
printf "Stream %i changed state from %s to %s\n",
$stream_id, const_name( "states", $previous_state ),
const_name( "states", $current_state );
},
on_error => sub {
my $error = shift;
printf "Error occured: %s\n", const_name( "errors", \$error );
},
);
on_done
として渡してあげます。まだ実際のリクエストは行われません。
$client->request(
':scheme' => "http",
':authority' => $host . ":" . $port,
':path' => "/assets/hello.txt",
':method' => "GET",
headers => [
'accept' => '*/*',
'user-agent' => 'perl-Protocol-HTTP2/0.01',
],
on_done => sub {
my ( $headers, $data ) = @_;
printf "Get headers. Count: %i\n", scalar(@$headers) / 2;
printf "Get data. Length: %i\n", length($data);
print $data;
},
);
AnyEvent::Socket
の tcp_connect
を使って TCP コネクションをはり、$client->feed()
でクライアントに流れてくるデータを渡していきます。クライアントはリクエストが完了すると、リクエストを登録したときの on_done
を実行します。
my \$w = AnyEvent->condvar;
tcp*connect $host, $port, sub {
my (\$fh) = @* or die "connection failed: $!";
my $handle;
$handle = AnyEvent::Handle->new(
fh => $fh,
autocork => 1,
on*error => sub {
\$*[0]->destroy;
print "connection error\n";
$w->send;
},
on_eof => sub {
$handle->destroy;
\$w->send;
}
);
# First write preface to peer
while ( my $frame = $client->next_frame ) {
$handle->push_write($frame);
}
$handle->on_read(
sub {
my $handle = shift;
$client->feed( $handle->{rbuf} );
$handle->{rbuf} = undef;
while ( my $frame = $client->next_frame ) {
$handle->push_write($frame);
}
$handle->push_shutdown if $client->shutdown;
}
);
};
\$w->recv;
\$ carton exec -- perl client-simple.pl
Stream 1 changed state from IDLE to HALF_CLOSED
Stream 1 changed state from HALF_CLOSED to CLOSED
Get headers. Count: 6
Get data. Length: 14
Hello HTTP/2!
リクエストの多重化
Protocol::HTTP2
でももちろんリクエストの多重化ができます。
request()
をつなげていきます。この例ではサイズの大きい /assets/largefile
と、サイズの小さい /assets/hello.txt
の GET を行います。
$client->request(
':scheme' => "http",
':authority' => $host . ":" . $port,
':path' => "/assets/largefile",
':method' => "GET",
headers => [
'accept' => '*/*',
'user-agent' => 'perl-Protocol-HTTP2/0.01',
],
on_done => sub {
my ( $headers, $data ) = @_;
printf "Get headers. Count: %i\n", scalar(@$headers) / 2;
printf "Get data. Length: %i\n", length($data);
print "Finish getting largefile.\n"
},
)->request(
':scheme' => "http",
':authority' => $host . ":" . $port,
':path' => "/assets/hello.txt",
':method' => "GET",
headers => [
'accept' => '*/*',
'user-agent' => 'perl-Protocol-HTTP2/0.01',
],
on_done => sub {
my ( $headers, $data ) = @_;
printf "Get headers. Count: %i\n", scalar(@$headers) / 2;
printf "Get data. Length: %i\n", length($data);
print "$data\n";
},
);
\$ carton exec -- perl client-multi-streams.pl
Stream 1 changed state from IDLE to HALF_CLOSED
Stream 3 changed state from IDLE to HALF_CLOSED
Stream 3 changed state from HALF_CLOSED to CLOSED
Get headers. Count: 6
Get data. Length: 14
Hello HTTP/2!
Stream 1 changed state from HALF_CLOSED to CLOSED
Get headers. Count: 6
Get data. Length: 100000000
Finish getting largefile.