File Coverage

blib/lib/App/HTTPThis.pm
Criterion Covered Total %
statement 21 67 31.3
branch 0 32 0.0
condition 0 10 0.0
subroutine 7 11 63.6
pod 2 2 100.0
total 30 122 24.5


line stmt bran cond sub pod time code
1             package App::HTTPThis;
2              
3             # ABSTRACT: Export the current directory over HTTP
4              
5 1     1   121737 use strict;
  1         2  
  1         48  
6 1     1   8 use warnings;
  1         2  
  1         82  
7 1     1   524 use Plack::App::DirectoryIndex;
  1         175685  
  1         55  
8 1     1   771 use Plack::Runner;
  1         7239  
  1         54  
9 1     1   915 use Getopt::Long;
  1         16624  
  1         6  
10 1     1   861 use Pod::Usage;
  1         62322  
  1         113  
11 1     1   546 use Config::Tiny;
  1         1104  
  1         592  
12              
13             our $VERSION = '0.11.1';
14              
15             =head1 NAME
16              
17             App::HTTPThis - A simple local web server.
18              
19             =head1 SYNOPSIS
20              
21             # Not to be used directly, see http_this command
22              
23             =head1 DESCRIPTION
24              
25             This class implements all the logic of the L command.
26              
27             Actually, this is just a very thin wrapper around
28             L, that is where the magic really is.
29              
30             =head1 METHODS
31              
32             =head2 new
33              
34             Creates a new App::HTTPThis object, parsing the command line arguments
35             into object attribute values.
36              
37             =cut
38              
39             sub new {
40 0     0 1   my $class = shift;
41 0           my $self = bless {port => 7007, root => '.'}, $class;
42              
43 0           my $default_config_file = '.http_thisrc';
44              
45 0   0       my $config_file = $self->{config} || $ENV{HTTP_THIS_CONFIG};
46              
47             # There are apparently OSes where $ENV{HOME} is undefined
48 0           for my $dir ('.', $ENV{HOME}) {
49 0 0         next unless defined $dir;
50 0 0 0       if (!$config_file && -f "$dir/$default_config_file") {
51 0           $config_file = "$dir/$default_config_file";
52 0           last;
53             }
54             }
55              
56 0 0         if ($config_file) {
57 0 0         my $config = Config::Tiny->read($config_file)
58             or die "FATAL: failed to read config file '$config_file'\n";
59 0           for my $key (qw(port name autoindex pretty)) {
60 0 0         $self->{$key} = $config->{_}->{$key} if $config->{_}->{$key};
61             }
62 0           delete $self->{config};
63             }
64              
65             GetOptions(
66 0 0         $self, "help", "man", "config=s", "host=s", "port=i", "name=s", "autoindex!", "pretty!"
67             ) || pod2usage(2);
68 0 0         pod2usage(1) if $self->{help};
69 0 0         pod2usage(-verbose => 2) if $self->{man};
70              
71 0 0         if (@ARGV > 1) {
    0          
72 0           pod2usage("$0: Too many roots, only single root supported");
73             }
74             elsif (@ARGV) {
75 0           $self->{root} = shift @ARGV;
76             }
77              
78 0           return $self;
79             }
80              
81             =head2 run
82              
83             Start the HTTP server.
84              
85             =cut
86              
87             sub run {
88 0     0 1   my ($self) = @_;
89              
90 0           my $runner = Plack::Runner->new;
91             $runner->parse_options(
92             ($self->{host} ? ('--host' => $self->{host}) : ()),
93             '--port' => $self->{port},
94             '--env' => 'production',
95 0     0     '--server_ready' => sub { $self->_server_ready(@_) },
96 0 0         '--autoindex' => 0,
97             '--pretty' => 0,
98             );
99              
100             my $app_config = {
101             root => $self->{root},
102             pretty => $self->{pretty},
103 0           dir_index => '',
104             };
105 0 0         $app_config->{dir_index} = 'index.html' if $self->{autoindex};
106              
107 0           eval {
108 0           $runner->run(Plack::App::DirectoryIndex->new( $app_config )->to_app);
109             };
110 0 0         if (my $e = $@) {
111 0 0         die "FATAL: port $self->{port} is already in use, try another one\n"
112             if $e =~ /failed to listen to port/;
113 0           die "FATAL: internal error - $e\n";
114             }
115             }
116              
117             sub _server_ready {
118 0     0     my ($self, $args) = @_;
119              
120 0   0       my $host = $args->{host} || '127.0.0.1';
121 0   0       my $proto = $args->{proto} || 'http';
122 0           my $port = $args->{port};
123              
124 0           print "Exporting '$self->{root}', available at:\n";
125 0           print " $proto://$host:$port/\n";
126              
127 0 0         return unless my $name = $self->{name};
128              
129 0           eval {
130 0           require Net::Rendezvous::Publish;
131 0           Net::Rendezvous::Publish->new->publish(
132             name => $name,
133             type => '_http._tcp',
134             port => $port,
135             domain => 'local',
136             );
137             };
138 0 0         if ($@) {
139 0           print "\nWARNING: your server will not be published over Bonjour\n";
140 0           print " Install one of the Net::Rendezvous::Publish::Backend\n";
141 0           print " modules from CPAN\n"
142             }
143             }
144              
145             1;
146              
147              
148              
149             =head1 SEE ALSO
150              
151             L, L, L, and L.
152              
153              
154             =head1 THANKS
155              
156             And the Oscar goes to: Tatsuhiko Miyagawa.
157              
158             For L, L and many many others.
159