| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package AnyEvent::WebSocket::Server; |
|
2
|
8
|
|
|
8
|
|
458284
|
use strict; |
|
|
8
|
|
|
|
|
13
|
|
|
|
8
|
|
|
|
|
177
|
|
|
3
|
8
|
|
|
8
|
|
25
|
use warnings; |
|
|
8
|
|
|
|
|
8
|
|
|
|
8
|
|
|
|
|
135
|
|
|
4
|
8
|
|
|
8
|
|
23
|
use Carp; |
|
|
8
|
|
|
|
|
12
|
|
|
|
8
|
|
|
|
|
360
|
|
|
5
|
8
|
|
|
8
|
|
3596
|
use AnyEvent::Handle; |
|
|
8
|
|
|
|
|
55416
|
|
|
|
8
|
|
|
|
|
206
|
|
|
6
|
8
|
|
|
8
|
|
3557
|
use Protocol::WebSocket::Handshake::Server; |
|
|
8
|
|
|
|
|
996624
|
|
|
|
8
|
|
|
|
|
221
|
|
|
7
|
8
|
|
|
8
|
|
53
|
use Try::Tiny; |
|
|
8
|
|
|
|
|
12
|
|
|
|
8
|
|
|
|
|
422
|
|
|
8
|
8
|
|
|
8
|
|
2933
|
use AnyEvent::WebSocket::Connection; |
|
|
8
|
|
|
|
|
27963
|
|
|
|
8
|
|
|
|
|
5217
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = "0.08"; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub new { |
|
13
|
45
|
|
|
45
|
1
|
373433
|
my ($class, %args) = @_; |
|
14
|
45
|
|
|
|
|
92
|
my $validator = $args{validator}; |
|
15
|
45
|
50
|
66
|
|
|
192
|
if(defined($validator) && ref($validator) ne "CODE") { |
|
16
|
0
|
|
|
|
|
0
|
croak "validator parameter must be a code-ref"; |
|
17
|
|
|
|
|
|
|
} |
|
18
|
|
|
|
|
|
|
my $handshake = defined($args{handshake}) ? $args{handshake} |
|
19
|
9
|
|
|
9
|
|
36
|
: defined($validator) ? sub { my ($req, $res) = @_; return ($res, $validator->($req)); } |
|
|
9
|
|
|
|
|
19
|
|
|
20
|
45
|
100
|
|
159
|
|
225
|
: sub { $_[1] }; |
|
|
159
|
100
|
|
|
|
770
|
|
|
21
|
45
|
50
|
|
|
|
151
|
if(ref($handshake) ne "CODE") { |
|
22
|
0
|
|
|
|
|
0
|
croak "handshake parameter must be a code-ref"; |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
my $self = bless { |
|
25
|
|
|
|
|
|
|
handshake => $handshake, |
|
26
|
45
|
|
|
|
|
82
|
map { ($_ => $args{$_}) } qw(ssl_key_file ssl_cert_file), |
|
|
90
|
|
|
|
|
298
|
|
|
27
|
|
|
|
|
|
|
}, $class; |
|
28
|
45
|
|
|
|
|
141
|
return $self; |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub _create_on_error { |
|
32
|
203
|
|
|
203
|
|
248
|
my ($cv) = @_; |
|
33
|
|
|
|
|
|
|
return sub { |
|
34
|
4
|
|
|
4
|
|
403
|
my ($handle, $fatal, $message) = @_; |
|
35
|
4
|
50
|
|
|
|
10
|
if($fatal) { |
|
36
|
4
|
|
|
|
|
18
|
$cv->croak("connection error: $message"); |
|
37
|
|
|
|
|
|
|
}else { |
|
38
|
0
|
|
|
|
|
0
|
warn $message; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
203
|
|
|
|
|
1209
|
}; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub _handle_args_tls { |
|
44
|
203
|
|
|
203
|
|
196
|
my ($self) = @_; |
|
45
|
203
|
100
|
66
|
|
|
681
|
if(!defined($self->{ssl_key_file}) && !defined($self->{ssl_cert_file})) { |
|
46
|
68
|
|
|
|
|
152
|
return (); |
|
47
|
|
|
|
|
|
|
} |
|
48
|
135
|
50
|
|
|
|
312
|
if(!defined($self->{ssl_cert_file})) { |
|
49
|
0
|
|
|
|
|
0
|
croak "Only ssl_key_file is specified. You need to specify ssl_cert_file, too."; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
return ( |
|
52
|
|
|
|
|
|
|
tls => "accept", |
|
53
|
|
|
|
|
|
|
tls_ctx => { |
|
54
|
|
|
|
|
|
|
cert_file => $self->{ssl_cert_file}, |
|
55
|
135
|
100
|
|
|
|
770
|
defined($self->{ssl_key_file}) ? (key_file => $self->{ssl_key_file}) : () |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub _do_handshake { |
|
61
|
203
|
|
|
203
|
|
300
|
my ($self, $cv_connection, $fh, $handshake) = @_; |
|
62
|
203
|
|
|
|
|
257
|
my $handshake_code = $self->{handshake}; |
|
63
|
203
|
|
|
|
|
400
|
my $handle = AnyEvent::Handle->new( |
|
64
|
|
|
|
|
|
|
$self->_handle_args_tls, |
|
65
|
|
|
|
|
|
|
fh => $fh, on_error => _create_on_error($cv_connection) |
|
66
|
|
|
|
|
|
|
); |
|
67
|
|
|
|
|
|
|
my $read_cb = sub { |
|
68
|
|
|
|
|
|
|
## We don't receive handle object as an argument here. $handle |
|
69
|
|
|
|
|
|
|
## is imported in this closure so that $handle becomes |
|
70
|
|
|
|
|
|
|
## half-immortal. |
|
71
|
|
|
|
|
|
|
try { |
|
72
|
405
|
100
|
|
|
|
12590
|
if(!defined($handshake->parse($handle->{rbuf}))) { |
|
73
|
4
|
|
|
|
|
755
|
die "handshake error: " . $handshake->error . "\n"; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
401
|
100
|
|
|
|
99727
|
return if !$handshake->is_done; |
|
76
|
195
|
50
|
|
|
|
1635
|
if($handshake->version ne "draft-ietf-hybi-17") { |
|
77
|
0
|
|
|
|
|
0
|
die "handshake error: unsupported WebSocket protocol version " . $handshake->version . "\n"; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
195
|
|
|
|
|
1291
|
my ($res, @other_results) = $handshake_code->($handshake->req, $handshake->res); |
|
80
|
186
|
100
|
|
|
|
3808
|
if(!defined($res)) { |
|
81
|
3
|
|
|
|
|
311
|
croak "handshake response was undef"; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
183
|
100
|
|
|
|
412
|
if(ref($res) eq "Protocol::WebSocket::Response") { |
|
84
|
180
|
|
|
|
|
436
|
$res = $res->to_string; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
183
|
|
|
|
|
42124
|
$handle->push_write("$res"); |
|
87
|
183
|
|
|
|
|
17116
|
$cv_connection->send(AnyEvent::WebSocket::Connection->new(handle => $handle), @other_results); |
|
88
|
183
|
|
|
|
|
58194
|
undef $handle; |
|
89
|
183
|
|
|
|
|
514
|
undef $cv_connection; |
|
90
|
|
|
|
|
|
|
}catch { |
|
91
|
16
|
|
|
|
|
356
|
my $e = shift; |
|
92
|
16
|
|
|
|
|
64
|
$cv_connection->croak($e); |
|
93
|
16
|
|
|
|
|
5650
|
undef $handle; |
|
94
|
16
|
|
|
|
|
55
|
undef $cv_connection; |
|
95
|
405
|
|
|
405
|
|
2530539
|
}; |
|
96
|
203
|
|
|
|
|
88111
|
}; |
|
97
|
203
|
|
|
|
|
354
|
$handle->{rbuf} = ""; |
|
98
|
203
|
|
|
|
|
293
|
$read_cb->(); ## in case the whole request is already consumed |
|
99
|
203
|
50
|
|
|
|
4582
|
$handle->on_read($read_cb) if defined $handle; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub establish { |
|
103
|
204
|
|
|
204
|
1
|
413237
|
my ($self, $fh) = @_; |
|
104
|
204
|
|
|
|
|
4931
|
my $cv_connection = AnyEvent->condvar; |
|
105
|
204
|
100
|
|
|
|
1446
|
if(!defined($fh)) { |
|
106
|
1
|
|
|
|
|
7
|
$cv_connection->croak("fh parameter is mandatory for establish() method"); |
|
107
|
1
|
|
|
|
|
37
|
return $cv_connection; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
203
|
|
|
|
|
1056
|
my $handshake = Protocol::WebSocket::Handshake::Server->new; |
|
110
|
203
|
|
|
|
|
1211
|
$self->_do_handshake($cv_connection, $fh, $handshake); |
|
111
|
203
|
|
|
|
|
4752
|
return $cv_connection; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub establish_psgi { |
|
115
|
0
|
|
|
0
|
1
|
|
my ($self, $env, $fh) = @_; |
|
116
|
0
|
|
|
|
|
|
my $cv_connection = AnyEvent->condvar; |
|
117
|
0
|
0
|
|
|
|
|
if(!defined($env)) { |
|
118
|
0
|
|
|
|
|
|
$cv_connection->croak("psgi_env parameter is mandatory"); |
|
119
|
0
|
|
|
|
|
|
return $cv_connection; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
0
|
0
|
|
|
|
|
$fh = $env->{"psgix.io"} if not defined $fh; |
|
122
|
0
|
0
|
|
|
|
|
if(!defined($fh)) { |
|
123
|
0
|
|
|
|
|
|
$cv_connection->croak("No connection file handle provided. Maybe the PSGI server does not support psgix.io extension."); |
|
124
|
0
|
|
|
|
|
|
return $cv_connection; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
0
|
|
|
|
|
|
my $handshake = Protocol::WebSocket::Handshake::Server->new_from_psgi($env); |
|
127
|
0
|
|
|
|
|
|
$self->_do_handshake($cv_connection, $fh, $handshake); |
|
128
|
0
|
|
|
|
|
|
return $cv_connection; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
1; |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
__END__ |