File Coverage

blib/lib/Plack/App/URLMap.pm
Criterion Covered Total %
statement 58 62 93.5
branch 14 18 77.7
condition 12 15 80.0
subroutine 10 11 90.9
pod 4 4 100.0
total 98 110 89.0


line stmt bran cond sub pod time code
1             package Plack::App::URLMap;
2 34     34   280700 use strict;
  34         116  
  34         1025  
3 34     34   173 use warnings;
  34         63  
  34         1584  
4 34     34   2174 use parent qw(Plack::Component);
  34         1258  
  34         165  
5 34 50   34   2336 use constant DEBUG => $ENV{PLACK_URLMAP_DEBUG} ? 1 : 0;
  34         192  
  34         1909  
6              
7 34     34   221 use Carp ();
  34         67  
  34         15154  
8              
9 0     0 1 0 sub mount { shift->map(@_) }
10              
11             sub map {
12 22     22 1 75 my $self = shift;
13 22         50 my($location, $app) = @_;
14              
15 22         32 my $host;
16 22 100       75 if ($location =~ m!^https?://(.*?)(/.*)!) {
17 3         9 $host = $1;
18 3         11 $location = $2;
19             }
20              
21 22 50       99 if ($location !~ m!^/!) {
22 0         0 Carp::croak("Paths need to start with /");
23             }
24 22         71 $location =~ s!/$!!;
25              
26 22         34 push @{$self->{_mapping}}, [ $host, $location, qr/^\Q$location\E/, $app ];
  22         622  
27             }
28              
29             sub prepare_app {
30 20     20 1 37 my $self = shift;
31             # sort by path length
32             $self->{_sorted_mapping} = [
33 58         95 map { [ @{$_}[2..5] ] }
  58         191  
34 50 50       134 sort { $b->[0] <=> $a->[0] || $b->[1] <=> $a->[1] }
35 20 100       41 map { [ ($_->[0] ? length $_->[0] : 0), length($_->[1]), @$_ ] } @{$self->{_mapping}},
  58         257  
  20         56  
36             ];
37             }
38              
39             sub call {
40 30     30 1 69 my ($self, $env) = @_;
41              
42 30         73 my $path_info = $env->{PATH_INFO};
43 30         55 my $script_name = $env->{SCRIPT_NAME};
44              
45 30         48 my($http_host, $server_name) = @{$env}{qw( HTTP_HOST SERVER_NAME )};
  30         70  
46              
47 30 50 33     174 if ($http_host and my $port = $env->{SERVER_PORT}) {
48 30         203 $http_host =~ s/:$port$//;
49             }
50              
51 30         69 for my $map (@{ $self->{_sorted_mapping} }) {
  30         90  
52 66         164 my($host, $location, $location_re, $app) = @$map;
53 66         97 my $path = $path_info; # copy
54 34     34   278 no warnings 'uninitialized';
  34         129  
  34         9741  
55 66         87 DEBUG && warn "Matching request (Host=$http_host Path=$path) and the map (Host=$host Path=$location)\n";
56 66 100 100     238 next unless not defined $host or
      66        
57             $http_host eq $host or
58             $server_name eq $host;
59 51 100 100     307 next unless $location eq '' or $path =~ s!$location_re!!;
60 33 100 100     157 next unless $path eq '' or $path =~ m!^/!;
61 30         46 DEBUG && warn "-> Matched!\n";
62              
63 30         64 my $orig_path_info = $env->{PATH_INFO};
64 30         50 my $orig_script_name = $env->{SCRIPT_NAME};
65              
66 30         50 $env->{PATH_INFO} = $path;
67 30         63 $env->{SCRIPT_NAME} = $script_name . $location;
68             return $self->response_cb($app->($env), sub {
69 30     30   62 $env->{PATH_INFO} = $orig_path_info;
70 30         73 $env->{SCRIPT_NAME} = $orig_script_name;
71 30         119 });
72             }
73              
74 0           DEBUG && warn "All matching failed.\n";
75              
76 0           return [404, [ 'Content-Type' => 'text/plain' ], [ "Not Found" ]];
77             }
78              
79             1;
80              
81             __END__