use Test::More tests => 17; use Test::Deep; use Net::SPDY::Compressor; use strict; use warnings; # Read chunk of size same as prototype from an IO::Handle and # compare it against the prototype. sub readcmp { my $handle = shift; my $proto = shift; my $msg = shift; my $buf; my $toread = length $proto; while ($toread) { my $read = $handle->read ($buf, $toread, (length $proto) - $toread); die $! unless defined $read; die 'Short read' unless $read; $toread -= $read; } is (join (' ', map { sprintf '%02x', $_ } unpack 'C*', $buf), join (' ', map { sprintf '%02x', $_ } unpack 'C*', $proto), $msg); } BEGIN { use_ok ('Net::SPDY::Framer') }; require_ok ('Net::SPDY::Framer'); pipe (R, W); my $framer = new Net::SPDY::Framer ({ compressor => new Net::SPDY::Compressor, socket => *W, }); ok ($framer, 'Created a framer instance'); my $sess1 = fork; die $! unless defined $sess1; unless ($sess1) { close R; $framer->write_frame ( type => Net::SPDY::Framer::SETTINGS, id_values => [{ flags => 1, value => 1000, id => 4 }] ); $framer->write_frame ( type => Net::SPDY::Framer::SYN_STREAM, stream_id => 1, associated_stream_id => 0, priority => 2, flags => 0, slot => 0, headers => [ ':method' => 'GET', ':scheme' => 'https', ':path' => '/', ':version' => 'HTTP/1.1', ':host' => 'example.com:443', ], ); $framer->write_frame ( type => Net::SPDY::Framer::HEADERS, flags => 0, stream_id => 1, headers => [ 'User-Agent' => 'spdy-client Net-Spdy/0.1', ], ); $framer->write_frame ( type => Net::SPDY::Framer::SYN_STREAM, stream_id => 3, associated_stream_id => 1, priority => 0, flags => Net::SPDY::Framer::FLAG_FIN, slot => 0, headers => [ ':method' => 'GET', ':scheme' => 'https', ':path' => '/', ':version' => 'HTTP/1.1', ':host' => 'example.com:443', 'User-Agent' => 'spdy-client Net-Spdy/0.1', ], ); $framer->write_frame ( control => 0, data => '', stream_id => 1, flags => Net::SPDY::Framer::FLAG_FIN, ); $framer->write_frame ( type => Net::SPDY::Framer::PING, id => 0x706c6c6d, ); $framer->write_frame ( type => Net::SPDY::Framer::GOAWAY, last_good_stream_id => 3, status => 0, ); exit 0; } close W; readcmp (*R, "\x80\x03\x00\x04". "\x00\x00\x00\x0c". "\x00\x00\x00\x01". "\x01\x00\x00\x04". "\x00\x00\x03\xe8", 'SETTINGS frame read correctly'); readcmp (*R, "\x80\x03\x00\x01". "\x00\x00\x00\x86". "\x00\x00\x00\x01". "\x00\x00\x00\x00". "\x40\x00". "\x78\x3f\xe3\xc6\xa7\xc2\x00\x6c\x00\x93\xff". "\x00\x00\x00\x05". "\x00\x00\x00\x07:method\x00\x00\x00\x03GET". "\x00\x00\x00\x07:scheme\x00\x00\x00\x05https". "\x00\x00\x00\x05:path\x00\x00\x00\x01/". "\x00\x00\x00\x08:version\x00\x00\x00\x08HTTP/1.1". "\x00\x00\x00\x05:host\x00\x00\x00\x0fexample.com:443". "\x00\x00\x00\xff\xff", 'SYN_STREAM frame read correctly'); readcmp (*R, "\x80\x03\x00\x08". "\x00\x00\x00\x3c". "\x00\x00\x00\x01". "\x00\x2e\x00\xd1\xff". "\x00\x00\x00\x01". "\x00\x00\x00\x0auser-agent\x00\x00\x00\x18spdy-client Net-Spdy/0.1". "\x00\x00\x00\xff\xff", 'HEADERS frame read correctly'); readcmp (*R, "\x80\x03\x00\x01". "\x01\x00\x00\xaa". "\x00\x00\x00\x03". "\x00\x00\x00\x01". "\x00\x00\x00\x96". "\x00\x69". "\xff". "\x00\x00\x00\x06". "\x00\x00\x00\x07:method\x00\x00\x00\x03GET". "\x00\x00\x00\x07:scheme\x00\x00\x00\x05https". "\x00\x00\x00\x05:path\x00\x00\x00\x01/". "\x00\x00\x00\x08:version\x00\x00\x00\x08HTTP/1.1". "\x00\x00\x00\x05:host\x00\x00\x00\x0fexample.com:443". "\x00\x00\x00\x0auser-agent\x00\x00\x00\x18spdy-client Net-Spdy/0.1". "\x00\x00\x00\xff\xff", 'SYN_STREAM frame read correctly'); readcmp (*R, "\x00\x00\x00\x01". "\x01\x00\x00\x00", 'Data frame read correctly'); readcmp (*R, "\x80\x03\x00\x06". "\x00\x00\x00\x04". "pllm", 'PING frame read correctly'); readcmp (*R, "\x80\x03\x00\x07". "\x00\x00\x00\x08". "\x00\x00\x00\x03". "\x00\x00\x00\x00", 'GOAWAY frame read correctly'); close R; kill $sess1; waitpid $sess1, 0; undef $framer; pipe (R, W); my $sess2 = fork; die $! unless defined $sess2; unless ($sess2) { close R; W->print ("\x80\x03\x00\x04". "\x00\x00\x00\x0c". "\x00\x00\x00\x01". "\x01\x00\x00\x04". "\x00\x00\x03\xe8"); W->print ("\x80\x03\x00\x01". "\x00\x00\x00\x86". "\x00\x00\x00\x01". "\x00\x00\x00\x00". "\x40\x00". "\x78\x3f\xe3\xc6\xa7\xc2\x00\x6c\x00\x93\xff". "\x00\x00\x00\x05". "\x00\x00\x00\x07:method\x00\x00\x00\x03GET". "\x00\x00\x00\x07:scheme\x00\x00\x00\x05https". "\x00\x00\x00\x05:path\x00\x00\x00\x01/". "\x00\x00\x00\x08:version\x00\x00\x00\x08HTTP/1.1". "\x00\x00\x00\x05:host\x00\x00\x00\x0fexample.com:443". "\x00\x00\x00\xff\xff"); W->print ("\x80\x03\x00\x08". "\x00\x00\x00\x3c". "\x00\x00\x00\x01". "\x00\x2e\x00\xd1\xff". "\x00\x00\x00\x01". "\x00\x00\x00\x0auser-agent\x00\x00\x00\x18spdy-client Net-Spdy/0.1". "\x00\x00\x00\xff\xff"); W->print ("\x80\x03\x00\x01". "\x01\x00\x00\xaa". "\x00\x00\x00\x03". "\x00\x00\x00\x01". "\x00\x00\x00\x96". "\x00\x69". "\xff". "\x00\x00\x00\x06". "\x00\x00\x00\x07:method\x00\x00\x00\x03GET". "\x00\x00\x00\x07:scheme\x00\x00\x00\x05https". "\x00\x00\x00\x05:path\x00\x00\x00\x01/". "\x00\x00\x00\x08:version\x00\x00\x00\x08HTTP/1.1". "\x00\x00\x00\x05:host\x00\x00\x00\x0fexample.com:443". "\x00\x00\x00\x0auser-agent\x00\x00\x00\x18spdy-client Net-Spdy/0.1". "\x00\x00\x00\xff\xff"); W->print ("\x00\x00\x00\x01". "\x01\x00\x00\x00"); W->print ("\x80\x03\x00\x06". "\x00\x00\x00\x04". "pllm"); W->print ("\x80\x03\x00\x07". "\x00\x00\x00\x08". "\x00\x00\x00\x03". "\x00\x00\x00\x00"); exit 0; } close W; $framer = new Net::SPDY::Framer ({ compressor => new Net::SPDY::Compressor, socket => *R, }); cmp_deeply ({$framer->read_frame}, { control => 1, version => 3, flags => 0, length => 12, entries => 1, type => Net::SPDY::Framer::SETTINGS, id_values => [{ flags => 1, value => 1000, id => 4 }], }, 'SETTINGS frame written correctly'); cmp_deeply ({$framer->read_frame}, { control => 1, version => 3, flags => 0, length => 134, type => Net::SPDY::Framer::SYN_STREAM, stream_id => 1, associated_stream_id => 0, priority => 2, flags => 0, slot => 0, headers => [ ':method' => 'GET', ':scheme' => 'https', ':path' => '/', ':version' => 'HTTP/1.1', ':host' => 'example.com:443', ], }, 'SYN_STREAM frame written correctly'); cmp_deeply ({$framer->read_frame}, { control => 1, version => 3, flags => 0, length => 60, type => Net::SPDY::Framer::HEADERS, flags => 0, stream_id => 1, headers => [ 'user-agent' => 'spdy-client Net-Spdy/0.1', ], }, 'SETTINGS frame written correctly'); cmp_deeply ({$framer->read_frame}, { control => 1, version => 3, flags => 0, length => 170, type => Net::SPDY::Framer::SYN_STREAM, stream_id => 3, associated_stream_id => 1, priority => 0, flags => Net::SPDY::Framer::FLAG_FIN, slot => 0, headers => [ ':method' => 'GET', ':scheme' => 'https', ':path' => '/', ':version' => 'HTTP/1.1', ':host' => 'example.com:443', 'user-agent' => 'spdy-client Net-Spdy/0.1', ], }, 'SYN_STREAM frame written correctly'); cmp_deeply ({$framer->read_frame}, { control => 0, flags => 0, length => 0, data => '', stream_id => 1, flags => Net::SPDY::Framer::FLAG_FIN, }, 'Data frame written correctly'); cmp_deeply ({$framer->read_frame}, { control => 1, version => 3, flags => 0, length => 4, type => Net::SPDY::Framer::PING, id => 0x706c6c6d, }, 'PING frame written correctly'); cmp_deeply ({$framer->read_frame}, { control => 1, version => 3, flags => 0, length => 8, type => Net::SPDY::Framer::GOAWAY, last_good_stream_id => 3, status => 0, }, 'GOAWAY frame written correctly'); kill $sess2; waitpid $sess2, 0;