[Catalyst-commits] r14552 - trunk/examples/CatalystAdvent/root/2014
jnapiorkowski at dev.catalyst.perl.org
jnapiorkowski at dev.catalyst.perl.org
Thu Dec 18 17:29:52 GMT 2014
Author: jnapiorkowski
Date: 2014-12-18 17:29:52 +0000 (Thu, 18 Dec 2014)
New Revision: 14552
Added:
trunk/examples/CatalystAdvent/root/2014/19.pod
Log:
19
Added: trunk/examples/CatalystAdvent/root/2014/19.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2014/19.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2014/19.pod 2014-12-18 17:29:52 UTC (rev 14552)
@@ -0,0 +1,86 @@
+=head1 Another Take on redispatching
+
+=head1 Overview
+
+In a previous advent story we reviewed a recipe for adding a redispatch method
+to the global L<Catalyst> object. This allows one to replace the current
+request with a new request to a different public path (URL). Presented is a
+different approach to the same problem, but instead of hacking Catalyst internals
+it creates a new request and dispatches over PSGI. This leads to a higher level
+of isolation as well as the ability to construct a full L<HTTP::Request> and
+customize it as need (for example make a POST request, or sets the query parameters.
+
+=head1 The redispatch_to methods
+
+Here's the method on your application class:
+
+ use warnings;
+ use strict;
+
+ package MyApp;
+
+ use Catalyst;
+ use HTTP::Message::PSGI ();
+
+ sub redispatch_to {
+ my $c = shift;
+ my $env = HTTP::Message::PSGI::req_to_psgi(shift);
+ our $app ||= $c->psgi_app;
+
+ $c->res->from_psgi_response( $app->($env) );
+ }
+
+ MyApp->setup;
+
+This method expects an L<HTTP::Request> as its first argument. We then convert
+that request to a L<PSGI> style C<$env> hash and invoke it on the application
+coderef. The response is sent directly to the initiating response.
+
+This would work fine with streaming and delayed style response, FWIW. Here's an
+example controller using it:
+
+ use warnings;
+ use strict;
+
+ package MyApp::Controller::Example;
+
+ use base 'Catalyst::Controller';
+ use HTTP::Request::Common;
+
+ sub base :Path('') {
+ my ($self, $c) = @_;
+ $c->redispatch_to(GET $c->uri_for($self->action_for('target')));
+ }
+
+ sub target :Path('target') {
+ my ($self, $c) = @_;
+ $c->response->content_type('text/plain');
+ $c->response->body("This is the target action");
+ }
+
+ __PACKAGE__->meta->make_immutable;
+
+And a test case that shows how it works:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp';
+
+ my $res = request "/example";
+ is $res->code, 200, 'OK';
+ is $res->content, 'This is the target action', 'correct body';
+
+ done_testing;
+
+You might note this would allow one to redispatch to essentially ANY public URL
+include ones not part of your controlled website. This may be construed as a bug
+or as a feature.
+
+=head1 Caveats
+
+Same as in the last advent article :)
+
+=head1 Author
+
+John Napiorkowski
+
+=cut
More information about the Catalyst-commits
mailing list