File Coverage

blib/lib/Protocol/HTTP2/Frame/Settings.pm
Criterion Covered Total %
statement 35 48 72.9
branch 10 16 62.5
condition 1 3 33.3
subroutine 6 6 100.0
pod 0 2 0.0
total 52 75 69.3


line stmt bran cond sub pod time code
1             package Protocol::HTTP2::Frame::Settings;
2 10     10   41 use strict;
  10         14  
  10         327  
3 10     10   50 use warnings;
  10         196  
  10         415  
4 10     10   45 use Protocol::HTTP2::Constants qw(const_name :flags :errors :limits :settings);
  10         10  
  10         2725  
5 10     10   51 use Protocol::HTTP2::Trace qw(tracer);
  10         15  
  10         6520  
6              
7             my %s_check = (
8             &SETTINGS_MAX_FRAME_SIZE => {
9             validator => sub {
10             $_[0] <= MAX_PAYLOAD_SIZE && $_[0] >= DEFAULT_MAX_FRAME_SIZE;
11             },
12             error => PROTOCOL_ERROR
13             },
14             &SETTINGS_ENABLE_PUSH => {
15             validator => sub {
16             $_[0] == 0 || $_[0] == 1;
17             },
18             error => PROTOCOL_ERROR
19             },
20             &SETTINGS_INITIAL_WINDOW_SIZE => {
21             validator => sub {
22             $_[0] <= MAX_FCW_SIZE;
23             },
24             error => FLOW_CONTROL_ERROR
25             },
26             );
27              
28             my %s_action = (
29             &SETTINGS_INITIAL_WINDOW_SIZE => sub {
30             my ( $con, $size ) = @_;
31             $con->fcw_initial_change($size);
32             }
33             );
34              
35             sub decode {
36 49     49 0 8303 my ( $con, $buf_ref, $buf_offset, $length ) = @_;
37 49         8280 my $frame_ref = $con->decode_context->{frame};
38              
39 49 50       8074 if ( $frame_ref->{stream} != 0 ) {
40 0         0 $con->error(PROTOCOL_ERROR);
41 0         0 return undef;
42             }
43              
44             # just ack for our previous settings
45 49 100       7737 if ( $frame_ref->{flags} & ACK ) {
    100          
46 24 50       3934 if ( $length != 0 ) {
47 0         0 tracer->error(
48             "ACK settings frame have non-zero ($length) payload\n");
49 0         0 $con->error(FRAME_SIZE_ERROR);
50 0         0 return undef;
51             }
52 24         7640 return 0
53              
54             # received empty settings (default), accept it
55             }
56             elsif ( $length == 0 ) {
57 12         1997 $con->accept_settings();
58 12         3906 return 0;
59             }
60              
61 13 50       1995 if ( $length % 6 != 0 ) {
62 0         0 tracer->error("Settings frame payload is broken (lenght $length)\n");
63 0         0 $con->error(FRAME_SIZE_ERROR);
64 0         0 return undef;
65             }
66              
67 13         2040 my @settings = unpack( '(nN)*', substr( $$buf_ref, $buf_offset, $length ) );
68 13         2062 while ( my ( $key, $value ) = splice @settings, 0, 2 ) {
69 13 50 33     2035 if ( !defined $con->enc_setting($key) ) {
    50          
70 0         0 tracer->debug("\tUnknown setting $key\n");
71              
72             # ignore unknown setting
73 0         0 next;
74             }
75             elsif ( exists $s_check{$key}
76             && !$s_check{$key}{validator}->($value) )
77             {
78 0         0 tracer->debug( "\tInvalid value of setting "
79             . const_name( "settings", $key ) . ": "
80             . $value );
81 0         0 $con->error( $s_check{$key}{error} );
82 0         0 return undef;
83             }
84              
85             # Settings change may run some action
86 13 50       2019 $s_action{$key}->( $con, $value ) if exists $s_action{$key};
87              
88 13         2021 tracer->debug(
89             "\tSettings " . const_name( "settings", $key ) . " = $value\n" );
90 13         1948 $con->enc_setting( $key, $value );
91             }
92              
93 13         1958 $con->accept_settings();
94 13         3884 return $length;
95             }
96              
97             sub encode {
98 54     54 0 7956 my ( $con, $flags_ref, $stream, $data ) = @_;
99 54         7847 my $payload = '';
100 54         7899 for my $key ( sort keys %$data ) {
101 15         1985 tracer->debug( "\tSettings "
102             . const_name( "settings", $key )
103             . " = $data->{$key}\n" );
104 15         4065 $payload .= pack( 'nN', $key, $data->{$key} );
105             }
106 54         15432 return $payload;
107             }
108              
109             1;