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