File Coverage

blib/lib/Plack/Middleware/Recursive.pm
Criterion Covered Total %
statement 55 58 94.8
branch 8 10 80.0
condition 4 9 44.4
subroutine 15 16 93.7
pod 1 2 50.0
total 83 95 87.3


line stmt bran cond sub pod time code
1             package Plack::Middleware::Recursive;
2 4     4   76079 use strict;
  4         9  
  4         200  
3 4     4   20 use parent qw(Plack::Middleware);
  4         8  
  4         16  
4              
5 4     4   1698 use Try::Tiny;
  4         6599  
  4         184  
6 4     4   23 use Scalar::Util qw(blessed);
  4         7  
  4         1865  
7              
8 4     4   20 open my $null_io, "<", \"";
  4         7  
  4         24  
9              
10             sub call {
11 9     9 1 21 my($self, $env) = @_;
12              
13 9         21 $env->{'plack.recursive.include'} = $self->recurse_callback($env, 1);
14              
15             my $res = try {
16 9     9   394 $self->app->($env);
17             } catch {
18 4 100 66 4   79 if (blessed $_ && $_->isa('Plack::Recursive::ForwardRequest')) {
19 3         6 return $self->recurse_callback($env)->($_->path);
20             } else {
21 1         5 die $_; # rethrow
22             }
23 9         65 };
24              
25 8 100       2276 return $res if ref $res eq 'ARRAY';
26              
27             return sub {
28 4     4   6 my $respond = shift;
29              
30 4         7 my $writer;
31             try {
32 4         132 $res->(sub { return $writer = $respond->(@_) });
  3         684  
33             } catch {
34 1 50 33     36 if (!$writer && blessed $_ && $_->isa('Plack::Recursive::ForwardRequest')) {
      33        
35 1         5 $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         19 };
41 4         27 };
42             }
43              
44             sub recurse_callback {
45 13     13 0 24 my($self, $env, $include) = @_;
46              
47 13         23 my $old_path_info = $env->{PATH_INFO};
48              
49             return sub {
50 6     6   24 my $new_path_info = shift;
51 6         25 my($path, $query) = split /\?/, $new_path_info, 2;
52              
53 6         24 Scalar::Util::weaken($env);
54              
55 6         13 $env->{PATH_INFO} = $path;
56 6         10 $env->{QUERY_STRING} = $query;
57 6         9 $env->{REQUEST_METHOD} = 'GET';
58 6         11 $env->{CONTENT_LENGTH} = 0;
59 6         9 $env->{CONTENT_TYPE} = '';
60 6         23 $env->{'psgi.input'} = $null_io;
61 6         8 push @{$env->{'plack.recursive.old_path_info'}}, $old_path_info;
  6         15  
62              
63 6 100       39 $include ? $self->app->($env) : $self->call($env);
64 13         89 };
65             }
66              
67             package Plack::Recursive::ForwardRequest;
68 4     4   26 use overload q("") => \&as_string, fallback => 1;
  4         8  
  4         23  
69              
70             sub new {
71 4     4   8 my($class, $path) = @_;
72 4         24 bless { path => $path }, $class;
73             }
74              
75 4     4   46 sub path { $_[0]->{path} }
76              
77             sub throw {
78 4     4   57 my($class, @args) = @_;
79 4         10 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__