File Coverage

blib/lib/Plack/Middleware/Recursive.pm
Criterion Covered Total %
statement 52 55 94.5
branch 8 10 80.0
condition 4 9 44.4
subroutine 14 15 93.3
pod 1 2 50.0
total 79 91 86.8


line stmt bran cond sub pod time code
1             package Plack::Middleware::Recursive;
2 4     4   104496 use strict;
  4         7  
  4         166  
3 4     4   24 use parent qw(Plack::Middleware);
  4         8  
  4         21  
4              
5 4     4   1624 use Try::Tiny;
  4         6612  
  4         225  
6 4     4   21 use Scalar::Util qw(blessed);
  4         4  
  4         1772  
7              
8             open my $null_io, "<", \"";
9              
10             sub call {
11 9     9 1 16 my($self, $env) = @_;
12              
13 9         22 $env->{'plack.recursive.include'} = $self->recurse_callback($env, 1);
14              
15             my $res = try {
16 9     9   355 $self->app->($env);
17             } catch {
18 4 100 66 4   64 if (blessed $_ && $_->isa('Plack::Recursive::ForwardRequest')) {
19 3         7 return $self->recurse_callback($env)->($_->path);
20             } else {
21 1         10 die $_; # rethrow
22             }
23 9         60 };
24              
25 8 100       2358 return $res if ref $res eq 'ARRAY';
26              
27             return sub {
28 4     4   5 my $respond = shift;
29              
30 4         5 my $writer;
31             try {
32 4         103 $res->(sub { return $writer = $respond->(@_) });
  3         688  
33             } catch {
34 1 50 33     26 if (!$writer && blessed $_ && $_->isa('Plack::Recursive::ForwardRequest')) {
      33        
35 1         3 $res = $self->recurse_callback($env)->($_->path);
36 1 50       7 return ref $res eq 'CODE' ? $res->($respond) : $respond->($res);
37             } else {
38 0         0 die $_;
39             }
40 4         21 };
41 4         29 };
42             }
43              
44             sub recurse_callback {
45 13     13 0 31 my($self, $env, $include) = @_;
46              
47 13         19 my $old_path_info = $env->{PATH_INFO};
48              
49             return sub {
50 6     6   16 my $new_path_info = shift;
51 6         20 my($path, $query) = split /\?/, $new_path_info, 2;
52              
53 6         35 Scalar::Util::weaken($env);
54              
55 6         15 $env->{PATH_INFO} = $path;
56 6         11 $env->{QUERY_STRING} = $query;
57 6         10 $env->{REQUEST_METHOD} = 'GET';
58 6         7 $env->{CONTENT_LENGTH} = 0;
59 6         19 $env->{CONTENT_TYPE} = '';
60 6         22 $env->{'psgi.input'} = $null_io;
61 6         8 push @{$env->{'plack.recursive.old_path_info'}}, $old_path_info;
  6         15  
62              
63 6 100       21 $include ? $self->app->($env) : $self->call($env);
64 13         76 };
65             }
66              
67             package Plack::Recursive::ForwardRequest;
68 4     4   23 use overload q("") => \&as_string, fallback => 1;
  4         5  
  4         47  
69              
70             sub new {
71 4     4   5 my($class, $path) = @_;
72 4         23 bless { path => $path }, $class;
73             }
74              
75 4     4   57 sub path { $_[0]->{path} }
76              
77             sub throw {
78 4     4   37 my($class, @args) = @_;
79 4         13 die $class->new(@args);
80             }
81              
82             sub as_string {
83 0     0     my $self = shift;
84 0           return "Forwarding to $self->{path}: Your application should be wrapped with Plack::Middleware::Recursive.";
85             }
86              
87             package Plack::Middleware::Recursive;
88              
89             1;
90              
91             __END__