source: main/trunk/greenstone2/perllib/cpan/Mojo/Server/Daemon.pm@ 32205

Last change on this file since 32205 was 32205, checked in by ak19, 6 years ago

First set of commits to do with implementing the new 'paged_html' output option of PDFPlugin that uses using xpdftools' new pdftohtml. So far tested only on Linux (64 bit), but things work there so I'm optimistically committing the changes since they work. 2. Committing the pre-built Linux binaries of XPDFtools for both 32 and 64 bit built by the XPDF group. 2. To use the correct bitness variant of xpdftools, setup.bash now exports the BITNESS env var, consulted by gsConvert.pl. 3. All the perl code changes to do with using xpdf tools' pdftohtml to generate paged_html and feed it in the desired form into GS(3): gsConvert.pl, PDFPlugin.pm and its parent ConvertBinaryPFile.pm have been modified to make it all work. xpdftools' pdftohtml generates a folder containing an html file and a screenshot for each page in a PDF (as well as an index.html linking to each page's html). However, we want a single html file that contains each individual 'page' html's content in a div, and need to do some further HTML style, attribute and structure modifications to massage the xpdftool output to what we want for GS. In order to parse and manipulate the HTML 'DOM' to do this, we're using the Mojo::DOM package that Dr Bainbridge found and which he's compiled up. Mojo::DOM is therefore also committed in this revision. Some further changes and some display fixes are required, but need to check with the others about that.

File size: 11.9 KB
Line 
1package Mojo::Server::Daemon;
2use Mojo::Base 'Mojo::Server';
3
4use Carp 'croak';
5use Mojo::IOLoop;
6use Mojo::IOLoop::Stream::HTTPServer;
7use Mojo::IOLoop::Stream::WebSocketServer;
8use Mojo::URL;
9use Scalar::Util 'weaken';
10
11use constant DEBUG => $ENV{MOJO_SERVER_DEBUG} || 0;
12
13has acceptors => sub { [] };
14has [qw(backlog max_clients silent)];
15has inactivity_timeout => sub { $ENV{MOJO_INACTIVITY_TIMEOUT} // 15 };
16has ioloop => sub { Mojo::IOLoop->singleton };
17has listen => sub { [split ',', $ENV{MOJO_LISTEN} || 'http://*:3000'] };
18has max_requests => 100;
19
20sub DESTROY {
21 return if Mojo::Util::_global_destruction();
22 my $self = shift;
23 my $loop = $self->ioloop;
24 $loop->remove($_) for keys %{$self->{connections} || {}}, @{$self->acceptors};
25}
26
27sub close_connections {
28 my $self = shift;
29 my $loop = $self->ioloop;
30 $_->max_requests(1)
31 for map { $loop->stream($_) || () } keys %{$self->{connections} || {}};
32}
33
34sub ports { [map { $_[0]->ioloop->acceptor($_)->port } @{$_[0]->acceptors}] }
35
36sub run {
37 my $self = shift;
38
39 # Make sure the event loop can be stopped in regular intervals
40 my $loop = $self->ioloop;
41 my $int = $loop->recurring(1 => sub { });
42 local $SIG{INT} = local $SIG{TERM} = sub { $loop->stop };
43 $self->start->ioloop->start;
44 $loop->remove($int);
45}
46
47sub start {
48 my $self = shift;
49
50 my $loop = $self->ioloop;
51 if (my $max = $self->max_clients) { $loop->max_connections($max) }
52
53 # Resume accepting connections
54 if (my $servers = $self->{servers}) {
55 push @{$self->acceptors}, $loop->acceptor(delete $servers->{$_})
56 for keys %$servers;
57 }
58
59 # Start listening
60 elsif (!@{$self->acceptors}) {
61 $self->app->server($self);
62 $self->_listen($_) for @{$self->listen};
63 }
64
65 return $self;
66}
67
68sub stop {
69 my $self = shift;
70
71 # Suspend accepting connections but keep listen sockets open
72 my $loop = $self->ioloop;
73 while (my $id = shift @{$self->acceptors}) {
74 my $server = $self->{servers}{$id} = $loop->acceptor($id);
75 $loop->remove($id);
76 $server->stop;
77 }
78
79 return $self;
80}
81
82sub _debug { $_[0]->app->log->debug($_[2]) if $_[0]{connections}{$_[1]}{tx} }
83
84sub _listen {
85 my ($self, $listen) = @_;
86
87 my $url = Mojo::URL->new($listen);
88 my $proto = $url->protocol;
89 croak qq{Invalid listen location "$listen"}
90 unless $proto eq 'http' || $proto eq 'https' || $proto eq 'http+unix';
91
92 my $query = $url->query;
93 my $options = {
94 backlog => $self->backlog,
95 stream_class => 'Mojo::IOLoop::Stream::HTTPServer'
96 };
97 $options->{$_} = $query->param($_) for qw(fd single_accept reuse);
98 if ($proto eq 'http+unix') { $options->{path} = $url->host }
99 else {
100 if ((my $host = $url->host) ne '*') { $options->{address} = $host }
101 if (my $port = $url->port) { $options->{port} = $port }
102 }
103 $options->{"tls_$_"} = $query->param($_) for qw(ca ciphers version);
104 /^(.*)_(cert|key)$/ and $options->{"tls_$2"}{$1} = $query->param($_)
105 for @{$query->names};
106 if (my $cert = $query->param('cert')) { $options->{'tls_cert'}{''} = $cert }
107 if (my $key = $query->param('key')) { $options->{'tls_key'}{''} = $key }
108 my $verify = $query->param('verify');
109 $options->{tls_verify} = hex $verify if defined $verify;
110 $options->{tls} = $proto eq 'https';
111
112 weaken $self;
113 push @{$self->acceptors}, $self->ioloop->server(
114 $options => sub {
115 my ($loop, $stream, $id) = @_;
116
117 my $c = $self->{connections}{$id} = {};
118 warn "-- Accept $id (@{[$stream->handle->peerhost]})\n" if DEBUG;
119 $stream->timeout($self->inactivity_timeout);
120 $stream->max_requests($self->max_requests);
121 weaken $stream->app($self)->{app};
122
123 $stream->on(close => sub { $self && $self->_remove($id) });
124 $stream->on(error =>
125 sub { $self && $self->app->log->error(pop) && $self->_remove($id) });
126 $stream->on(request => sub { $self->_request($id, pop) });
127 $stream->on(start => sub { $c->{tx} = pop->connection($id) });
128 $stream->on(timeout => sub { $self->_debug($id, 'Inactivity timeout') });
129 $stream->on(upgrade => sub { $self->_upgrade($id, pop) });
130 }
131 );
132
133 return if $self->silent;
134 $self->app->log->info(qq{Listening at "$url"});
135 $query->pairs([]);
136 $url->host('127.0.0.1') if $url->host eq '*';
137 say 'Server available at ', $options->{path} // $url;
138}
139
140sub _remove {
141 my ($self, $id) = @_;
142 $self->ioloop->remove($id);
143 delete $self->{connections}{$id};
144}
145
146sub _request {
147 my ($self, $id, $tx) = @_;
148 if (my $error = $tx->error) { $self->_debug($id, $error->{message}) }
149
150 weaken $self;
151 $tx->on(finish => sub { delete $self->{connections}{$id}{tx} });
152 $self->emit(request => $tx);
153}
154
155sub _upgrade {
156 my ($self, $id, $ws) = @_;
157
158 my $loop = $self->ioloop;
159 my $timeout = $loop->stream($id)->timeout;
160 my $stream = $loop->transition($id, 'Mojo::IOLoop::Stream::WebSocketServer');
161 $stream->timeout($timeout);
162
163 weaken $self;
164 $stream->on(timeout => sub { $self->_debug($id, 'Inactivity timeout') });
165 $stream->on(close => sub { $self && $self->_remove($id) });
166 $stream->on(
167 error => sub { $self && $self->app->log->error(pop) && $self->_remove($id) }
168 );
169
170 $self->{connections}{$id} = {tx => $ws};
171 $stream->process($ws);
172}
173
1741;
175
176=encoding utf8
177
178=head1 NAME
179
180Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
181
182=head1 SYNOPSIS
183
184 use Mojo::Server::Daemon;
185
186 my $daemon = Mojo::Server::Daemon->new(listen => ['http://*:8080']);
187 $daemon->unsubscribe('request')->on(request => sub {
188 my ($daemon, $tx) = @_;
189
190 # Request
191 my $method = $tx->req->method;
192 my $path = $tx->req->url->path;
193
194 # Response
195 $tx->res->code(200);
196 $tx->res->headers->content_type('text/plain');
197 $tx->res->body("$method request for $path!");
198
199 # Resume transaction
200 $tx->resume;
201 });
202 $daemon->run;
203
204=head1 DESCRIPTION
205
206L<Mojo::Server::Daemon> is a full featured, highly portable non-blocking I/O
207HTTP and WebSocket server, with IPv6, TLS, SNI, Comet (long polling), keep-alive
208and multiple event loop support.
209
210For better scalability (epoll, kqueue) and to provide non-blocking name
211resolution, SOCKS5 as well as TLS support, the optional modules L<EV> (4.0+),
212L<Net::DNS::Native> (0.15+), L<IO::Socket::Socks> (0.64+) and
213L<IO::Socket::SSL> (2.009+) will be used automatically if possible. Individual
214features can also be disabled with the C<MOJO_NO_NNR>, C<MOJO_NO_SOCKS> and
215C<MOJO_NO_TLS> environment variables.
216
217See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
218
219=head1 SIGNALS
220
221The L<Mojo::Server::Daemon> process can be controlled at runtime with the
222following signals.
223
224=head2 INT, TERM
225
226Shut down server immediately.
227
228=head1 EVENTS
229
230L<Mojo::Server::Daemon> inherits all events from L<Mojo::Server>.
231
232=head1 ATTRIBUTES
233
234L<Mojo::Server::Daemon> inherits all attributes from L<Mojo::Server> and
235implements the following new ones.
236
237=head2 acceptors
238
239 my $acceptors = $daemon->acceptors;
240 $daemon = $daemon->acceptors(['6be0c140ef00a389c5d039536b56d139']);
241
242Active acceptor ids.
243
244 # Check port
245 mu $port = $daemon->ioloop->acceptor($daemon->acceptors->[0])->port;
246
247=head2 backlog
248
249 my $backlog = $daemon->backlog;
250 $daemon = $daemon->backlog(128);
251
252Listen backlog size, defaults to C<SOMAXCONN>.
253
254=head2 inactivity_timeout
255
256 my $timeout = $daemon->inactivity_timeout;
257 $daemon = $daemon->inactivity_timeout(5);
258
259Maximum amount of time in seconds a connection can be inactive before getting
260closed, defaults to the value of the C<MOJO_INACTIVITY_TIMEOUT> environment
261variable or C<15>. Setting the value to C<0> will allow connections to be
262inactive indefinitely.
263
264=head2 ioloop
265
266 my $loop = $daemon->ioloop;
267 $daemon = $daemon->ioloop(Mojo::IOLoop->new);
268
269Event loop object to use for I/O operations, defaults to the global
270L<Mojo::IOLoop> singleton.
271
272=head2 listen
273
274 my $listen = $daemon->listen;
275 $daemon = $daemon->listen(['https://127.0.0.1:8080']);
276
277Array reference with one or more locations to listen on, defaults to the value
278of the C<MOJO_LISTEN> environment variable or C<http://*:3000> (shortcut for
279C<http://0.0.0.0:3000>).
280
281 # Listen on all IPv4 interfaces
282 $daemon->listen(['http://*:3000']);
283
284 # Listen on all IPv4 and IPv6 interfaces
285 $daemon->listen(['http://[::]:3000']);
286
287 # Listen on IPv6 interface
288 $daemon->listen(['http://[::1]:4000']);
289
290 # Listen on IPv4 and IPv6 interfaces
291 $daemon->listen(['http://127.0.0.1:3000', 'http://[::1]:3000']);
292
293 # Listen on UNIX domain socket "/tmp/myapp.sock" (percent encoded slash)
294 $daemon->listen(['http+unix://%2Ftmp%2Fmyapp.sock']);
295
296 # File descriptor, as used by systemd
297 $daemon->listen(['http://127.0.0.1?fd=3']);
298
299 # Allow multiple servers to use the same port (SO_REUSEPORT)
300 $daemon->listen(['http://*:8080?reuse=1']);
301
302 # Listen on two ports with HTTP and HTTPS at the same time
303 $daemon->listen(['http://*:3000', 'https://*:4000']);
304
305 # Use a custom certificate and key
306 $daemon->listen(['https://*:3000?cert=/x/server.crt&key=/y/server.key']);
307
308 # Domain specific certificates and keys (SNI)
309 $daemon->listen(
310 ['https://*:3000?example.com_cert=/x/my.crt&example.com_key=/y/my.key']);
311
312 # Or even a custom certificate authority
313 $daemon->listen(
314 ['https://*:3000?cert=/x/server.crt&key=/y/server.key&ca=/z/ca.crt']);
315
316These parameters are currently available:
317
318=over 2
319
320=item ca
321
322 ca=/etc/tls/ca.crt
323
324Path to TLS certificate authority file used to verify the peer certificate.
325
326=item cert
327
328 cert=/etc/tls/server.crt
329 mojolicious.org_cert=/etc/tls/mojo.crt
330
331Path to the TLS cert file, defaults to a built-in test certificate.
332
333=item ciphers
334
335 ciphers=AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH
336
337TLS cipher specification string. For more information about the format see
338L<https://www.openssl.org/docs/manmaster/apps/ciphers.html#CIPHER-STRINGS>.
339
340=item fd
341
342 fd=3
343
344File descriptor with an already prepared listen socket.
345
346=item key
347
348 key=/etc/tls/server.key
349 mojolicious.org_key=/etc/tls/mojo.key
350
351Path to the TLS key file, defaults to a built-in test key.
352
353=item reuse
354
355 reuse=1
356
357Allow multiple servers to use the same port with the C<SO_REUSEPORT> socket
358option.
359
360=item single_accept
361
362 single_accept=1
363
364Only accept one connection at a time.
365
366=item verify
367
368 verify=0x00
369
370TLS verification mode.
371
372=item version
373
374 version=TLSv1_2
375
376TLS protocol version.
377
378=back
379
380=head2 max_clients
381
382 my $max = $daemon->max_clients;
383 $daemon = $daemon->max_clients(100);
384
385Maximum number of accepted connections this server is allowed to handle
386concurrently, before stopping to accept new incoming connections, passed along
387to L<Mojo::IOLoop/"max_connections">.
388
389=head2 max_requests
390
391 my $max = $daemon->max_requests;
392 $daemon = $daemon->max_requests(250);
393
394Maximum number of keep-alive requests per connection, defaults to C<100>.
395
396=head2 silent
397
398 my $bool = $daemon->silent;
399 $daemon = $daemon->silent($bool);
400
401Disable console messages.
402
403=head1 METHODS
404
405L<Mojo::Server::Daemon> inherits all methods from L<Mojo::Server> and
406implements the following new ones.
407
408=head2 close_connections
409
410 $daemon->close_connections;
411
412Stop accepting new requests and close all connections after finising those
413currently being processed.
414
415=head2 ports
416
417 my $ports = $daemon->ports;
418
419Get all ports this server is currently listening on.
420
421 # All ports
422 say for @{$daemon->ports};
423
424=head2 run
425
426 $daemon->run;
427
428Run server and wait for L</"SIGNALS">.
429
430=head2 start
431
432 $daemon = $daemon->start;
433
434Start or resume accepting connections through L</"ioloop">.
435
436 # Listen on random port
437 my $port = $daemon->listen(['http://127.0.0.1'])->start->ports->[0];
438
439 # Run multiple web servers concurrently
440 my $daemon1 = Mojo::Server::Daemon->new(listen => ['http://*:3000'])->start;
441 my $daemon2 = Mojo::Server::Daemon->new(listen => ['http://*:4000'])->start;
442 Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
443
444=head2 stop
445
446 $daemon = $daemon->stop;
447
448Stop accepting connections through L</"ioloop">.
449
450=head1 DEBUGGING
451
452You can set the C<MOJO_SERVER_DEBUG> environment variable to get some advanced
453diagnostics information printed to C<STDERR>.
454
455 MOJO_SERVER_DEBUG=1
456
457=head1 SEE ALSO
458
459L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
460
461=cut
Note: See TracBrowser for help on using the repository browser.