File Coverage

blib/lib/Plack/App/Hostname.pm
Criterion Covered Total %
statement 52 53 98.1
branch 9 12 75.0
condition 10 14 71.4
subroutine 10 10 100.0
pod 5 5 100.0
total 86 94 91.4


line stmt bran cond sub pod time code
1 1     1   383 use 5.006; use strict; use warnings;
  1     1   3  
  1     1   4  
  1         2  
  1         15  
  1         3  
  1         1  
  1         64  
2              
3             package Plack::App::Hostname;
4              
5             our $VERSION = '1.002';
6              
7 1     1   418 BEGIN { require Plack::Component; our @ISA = 'Plack::Component' }
  1         11496  
8 1     1   355 use Plack::Util::Accessor qw( custom_matcher missing_header_app default_app );
  1         222  
  1         6  
9              
10             sub map_hosts_to {
11 5     5 1 2043 my $self = shift;
12 5         6 my $app = shift;
13 5         12 @{ $self->{'_app_for_host'} }{ map { lc } @_ } = ( $app ) x @_;
  5         42  
  10         21  
14 5         11 $self->{'_num_wildcards'} += grep { /\A\*\*\./ } @_;
  10         25  
15 5         11 return $self;
16             }
17              
18             sub unmap_host {
19 2     2 1 1211 my $self = shift;
20 2         5 delete @{ $self->{'_app_for_host'} }{ map { lc } @_ };
  2         9  
  4         10  
21 2         5 $self->{'_num_wildcards'} -= grep { /\A\*\*\./ } @_;
  4         12  
22 2         4 return $self;
23             }
24              
25             sub unmap_app {
26 1     1 1 581 my $self = shift;
27 1   50     12 my $map = $self->{'_app_for_host'} ||= {};
28 1         7 while ( my ( $host, $host_app ) = each %$map ) {
29 6 50       11 next if not grep { $host_app == $_ } @_;
  6         16  
30 6         7 delete $map->{ $host };
31 6 50       21 --$self->{'_num_wildcards'} if $host =~ /\A\*\*\./;
32             }
33 1         2 return $self;
34             }
35              
36             sub matching {
37 21     21 1 32 my $self = shift;
38 21         33 my $host = lc $_[0];
39              
40 21         28 my $map = $self->{'_app_for_host'};
41              
42 21   66     84 return $_ for $map->{ $host } || ();
43              
44 11 100       26 if ( $self->{'_num_wildcards'} ) {
45 4         14 my @part = split /\./, $host, 16;
46 4         9 for my $pattern ( map { shift @part; join '.', '**', @part } 1 .. $#part ) {
  22         24  
  22         49  
47 19   66     48 return $_ for $map->{ $pattern } || ();
48             }
49             }
50              
51 9 50       23 return undef unless my $cb = $self->custom_matcher;
52              
53 0         0 return scalar $cb->() for $host;
54             }
55              
56             our $sadtrombone = [
57             400,
58             [qw( Content-Type text/html )],
59             ['Bad Request

Bad Request

Unknown host or domain'],

60             ];
61              
62             sub call {
63 24     24 1 44378 my $self = shift;
64 24         42 my ( $env ) = @_;
65              
66 24         34 my $host = $env->{'HTTP_HOST'};
67              
68 24 100 100     111 my $app = defined $host
69             ? ( $host =~ s/:$env->{'SERVER_PORT'}\z//, $self->matching( $host ) || $self->default_app )
70             : $self->missing_header_app;
71              
72 24 100 66     170 return 'CODE' eq ref $app ? &$app : $app || $sadtrombone;
73             }
74              
75             1;