File Coverage

blib/lib/Plack/Handler/Net/Async/HTTP/Server.pm
Criterion Covered Total %
statement 11 54 20.3
branch 0 22 0.0
condition 0 5 0.0
subroutine 4 7 57.1
pod 2 2 100.0
total 17 90 18.8


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2013-2023 -- leonerd@leonerd.org.uk
5              
6             package Plack::Handler::Net::Async::HTTP::Server 0.14;
7              
8 1     1   517 use v5.14;
  1         3  
9 1     1   5 use warnings;
  1         20  
  1         32  
10              
11 1     1   472 use Net::Async::HTTP::Server::PSGI;
  1         2  
  1         49  
12 1     1   851 use IO::Async::Loop;
  1         10382  
  1         719  
13              
14             =head1 NAME
15              
16             C - HTTP handler for Plack using L
17              
18             =head1 SYNOPSIS
19              
20             use Plack::Handler::Net::Async::HTTP::Server;
21              
22             my $handler = Plack::Handler::Net::Async::HTTP::Server->new(
23             listen => [ ":8080" ],
24             );
25              
26             sub psgi_app { ... }
27              
28             $handler->run( \&psgi_app );
29              
30             =head1 DESCRIPTION
31              
32             This module allows L to run a L application as a standalone
33             HTTP daemon under L, by using L.
34              
35             plackup -s Net::Async::HTTP::Server --listen ":8080" application.psgi
36              
37             This is internally implemented using L;
38             further information on environment etc.. is documented there.
39              
40             If L is available, this handler supports accepting connections
41             via C
42              
43             plackup -s Net::Async::HTTP::Server --ssl ...
44              
45             Or per-listen argument by appending C<:SSL>, as
46              
47             plackup -s Net::Async::HTTP::Server --listen ":8443:SSL" ...
48              
49             Any other options whose names start C will be passed on to the SSL
50             listen method.
51              
52             =cut
53              
54             =head1 METHODS
55              
56             =cut
57              
58             =head2 $handler = Plack::Handler::Net::Async::HTTP::Server->new( %args )
59              
60             Returns a new instance of a C
61             object. Takes the following named arguments:
62              
63             =over 4
64              
65             =item listen => ARRAY of STRING
66              
67             Reference to an array containing listen string specifications. Each string
68             gives a port number and optional hostname, given as C<:port> or C.
69              
70             =item server_ready => CODE
71              
72             Reference to code to invoke when the server is set up and listening, ready to
73             accept connections. It is invoked with a HASH reference containing the
74             following details:
75              
76             $server_ready->( {
77             host => HOST,
78             port => SERVICE,
79             server_software => NAME,
80             } )
81              
82             =item socket => STRING
83              
84             Gives a UNIX socket path to listen on, instead of a TCP socket.
85              
86             =item queuesize => INT
87              
88             Optional. If provided, sets the C queue size for creating listening
89             sockets. If missing, a default of 10 is used.
90              
91             =back
92              
93             =cut
94              
95             sub new
96             {
97 0     0 1   my $class = shift;
98 0           my %opts = @_;
99              
100 0           delete $opts{host};
101 0           delete $opts{port};
102 0           delete $opts{socket};
103              
104             my $self = bless {
105 0           map { $_ => delete $opts{$_} } qw( listen server_ready queuesize ),
  0            
106             }, $class;
107              
108             # Grab all of the SSL options
109 0 0         $self->{ssl} = 1 if exists $opts{ssl}; delete $opts{ssl};
  0            
110 0           $self->{$_} = delete $opts{$_} for grep m/^ssl_/, keys %opts;
111              
112 0 0         keys %opts and die "Unrecognised keys " . join( ", ", sort keys %opts );
113              
114 0           return $self;
115             }
116              
117             =head2 $handler->run( $psgi_app )
118              
119             Creates the HTTP-listening socket or sockets, and runs the given PSGI
120             application for received requests.
121              
122             =cut
123              
124             sub run
125             {
126 0     0 1   my $self = shift;
127 0           my ( $app ) = @_;
128              
129 0           my $loop = IO::Async::Loop->new;
130 0   0       my $queuesize = $self->{queuesize} || 10;
131              
132 0           foreach my $listen ( @{ $self->{listen} } ) {
  0            
133 0           my $httpserver = Net::Async::HTTP::Server::PSGI->new(
134             app => $app,
135             );
136              
137 0           $loop->add( $httpserver );
138              
139             # IPv6 addresses contain colons. They'll be wrapped in [] brackets
140 0           my $host;
141             my $path;
142              
143 0 0         if( $listen =~ s/^\[([0-9a-f:]+)\]://i ) {
    0          
    0          
144 0           $host = $1;
145             }
146             elsif( $listen =~ s/^([^:]+?):// ) {
147 0           $host = $1;
148             }
149             elsif( $listen =~ s/^:// ) {
150             # OK
151             }
152             else {
153 0           $path = $listen;
154             }
155              
156 0 0         if( defined $path ) {
157 0           require IO::Socket::UNIX;
158              
159 0 0         unlink $path if -e $path;
160              
161 0 0         my $socket = IO::Socket::UNIX->new(
162             Local => $path,
163             Listen => $queuesize,
164             ) or die "Cannot listen on $path - $!";
165              
166 0           $httpserver->configure( handle => $socket );
167             }
168             else {
169 0           my ( $service, $ssl ) = split m/:/, $listen;
170 0   0       $ssl ||= $self->{ssl};
171              
172 0           my %SSL_args;
173 0 0         if( $ssl ) {
174 0           require IO::Async::SSL;
175 0           %SSL_args = (
176             extensions => [qw( SSL )],
177             );
178              
179 0           foreach my $key ( grep m/^ssl_/, keys %$self ) {
180 0           my $val = $self->{$key};
181             # IO::Async::Listener extension wants uppercase "SSL"
182 0           $key =~ s/^ssl/SSL/;
183              
184 0           $SSL_args{$key} = $val;
185             };
186             }
187              
188             $httpserver->listen(
189             host => $host,
190             service => $service,
191             socktype => "stream",
192             queuesize => $queuesize,
193              
194             %SSL_args,
195              
196             on_notifier => sub {
197             $self->{server_ready}->( {
198             host => $host,
199             port => $service,
200             proto => $ssl ? "https" : "http",
201             server_software => ref $self,
202 0 0   0     } ) if $self->{server_ready};
    0          
203             },
204 0           )->get;
205             }
206             }
207              
208 0           $loop->run;
209             }
210              
211             =head1 SEE ALSO
212              
213             =over 4
214              
215             =item *
216              
217             L - serve HTTP with L
218              
219             =item *
220              
221             L - Perl Superglue for Web frameworks and Web Servers (PSGI toolkit)
222              
223             =back
224              
225             =head1 AUTHOR
226              
227             Paul Evans
228              
229             =cut
230              
231             0x55AA;