1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
package Protocol::HTTP2::Frame::Data;
use strict;
use warnings;
use Protocol::HTTP2::Constants qw(:flags :errors :settings :limits);
use Protocol::HTTP2::Trace qw(tracer);
sub decode {
my ( $con, $buf_ref, $buf_offset, $length ) = @_;
my ( $pad, $offset ) = ( 0, 0 );
my $frame_ref = $con->decode_context->{frame};
# Protocol errors
if (
# DATA frames MUST be associated with a stream
$frame_ref->{stream} == 0
)
{
$con->error(PROTOCOL_ERROR);
return undef;
}
if ( $frame_ref->{flags} & PADDED ) {
$pad = unpack( 'C', substr( $$buf_ref, $buf_offset ) );
$offset += 1;
}
my $dblock_size = $length - $offset - $pad;
if ( $dblock_size < 0 ) {
tracer->error("Not enough space for data block\n");
$con->error(PROTOCOL_ERROR);
return undef;
}
my $fcw = $con->fcw_recv( -$length );
my $stream_fcw = $con->stream_fcw_recv( $frame_ref->{stream}, -$length );
if ( $fcw < 0 || $stream_fcw < 0 ) {
tracer->warning(
"received data overflow flow control window: $fcw|$stream_fcw\n");
$con->stream_error( $frame_ref->{stream}, FLOW_CONTROL_ERROR );
return $length;
}
$con->fcw_update() if $fcw < $con->dec_setting(SETTINGS_MAX_FRAME_SIZE);
$con->stream_fcw_update( $frame_ref->{stream} )
if $stream_fcw < $con->dec_setting(SETTINGS_MAX_FRAME_SIZE)
&& !( $frame_ref->{flags} & END_STREAM );
return $length unless $dblock_size;
my $data = substr $$buf_ref, $buf_offset + $offset, $dblock_size;
# Update stream data container
$con->stream_data( $frame_ref->{stream}, $data );
# Check length of data matched content-length in header
if ( $frame_ref->{flags} & END_STREAM ) {
my $slen = $con->stream_length( $frame_ref->{stream} );
if ( defined $slen && defined $con->stream_data( $frame_ref->{stream} )
&& $slen != length $con->stream_data( $frame_ref->{stream} ) )
{
tracer->warning(
"content-length header don't match data frames size\n");
$con->stream_error( $frame_ref->{stream}, PROTOCOL_ERROR );
}
}
return $length;
}
sub encode {
my ( $con, $flags_ref, $stream_id, $data_ref ) = @_;
return $$data_ref;
}
1;
|