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__ |