/usr/share/perl5/Plack/Middleware.pm is in libplack-perl 1.0030-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | package Plack::Middleware;
use strict;
use warnings;
use Carp ();
use parent qw(Plack::Component);
use Plack::Util;
use Plack::Util::Accessor qw( app );
sub wrap {
my($self, $app, @args) = @_;
if (ref $self) {
$self->{app} = $app;
} else {
$self = $self->new({ app => $app, @args });
}
return $self->to_app;
}
1;
__END__
=head1 NAME
Plack::Middleware - Base class for easy-to-use PSGI middleware
=head1 SYNOPSIS
package Plack::Middleware::Foo;
use parent qw( Plack::Middleware );
sub call {
my($self, $env) = @_;
# Do something with $env
# $self->app is the original app
my $res = $self->app->($env);
# Do something with $res
return $res;
}
# then in app.psgi
use Plack::Builder;
my $app = sub { ... } # as usual
builder {
enable "Plack::Middleware::Foo";
enable "Plack::Middleware::Bar", %options;
$app;
};
=head1 DESCRIPTION
Plack::Middleware is a utility base class to write PSGI
middleware. All you have to do is to inherit from Plack::Middleware
and then implement the callback C<call> method (or the C<to_app> method
that would return the PSGI code reference) to do the actual work. You
can use C<< $self->app >> to call the original (wrapped) application.
Your middleware object is created at the PSGI application compile time
and is persistent during the web server life cycle (unless it is a
non-persistent environment such as CGI), so you should never set or
cache per-request data like C<$env> in your middleware object. See
also L<Plack::Component/"OBJECT LIFECYCLE">.
See L<Plack::Builder> how to actually enable middleware in your
I<.psgi> application file using the DSL. If you do not like our
builder DSL, you can also use the C<wrap> method to wrap your application
with a middleware:
use Plack::Middleware::Foo;
my $app = sub { ... };
$app = Plack::Middleware::Foo->wrap($app, %options);
$app = Plack::Middleware::Bar->wrap($app, %options);
=head1 RESPONSE CALLBACK
The typical middleware is written like this:
package Plack::Middleware::Something;
use parent qw(Plack::Middleware);
sub call {
my($self, $env) = @_;
# pre-processing $env
my $res = $self->app->($env);
# post-processing $res
return $res;
}
The tricky thing about post-processing the response is that it could
either be an immediate 3 element array ref, or a code reference that
implements the delayed (streaming) interface.
Dealing with these two types of response in each piece of middleware
is pointless, so you're recommended to use the C<response_cb> wrapper
function in L<Plack::Util> when implementing a post processing
middleware.
my $res = $app->($env);
Plack::Util::response_cb($res, sub {
my $res = shift;
# do something with $res;
});
The callback function gets a PSGI response as a 3 element array
reference, and you can update the reference to implement the post-processing.
package Plack::Middleware::Always500;
use parent qw(Plack::Middleware);
use Plack::Util;
sub call {
my($self, $env) = @_;
my $res = $self->app->($env);
Plack::Util::response_cb($res, sub {
my $res = shift;
$res->[0] = 500;
return;
});
}
In this example, the callback gets the C<$res> and updates its first
element (status code) to 500. Using C<response_cb> makes sure that
this works with the delayed response too.
You're not required (and not recommended either) to return a new array
reference - they will be simply ignored. You're suggested to
explicitly return, unless you fiddle with the content filter callback
(see below).
Similarly, note that you have to keep the C<$res> reference when you
swap the entire response.
Plack::Util::response_cb($res, sub {
my $res = shift;
$res = [ $new_status, $new_headers, $new_body ]; # THIS DOES NOT WORK
return;
});
This does not work, since assigning a new anonymous array to C<$res>
doesn't update the original PSGI response value. You should instead
do:
Plack::Util::response_cb($res, sub {
my $res = shift;
@$res = ($new_status, $new_headers, $new_body); # THIS WORKS
return;
});
The third element of the PSGI response array ref is a body, and it could
be either an arrayref or L<IO::Handle>-ish object. The application could
also make use of the C<$writer> object if C<psgi.streaming> is in
effect. Dealing with these variants is again really painful, and
C<response_cb> can take care of that too, by allowing you to return a
content filter as a code reference.
# replace all "Foo" in content body with "Bar"
Plack::Util::response_cb($res, sub {
my $res = shift;
return sub {
my $chunk = shift;
return unless defined $chunk;
$chunk =~ s/Foo/Bar/g;
return $chunk;
}
});
The callback takes one argument C<$chunk> and your callback is
expected to return the updated chunk. If the given C<$chunk> is undef,
it means the stream has reached the end, so your callback should also
return undef, or return the final chunk and return undef when called
next time.
=head1 SEE ALSO
L<Plack> L<Plack::Builder> L<Plack::Component>
=cut
|