| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Mojo::Server::Daemon; |
|
2
|
54
|
|
|
54
|
|
4925
|
use Mojo::Base 'Mojo::Server'; |
|
|
54
|
|
|
|
|
218
|
|
|
|
54
|
|
|
|
|
393
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
54
|
|
|
54
|
|
428
|
use Carp qw(croak); |
|
|
54
|
|
|
|
|
157
|
|
|
|
54
|
|
|
|
|
2757
|
|
|
5
|
54
|
|
|
54
|
|
871
|
use Mojo::IOLoop; |
|
|
54
|
|
|
|
|
152
|
|
|
|
54
|
|
|
|
|
409
|
|
|
6
|
54
|
|
|
54
|
|
27247
|
use Mojo::Transaction::WebSocket; |
|
|
54
|
|
|
|
|
235
|
|
|
|
54
|
|
|
|
|
642
|
|
|
7
|
54
|
|
|
54
|
|
416
|
use Mojo::URL; |
|
|
54
|
|
|
|
|
196
|
|
|
|
54
|
|
|
|
|
332
|
|
|
8
|
54
|
|
|
54
|
|
332
|
use Mojo::Util qw(term_escape); |
|
|
54
|
|
|
|
|
152
|
|
|
|
54
|
|
|
|
|
3083
|
|
|
9
|
54
|
|
|
54
|
|
345
|
use Mojo::WebSocket qw(server_handshake); |
|
|
54
|
|
|
|
|
217
|
|
|
|
54
|
|
|
|
|
2280
|
|
|
10
|
54
|
|
|
54
|
|
382
|
use Scalar::Util qw(weaken); |
|
|
54
|
|
|
|
|
153
|
|
|
|
54
|
|
|
|
|
3541
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
54
|
|
50
|
54
|
|
429
|
use constant DEBUG => $ENV{MOJO_SERVER_DEBUG} || 0; |
|
|
54
|
|
|
|
|
147
|
|
|
|
54
|
|
|
|
|
192485
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
has acceptors => sub { [] }; |
|
15
|
|
|
|
|
|
|
has [qw(backlog max_clients silent)]; |
|
16
|
|
|
|
|
|
|
has inactivity_timeout => sub { $ENV{MOJO_INACTIVITY_TIMEOUT} // 30 }; |
|
17
|
|
|
|
|
|
|
has ioloop => sub { Mojo::IOLoop->singleton }; |
|
18
|
|
|
|
|
|
|
has keep_alive_timeout => sub { $ENV{MOJO_KEEP_ALIVE_TIMEOUT} // 5 }; |
|
19
|
|
|
|
|
|
|
has listen => sub { [split /,/, $ENV{MOJO_LISTEN} || 'http://*:3000'] }; |
|
20
|
|
|
|
|
|
|
has max_requests => 100; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub DESTROY { |
|
23
|
132
|
|
|
132
|
|
11465
|
my $self = shift; |
|
24
|
132
|
50
|
|
|
|
569
|
return if ${^GLOBAL_PHASE} eq 'DESTRUCT'; |
|
25
|
132
|
|
|
|
|
498
|
my $loop = $self->ioloop; |
|
26
|
132
|
|
100
|
|
|
300
|
$loop->remove($_) for keys %{$self->{connections} // {}}, @{$self->acceptors}; |
|
|
132
|
|
|
|
|
896
|
|
|
|
132
|
|
|
|
|
486
|
|
|
27
|
|
|
|
|
|
|
} |
|
28
|
|
|
|
|
|
|
|
|
29
|
134
|
|
|
134
|
1
|
366
|
sub ports { [map { $_[0]->ioloop->acceptor($_)->port } @{$_[0]->acceptors}] } |
|
|
134
|
|
|
|
|
487
|
|
|
|
134
|
|
|
|
|
522
|
|
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub run { |
|
32
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Make sure the event loop can be stopped in regular intervals |
|
35
|
0
|
|
|
|
|
0
|
my $loop = $self->ioloop; |
|
36
|
0
|
|
|
0
|
|
0
|
my $int = $loop->recurring(1 => sub { }); |
|
37
|
0
|
|
|
0
|
|
0
|
local $SIG{INT} = local $SIG{TERM} = sub { $loop->stop }; |
|
|
0
|
|
|
|
|
0
|
|
|
38
|
0
|
|
|
|
|
0
|
$self->start->ioloop->start; |
|
39
|
0
|
|
|
|
|
0
|
$loop->remove($int); |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub start { |
|
43
|
140
|
|
|
140
|
1
|
349
|
my $self = shift; |
|
44
|
|
|
|
|
|
|
|
|
45
|
140
|
|
|
|
|
559
|
my $loop = $self->ioloop; |
|
46
|
140
|
100
|
|
|
|
619
|
if (my $max = $self->max_clients) { $loop->max_connections($max) } |
|
|
4
|
|
|
|
|
13
|
|
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Resume accepting connections |
|
49
|
140
|
100
|
|
|
|
539
|
if (my $servers = $self->{servers}) { |
|
|
|
100
|
|
|
|
|
|
|
50
|
1
|
|
|
|
|
6
|
push @{$self->acceptors}, $loop->acceptor(delete $servers->{$_}) for keys %$servers; |
|
|
1
|
|
|
|
|
5
|
|
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Start listening |
|
54
|
139
|
|
|
|
|
688
|
elsif (!@{$self->acceptors}) { |
|
55
|
138
|
|
|
|
|
446
|
$self->app->server($self); |
|
56
|
138
|
|
|
|
|
281
|
$self->_listen($_) for @{$self->listen}; |
|
|
138
|
|
|
|
|
587
|
|
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
138
|
|
|
|
|
842
|
return $self; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub stop { |
|
63
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Suspend accepting connections but keep listen sockets open |
|
66
|
1
|
|
|
|
|
6
|
my $loop = $self->ioloop; |
|
67
|
1
|
|
|
|
|
3
|
while (my $id = shift @{$self->acceptors}) { |
|
|
2
|
|
|
|
|
5
|
|
|
68
|
1
|
|
|
|
|
7
|
my $server = $self->{servers}{$id} = $loop->acceptor($id); |
|
69
|
1
|
|
|
|
|
5
|
$loop->remove($id); |
|
70
|
1
|
|
|
|
|
6
|
$server->stop; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
1
|
|
|
|
|
5
|
return $self; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _build_tx { |
|
77
|
948
|
|
|
948
|
|
2358
|
my ($self, $id, $c) = @_; |
|
78
|
|
|
|
|
|
|
|
|
79
|
948
|
|
|
|
|
3961
|
my $tx = $self->build_tx->connection($id); |
|
80
|
948
|
|
|
|
|
3122
|
$tx->res->headers->server('Mojolicious (Perl)'); |
|
81
|
948
|
|
|
|
|
3370
|
my $handle = $self->ioloop->stream($id)->timeout($self->inactivity_timeout)->handle; |
|
82
|
948
|
50
|
|
|
|
6060
|
unless ($handle->isa('IO::Socket::UNIX')) { |
|
83
|
948
|
|
|
|
|
3408
|
$tx->local_address($handle->sockhost)->local_port($handle->sockport); |
|
84
|
948
|
|
|
|
|
4077
|
$tx->remote_address($handle->peerhost)->remote_port($handle->peerport); |
|
85
|
|
|
|
|
|
|
} |
|
86
|
948
|
50
|
|
|
|
3593
|
$tx->req->url->base->scheme('https') if $c->{tls}; |
|
87
|
|
|
|
|
|
|
|
|
88
|
948
|
|
|
|
|
3529
|
weaken $self; |
|
89
|
|
|
|
|
|
|
$tx->on( |
|
90
|
|
|
|
|
|
|
request => sub { |
|
91
|
948
|
|
|
948
|
|
1781
|
my $tx = shift; |
|
92
|
|
|
|
|
|
|
|
|
93
|
948
|
|
|
|
|
2708
|
my $req = $tx->req; |
|
94
|
948
|
100
|
|
|
|
2886
|
if (my $error = $req->error) { $self->_trace($id, $error->{message}) } |
|
|
1
|
|
|
|
|
7
|
|
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# WebSocket |
|
97
|
948
|
100
|
|
|
|
2857
|
if ($req->is_handshake) { |
|
98
|
72
|
|
|
|
|
550
|
my $ws = $self->{connections}{$id}{next} = Mojo::Transaction::WebSocket->new(handshake => $tx); |
|
99
|
72
|
|
|
|
|
331
|
$self->emit(request => server_handshake $ws); |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# HTTP |
|
103
|
876
|
|
|
|
|
3428
|
else { $self->emit(request => $tx) } |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Last keep-alive request or corrupted connection |
|
106
|
948
|
|
|
|
|
3433
|
my $c = $self->{connections}{$id}; |
|
107
|
948
|
100
|
100
|
|
|
4704
|
$tx->res->headers->connection('close') if ($c->{requests} || 1) >= $self->max_requests || $req->error; |
|
|
|
|
100
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
|
109
|
948
|
|
|
|
|
6546
|
$tx->on(resume => sub { $self->_write($id) }); |
|
|
94
|
|
|
|
|
380
|
|
|
110
|
948
|
|
|
|
|
3824
|
$self->_write($id); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
948
|
|
|
|
|
8337
|
); |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Kept alive if we have more than one request on the connection |
|
115
|
948
|
100
|
|
|
|
4703
|
return ++$c->{requests} > 1 ? $tx->kept_alive(1) : $tx; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub _close { |
|
119
|
238
|
|
|
238
|
|
620
|
my ($self, $id) = @_; |
|
120
|
238
|
100
|
|
|
|
917
|
if (my $tx = $self->{connections}{$id}{tx}) { $tx->closed } |
|
|
68
|
|
|
|
|
255
|
|
|
121
|
238
|
|
|
|
|
4655
|
delete $self->{connections}{$id}; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
|
|
124
|
4
|
100
|
|
4
|
|
63
|
sub _trace { $_[0]->app->log->trace($_[2]) if $_[0]{connections}{$_[1]}{tx} } |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub _finish { |
|
127
|
1042
|
|
|
1042
|
|
2782
|
my ($self, $id) = @_; |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Always remove connection for WebSockets |
|
130
|
1042
|
|
|
|
|
2431
|
my $c = $self->{connections}{$id}; |
|
131
|
1042
|
100
|
|
|
|
3394
|
return unless my $tx = $c->{tx}; |
|
132
|
986
|
100
|
|
|
|
3210
|
return $self->_remove($id) if $tx->is_websocket; |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# Finish transaction |
|
135
|
940
|
|
|
|
|
3653
|
delete($c->{tx})->closed; |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Upgrade connection to WebSocket |
|
138
|
940
|
100
|
|
|
|
3017
|
if (my $ws = delete $c->{next}) { |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Successful upgrade |
|
141
|
72
|
100
|
|
|
|
285
|
if ($ws->handshake->res->code == 101) { |
|
142
|
62
|
|
|
|
|
188
|
$c->{tx} = $ws->established(1); |
|
143
|
62
|
|
|
|
|
238
|
weaken $self; |
|
144
|
62
|
|
|
246
|
|
434
|
$ws->on(resume => sub { $self->_write($id) }); |
|
|
246
|
|
|
|
|
716
|
|
|
145
|
62
|
|
|
|
|
211
|
$self->_write($id); |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Failed upgrade |
|
149
|
10
|
|
|
|
|
59
|
else { $ws->closed } |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Close connection if necessary |
|
153
|
940
|
100
|
100
|
|
|
2861
|
return $self->_remove($id) if $tx->error || !$tx->keep_alive; |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Build new transaction for leftovers |
|
156
|
913
|
100
|
|
|
|
2674
|
if (length(my $leftovers = $tx->req->content->leftovers)) { |
|
157
|
1
|
|
|
|
|
6
|
$tx = $c->{tx} = $self->_build_tx($id, $c); |
|
158
|
1
|
|
|
|
|
6
|
$tx->server_read($leftovers); |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Keep-alive connection |
|
162
|
913
|
100
|
|
|
|
4118
|
$self->ioloop->stream($id)->timeout($self->keep_alive_timeout) unless $c->{tx}; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _listen { |
|
166
|
138
|
|
|
138
|
|
519
|
my ($self, $listen) = @_; |
|
167
|
|
|
|
|
|
|
|
|
168
|
138
|
|
|
|
|
753
|
my $url = Mojo::URL->new($listen); |
|
169
|
138
|
|
|
|
|
568
|
my $proto = $url->protocol; |
|
170
|
138
|
100
|
100
|
|
|
971
|
croak qq{Invalid listen location "$listen"} unless $proto eq 'http' || $proto eq 'https' || $proto eq 'http+unix'; |
|
|
|
|
66
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
|
172
|
137
|
|
|
|
|
500
|
my $query = $url->query; |
|
173
|
137
|
|
|
|
|
712
|
my $options = {backlog => $self->backlog}; |
|
174
|
137
|
|
|
|
|
1117
|
$options->{$_} = $query->param($_) for qw(fd single_accept reuse); |
|
175
|
137
|
50
|
|
|
|
544
|
if ($proto eq 'http+unix') { $options->{path} = $url->host } |
|
|
0
|
|
|
|
|
0
|
|
|
176
|
|
|
|
|
|
|
else { |
|
177
|
137
|
50
|
|
|
|
475
|
if ((my $host = $url->host) ne '*') { $options->{address} = $host } |
|
|
137
|
|
|
|
|
426
|
|
|
178
|
137
|
50
|
|
|
|
493
|
if (my $port = $url->port) { $options->{port} = $port } |
|
|
0
|
|
|
|
|
0
|
|
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
137
|
|
|
|
|
438
|
$options->{tls_ca} = $query->param('ca'); |
|
182
|
137
|
|
33
|
|
|
341
|
/^(.*)_(cert|key)$/ and $options->{"tls_$2"}{$1} = $query->param($_) for @{$query->names}; |
|
|
137
|
|
|
|
|
543
|
|
|
183
|
137
|
50
|
|
|
|
478
|
if (my $cert = $query->param('cert')) { $options->{tls_cert}{''} = $cert } |
|
|
0
|
|
|
|
|
0
|
|
|
184
|
137
|
50
|
|
|
|
503
|
if (my $key = $query->param('key')) { $options->{tls_key}{''} = $key } |
|
|
0
|
|
|
|
|
0
|
|
|
185
|
137
|
|
|
|
|
575
|
my ($ciphers, $verify, $version) = ($query->param('ciphers'), $query->param('verify'), $query->param('version')); |
|
186
|
137
|
50
|
|
|
|
569
|
$options->{tls_options}{SSL_cipher_list} = $ciphers if defined $ciphers; |
|
187
|
137
|
50
|
|
|
|
428
|
$options->{tls_options}{SSL_verify_mode} = hex $verify if defined $verify; |
|
188
|
137
|
50
|
|
|
|
437
|
$options->{tls_options}{SSL_version} = $version if defined $version; |
|
189
|
137
|
|
|
|
|
562
|
my $tls = $options->{tls} = $proto eq 'https'; |
|
190
|
|
|
|
|
|
|
|
|
191
|
137
|
|
|
|
|
627
|
weaken $self; |
|
192
|
137
|
|
|
|
|
473
|
push @{$self->acceptors}, $self->ioloop->server( |
|
193
|
|
|
|
|
|
|
$options => sub { |
|
194
|
181
|
|
|
181
|
|
658
|
my ($loop, $stream, $id) = @_; |
|
195
|
|
|
|
|
|
|
|
|
196
|
181
|
|
|
|
|
1002
|
$self->{connections}{$id} = {tls => $tls}; |
|
197
|
181
|
|
|
|
|
397
|
warn "-- Accept $id (@{[_peer($stream->handle)]})\n" if DEBUG; |
|
198
|
181
|
|
|
|
|
856
|
$stream->timeout($self->inactivity_timeout); |
|
199
|
|
|
|
|
|
|
|
|
200
|
181
|
50
|
|
|
|
1623
|
$stream->on(close => sub { $self && $self->_close($id) }); |
|
|
165
|
|
|
|
|
939
|
|
|
201
|
181
|
0
|
0
|
|
|
1191
|
$stream->on(error => sub { $self && $self->app->log->error(pop) && $self->_close($id) }); |
|
|
0
|
|
|
|
|
0
|
|
|
202
|
181
|
|
|
|
|
1056
|
$stream->on(read => sub { $self->_read($id => pop) }); |
|
|
1138
|
|
|
|
|
4353
|
|
|
203
|
181
|
|
|
|
|
1090
|
$stream->on(timeout => sub { $self->_trace($id, 'Inactivity timeout (see FAQ for more)') }); |
|
|
3
|
|
|
|
|
34
|
|
|
204
|
|
|
|
|
|
|
} |
|
205
|
137
|
|
|
|
|
279
|
); |
|
206
|
|
|
|
|
|
|
|
|
207
|
136
|
50
|
|
|
|
748
|
return if $self->silent; |
|
208
|
0
|
|
|
|
|
0
|
$self->app->log->info(qq{Listening at "$url"}); |
|
209
|
0
|
|
|
|
|
0
|
$query->pairs([]); |
|
210
|
0
|
0
|
|
|
|
0
|
$url->host('127.0.0.1') if $url->host eq '*'; |
|
211
|
0
|
0
|
0
|
|
|
0
|
$url->port($self->ports->[-1]) if !$options->{path} && !$url->port; |
|
212
|
0
|
|
0
|
|
|
0
|
say 'Web application available at ', $options->{path} // $url; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
0
|
0
|
|
0
|
|
0
|
sub _peer { $_[0]->isa('IO::Socket::UNIX') ? $_[0]->peerpath : $_[0]->peerhost } |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub _read { |
|
218
|
1138
|
|
|
1138
|
|
3289
|
my ($self, $id, $chunk) = @_; |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Make sure we have a transaction |
|
221
|
1138
|
|
|
|
|
2668
|
my $c = $self->{connections}{$id}; |
|
222
|
1138
|
|
66
|
|
|
5549
|
my $tx = $c->{tx} ||= $self->_build_tx($id, $c); |
|
223
|
1138
|
|
|
|
|
1881
|
warn term_escape "-- Server <<< Client (@{[_url($tx)]})\n$chunk\n" if DEBUG; |
|
224
|
1138
|
|
|
|
|
4013
|
$tx->server_read($chunk); |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub _remove { |
|
228
|
73
|
|
|
73
|
|
242
|
my ($self, $id) = @_; |
|
229
|
73
|
|
|
|
|
229
|
$self->ioloop->remove($id); |
|
230
|
73
|
|
|
|
|
307
|
$self->_close($id); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
0
|
|
|
0
|
|
0
|
sub _url { shift->req->url->to_abs } |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub _write { |
|
236
|
2340
|
|
|
2340
|
|
5352
|
my ($self, $id) = @_; |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# Protect from resume event recursion |
|
239
|
2340
|
|
|
|
|
4953
|
my $c = $self->{connections}{$id}; |
|
240
|
2340
|
100
|
100
|
|
|
11217
|
return if !(my $tx = $c->{tx}) || $c->{writing}; |
|
241
|
2298
|
|
|
|
|
5387
|
local $c->{writing} = 1; |
|
242
|
2298
|
|
|
|
|
7106
|
my $chunk = $tx->server_write; |
|
243
|
2298
|
|
|
|
|
3604
|
warn term_escape "-- Server >>> Client (@{[_url($tx)]})\n$chunk\n" if DEBUG; |
|
244
|
2298
|
100
|
|
|
|
7420
|
my $next = $tx->is_finished ? '_finish' : length $chunk ? '_write' : undef; |
|
|
|
100
|
|
|
|
|
|
|
245
|
2298
|
100
|
|
|
|
5626
|
return $self->ioloop->stream($id)->write($chunk) unless $next; |
|
246
|
2058
|
|
|
|
|
7152
|
weaken $self; |
|
247
|
2058
|
|
|
2032
|
|
5741
|
$self->ioloop->stream($id)->write($chunk => sub { $self->$next($id) }); |
|
|
2032
|
|
|
|
|
8355
|
|
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
1; |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=encoding utf8 |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head1 NAME |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
use Mojo::Server::Daemon; |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
my $daemon = Mojo::Server::Daemon->new(listen => ['http://*:8080']); |
|
263
|
|
|
|
|
|
|
$daemon->unsubscribe('request')->on(request => sub ($daemon, $tx) { |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# Request |
|
266
|
|
|
|
|
|
|
my $method = $tx->req->method; |
|
267
|
|
|
|
|
|
|
my $path = $tx->req->url->path; |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Response |
|
270
|
|
|
|
|
|
|
$tx->res->code(200); |
|
271
|
|
|
|
|
|
|
$tx->res->headers->content_type('text/plain'); |
|
272
|
|
|
|
|
|
|
$tx->res->body("$method request for $path!"); |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Resume transaction |
|
275
|
|
|
|
|
|
|
$tx->resume; |
|
276
|
|
|
|
|
|
|
}); |
|
277
|
|
|
|
|
|
|
$daemon->run; |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
L is a full featured, highly portable non-blocking I/O HTTP and WebSocket server, with IPv6, TLS, |
|
282
|
|
|
|
|
|
|
SNI, Comet (long polling), keep-alive and multiple event loop support. |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
For better scalability (epoll, kqueue) and to provide non-blocking name resolution, SOCKS5 as well as TLS support, the |
|
285
|
|
|
|
|
|
|
optional modules L (4.32+), L (0.15+), L (0.64+) and L |
|
286
|
|
|
|
|
|
|
(2.009+) will be used automatically if possible. Individual features can also be disabled with the C, |
|
287
|
|
|
|
|
|
|
C and C environment variables. |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
See L for more. |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=head1 SIGNALS |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
The L process can be controlled at runtime with the following signals. |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head2 INT, TERM |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
Shut down server immediately. |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head1 EVENTS |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
L inherits all events from L. |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
L inherits all attributes from L and implements the following new ones. |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head2 acceptors |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
my $acceptors = $daemon->acceptors; |
|
310
|
|
|
|
|
|
|
$daemon = $daemon->acceptors(['6be0c140ef00a389c5d039536b56d139']); |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Active acceptor ids. |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# Check port |
|
315
|
|
|
|
|
|
|
mu $port = $daemon->ioloop->acceptor($daemon->acceptors->[0])->port; |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
=head2 backlog |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
my $backlog = $daemon->backlog; |
|
320
|
|
|
|
|
|
|
$daemon = $daemon->backlog(128); |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Listen backlog size, defaults to C. |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head2 inactivity_timeout |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
my $timeout = $daemon->inactivity_timeout; |
|
327
|
|
|
|
|
|
|
$daemon = $daemon->inactivity_timeout(5); |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Maximum amount of time in seconds a connection with an active request can be inactive before getting closed, defaults |
|
330
|
|
|
|
|
|
|
to the value of the C environment variable or C<30>. Setting the value to C<0> will allow |
|
331
|
|
|
|
|
|
|
connections to be inactive indefinitely. |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head2 ioloop |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
my $loop = $daemon->ioloop; |
|
336
|
|
|
|
|
|
|
$daemon = $daemon->ioloop(Mojo::IOLoop->new); |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
Event loop object to use for I/O operations, defaults to the global L singleton. |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head2 keep_alive_timeout |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
my $timeout = $daemon->keep_alive_timeout; |
|
343
|
|
|
|
|
|
|
$daemon = $daemon->keep_alive_timeout(10); |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
Maximum amount of time in seconds a connection without an active request can be inactive before getting closed, |
|
346
|
|
|
|
|
|
|
defaults to the value of the C environment variable or C<5>. Setting the value to C<0> will |
|
347
|
|
|
|
|
|
|
allow connections to be inactive indefinitely. |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head2 listen |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
my $listen = $daemon->listen; |
|
352
|
|
|
|
|
|
|
$daemon = $daemon->listen(['https://127.0.0.1:8080']); |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Array reference with one or more locations to listen on, defaults to the value of the C environment |
|
355
|
|
|
|
|
|
|
variable or C (shortcut for C). |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Listen on all IPv4 interfaces |
|
358
|
|
|
|
|
|
|
$daemon->listen(['http://*:3000']); |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# Listen on all IPv4 and IPv6 interfaces |
|
361
|
|
|
|
|
|
|
$daemon->listen(['http://[::]:3000']); |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# Listen on IPv6 interface |
|
364
|
|
|
|
|
|
|
$daemon->listen(['http://[::1]:4000']); |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# Listen on IPv4 and IPv6 interfaces |
|
367
|
|
|
|
|
|
|
$daemon->listen(['http://127.0.0.1:3000', 'http://[::1]:3000']); |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Listen on UNIX domain socket "/tmp/myapp.sock" (percent encoded slash) |
|
370
|
|
|
|
|
|
|
$daemon->listen(['http+unix://%2Ftmp%2Fmyapp.sock']); |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# File descriptor, as used by systemd |
|
373
|
|
|
|
|
|
|
$daemon->listen(['http://127.0.0.1?fd=3']); |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# Allow multiple servers to use the same port (SO_REUSEPORT) |
|
376
|
|
|
|
|
|
|
$daemon->listen(['http://*:8080?reuse=1']); |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Listen on two ports with HTTP and HTTPS at the same time |
|
379
|
|
|
|
|
|
|
$daemon->listen(['http://*:3000', 'https://*:4000']); |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# Use a custom certificate and key |
|
382
|
|
|
|
|
|
|
$daemon->listen(['https://*:3000?cert=/x/server.crt&key=/y/server.key']); |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# Domain specific certificates and keys (SNI) |
|
385
|
|
|
|
|
|
|
$daemon->listen( |
|
386
|
|
|
|
|
|
|
['https://*:3000?example.com_cert=/x/my.crt&example.com_key=/y/my.key']); |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# Or even a custom certificate authority |
|
389
|
|
|
|
|
|
|
$daemon->listen( |
|
390
|
|
|
|
|
|
|
['https://*:3000?cert=/x/server.crt&key=/y/server.key&ca=/z/ca.crt']); |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
These parameters are currently available: |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=over 2 |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=item ca |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
ca=/etc/tls/ca.crt |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
Path to TLS certificate authority file used to verify the peer certificate. |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=item cert |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
cert=/etc/tls/server.crt |
|
405
|
|
|
|
|
|
|
mojolicious.org_cert=/etc/tls/mojo.crt |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Path to the TLS cert file, defaults to a built-in test certificate. |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=item ciphers |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
ciphers=AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
TLS cipher specification string. For more information about the format see |
|
414
|
|
|
|
|
|
|
L. |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=item fd |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
fd=3 |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
File descriptor with an already prepared listen socket. |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=item key |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
key=/etc/tls/server.key |
|
425
|
|
|
|
|
|
|
mojolicious.org_key=/etc/tls/mojo.key |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Path to the TLS key file, defaults to a built-in test key. |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=item reuse |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
reuse=1 |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
Allow multiple servers to use the same port with the C socket option. |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=item single_accept |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
single_accept=1 |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Only accept one connection at a time. |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=item verify |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
verify=0x00 |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
TLS verification mode. |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=item version |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
version=TLSv1_2 |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
TLS protocol version. |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=back |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=head2 max_clients |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
my $max = $daemon->max_clients; |
|
458
|
|
|
|
|
|
|
$daemon = $daemon->max_clients(100); |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
Maximum number of accepted connections this server is allowed to handle concurrently, before stopping to accept new |
|
461
|
|
|
|
|
|
|
incoming connections, passed along to L. |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head2 max_requests |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
my $max = $daemon->max_requests; |
|
466
|
|
|
|
|
|
|
$daemon = $daemon->max_requests(250); |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
Maximum number of keep-alive requests per connection, defaults to C<100>. |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head2 silent |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
my $bool = $daemon->silent; |
|
473
|
|
|
|
|
|
|
$daemon = $daemon->silent($bool); |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
Disable console messages. |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head1 METHODS |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
L inherits all methods from L and implements the following new ones. |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=head2 ports |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
my $ports = $daemon->ports; |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Get all ports this server is currently listening on. |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
# All ports |
|
488
|
|
|
|
|
|
|
say for @{$daemon->ports}; |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head2 run |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
$daemon->run; |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
Run server and wait for L"SIGNALS">. |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=head2 start |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
$daemon = $daemon->start; |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
Start or resume accepting connections through L"ioloop">. |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
# Listen on random port |
|
503
|
|
|
|
|
|
|
my $port = $daemon->listen(['http://127.0.0.1'])->start->ports->[0]; |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# Run multiple web servers concurrently |
|
506
|
|
|
|
|
|
|
my $daemon1 = Mojo::Server::Daemon->new(listen => ['http://*:3000'])->start; |
|
507
|
|
|
|
|
|
|
my $daemon2 = Mojo::Server::Daemon->new(listen => ['http://*:4000'])->start; |
|
508
|
|
|
|
|
|
|
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head2 stop |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
$daemon = $daemon->stop; |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Stop accepting connections through L"ioloop">. |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=head1 DEBUGGING |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
You can set the C environment variable to get some advanced diagnostics information printed to |
|
519
|
|
|
|
|
|
|
C. |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
MOJO_SERVER_DEBUG=1 |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
L, L, L. |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=cut |