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 11     11   54 use strict;
  11         17  
  11         285  
3 11     11   52 use warnings;
  11         258  
  11         348  
4 11     11   56 use Protocol::HTTP2::Constants qw(const_name :flags :errors :limits :settings);
  11         17  
  11         3742  
5 11     11   58 use Protocol::HTTP2::Trace qw(tracer);
  11         22  
  11         8075  
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 53     53 0 10989 my ( $con, $buf_ref, $buf_offset, $length ) = @_;
37 53         10969 my $frame_ref = $con->decode_context->{frame};
38              
39 53 50       10952 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 53 100       10966 if ( $frame_ref->{flags} & ACK ) {
    100          
46 26 50       5532 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 26         10951 return 0
53              
54             # received empty settings (default), accept it
55             }
56             elsif ( $length == 0 ) {
57 13         2712 $con->accept_settings();
58 13         5495 return 0;
59             }
60              
61 14 50       2765 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 14         2767 my @settings = unpack( '(nN)*', substr( $$buf_ref, $buf_offset, $length ) );
68 14         2746 while ( my ( $key, $value ) = splice @settings, 0, 2 ) {
69 14 50 33     2758 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 14 50       2726 $s_action{$key}->( $con, $value ) if exists $s_action{$key};
87              
88 14         2725 tracer->debug(
89             "\tSettings " . const_name( "settings", $key ) . " = $value\n" );
90 14         2717 $con->enc_setting( $key, $value );
91             }
92              
93 14         2742 $con->accept_settings();
94 14         5503 return $length;
95             }
96              
97             sub encode {
98 58     58 0 10790 my ( $con, $flags_ref, $stream, $data ) = @_;
99 58         10844 my $payload = '';
100 58         10975 for my $key ( sort keys %$data ) {
101 16         2702 tracer->debug( "\tSettings "
102             . const_name( "settings", $key )
103             . " = $data->{$key}\n" );
104 16         5429 $payload .= pack( 'nN', $key, $data->{$key} );
105             }
106 58         21779 return $payload;
107             }
108              
109             1;