File Coverage

blib/lib/Net/WebSocket/Frame/close.pm
Criterion Covered Total %
statement 24 46 52.1
branch 3 20 15.0
condition 0 3 0.0
subroutine 7 8 87.5
pod 0 2 0.0
total 34 79 43.0


line stmt bran cond sub pod time code
1             package Net::WebSocket::Frame::close;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Net::WebSocket::Frame::close
8              
9             =head1 SYNOPSIS
10              
11             my $frm = Net::WebSocket::Frame::close->new(
12              
13             #Optional, can be either empty (default) or four random bytes
14             mask => q<>,
15              
16             code => 'SUCCESS', #See below
17              
18             reason => 'yeah, baby', #See below
19             );
20              
21             $frm->get_type(); #"close"
22              
23             $frm->is_control_frame(); #1
24              
25             my $mask = $frm->get_mask_bytes();
26              
27             my ($code, $reason) = $frm->get_code_and_reason();
28              
29             #If, for some reason, you need the raw payload:
30             my $payload = $frm->get_payload();
31              
32             my $serialized = $frm->to_bytes();
33              
34             Note that, L,
35             close messages can have any of:
36              
37             =over
38              
39             =item * no code, and no reason
40              
41             =item * a code, and no reason
42              
43             =item * a code, and a reason that cannot exceed 123 bytes
44              
45             =back
46              
47             The code (i.e., C<$code>) is subject to
48             L.
49             You can also, in lieu of a numeric constant, use the following string
50             constants that L:
51              
52             =over
53              
54             =item * C (1000)
55              
56             =item * C (1001)
57              
58             =item * C (1002)
59              
60             =item * C (1003)
61              
62             =item * C (1007)
63              
64             =item * C (1008)
65              
66             =item * C (1009)
67              
68             =item * C (1010)
69              
70             =item * C (1011)
71              
72             NOTE: As per L
73             3227, this status is meant to encompass client errors as well. Since these
74             constants are meant to match Microsoft’s (in default of such in the actual
75             WebSocket standard), however, Net::WebSocket only recognizes C
76             as an alias of 1011. Hopefully a future update to the WebSocket standard will
77             include useful string aliases for the status codes.
78              
79             Also note that L contains some that
80             don’t have string constants.
81              
82             =back
83              
84             =cut
85              
86 3     3   799 use strict;
  3         5  
  3         72  
87 3     3   13 use warnings;
  3         6  
  3         70  
88              
89 3         15 use parent qw(
90             Net::WebSocket::Base::ControlFrame
91 3     3   13 );
  3         5  
92              
93 3     3   576 use Call::Context ();
  3         427  
  3         43  
94              
95 3     3   14 use Net::WebSocket::Constants ();
  3         5  
  3         42  
96              
97 3     3   12 use constant get_opcode => 8;
  3         5  
  3         1011  
98              
99             sub new {
100 0     0 0 0 my ($class, %opts) = @_;
101              
102 0 0       0 if (!$opts{'payload_sr'}) {
103 0         0 my $payload;
104              
105 0 0       0 if ($opts{'code'}) {
106 0         0 my $num = Net::WebSocket::Constants::status_name_to_code($opts{'code'});
107 0 0       0 if (!$num) {
108 0         0 $num = $opts{'code'};
109              
110 0 0       0 if ($num !~ m<\A[0-9]{4}\z> ) {
111 0         0 die Net::WebSocket::X->create('BadArg', 'code', $num, 'Invalid WebSocket status code');
112             }
113              
114 0 0       0 if ( !Net::WebSocket::Constants::status_code_to_name($num) ) {
115 0 0 0     0 if ( $num < 4000 || $num > 4999 ) {
116 0         0 die Net::WebSocket::X->create('BadArg', 'code', $num, 'Disallowed WebSocket status code');
117             }
118             }
119             }
120              
121 0         0 $payload = pack 'n', $num;
122              
123 0 0       0 if (defined $opts{'reason'}) {
124 0 0       0 if (length $opts{'reason'} > 123) {
125 0         0 die Net::WebSocket::X->create('BadArg', 'reason', $opts{'reason'}, 'Reason cannot exceed 123 bytes!');
126             }
127              
128 0         0 $payload .= $opts{'reason'};
129             }
130             }
131             else {
132 0         0 $payload = q<>;
133             }
134              
135 0         0 $opts{'payload_sr'} = \$payload;
136             }
137              
138 0         0 return $class->SUPER::new( %opts, type => 'close' );
139             }
140              
141             sub get_code_and_reason {
142 15     15 0 438 my ($self) = @_;
143              
144 15         37 Call::Context::must_be_list();
145              
146             #This shouldn’t happen … maybe leftover from previous architecture?
147 15 50       130 if ($self->get_type() ne 'close') {
148 0         0 my $type = $self->get_type();
149 0         0 die "Frame type is “$type”, not “close” as expected!";
150             }
151              
152 15 100       21 return if !length ${ $self->[$self->PAYLOAD] };
  15         80  
153              
154 10         30 return unpack 'na*', $self->get_payload();
155             }
156              
157             1;