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