From: Rafael Kitover Date: Tue, 1 Jul 2008 02:16:38 +0000 (+0000) Subject: Converted C::P::CGIBin to C::C::CGIBin, added regex env key support X-Git-Tag: 0.030~65 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Controller-WrapCGI.git;a=commitdiff_plain;h=21a20b7e40ead509ca832db9099a4b76d3d61cd4 Converted C::P::CGIBin to C::C::CGIBin, added regex env key support --- diff --git a/Changes b/Changes index 5cddccb..6e5e549 100644 --- a/Changes +++ b/Changes @@ -2,3 +2,6 @@ Revision history for Catalyst-Controller-WrapCGI 0.001 2008-06-28 15:28:46 First complete dist. + +0.002 2008-06-30 16:00:44 + Converted C::P::CGIBin to C::C::CGIBin diff --git a/MANIFEST b/MANIFEST index 1652858..6c8cfe5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,10 +1,32 @@ Changes -MANIFEST -Makefile.PL -README +inc/Module/AutoInstall.pm +inc/Module/Install.pm +inc/Module/Install/AutoInstall.pm +inc/Module/Install/Base.pm +inc/Module/Install/Can.pm +inc/Module/Install/Fetch.pm +inc/Module/Install/Include.pm +inc/Module/Install/Makefile.pm +inc/Module/Install/Metadata.pm +inc/Module/Install/Win32.pm +inc/Module/Install/WriteAll.pm +lib/Catalyst/Controller/CGIBin.pm lib/Catalyst/Controller/WrapCGI.pm -lib/Catalyst/Plugin/CGIBin.pm lib/CatalystX/GlobalContext.pm +Makefile.PL +MANIFEST +META.yml +README t/00-load.t +t/boilerplate.t +t/cgibin.t +t/global-context.t +t/lib/TestApp.pm +t/lib/TestApp/Controller/Root.pm +t/lib/TestCGIBin.pm +t/lib/TestCGIBin/Controller/CGIHandler.pm +t/lib/TestCGIBin/root/cgi-bin/test.pl +t/lib/TestCGIBin/root/cgi-bin/test.sh t/pod-coverage.t t/pod.t +t/wrap-cgi.t diff --git a/META.yml b/META.yml index 8c7d190..5cfa7d4 100644 --- a/META.yml +++ b/META.yml @@ -22,4 +22,4 @@ requires: Task::Weaken: 0 URI: 0 parent: 0 -version: 0.001 +version: 0.002 diff --git a/README b/README index 8a33885..b5d1a5f 100644 --- a/README +++ b/README @@ -16,7 +16,7 @@ SUPPORT AND DOCUMENTATION After installing, you can find documentation for these modules with the perldoc command. - perldoc Catalyst::Plugin::CGIBin + perldoc Catalyst::Controller::CGIBin perldoc Catalyst::Controller::WrapCGI perldoc CatalystX::GlobalContext diff --git a/lib/Catalyst/Controller/CGIBin.pm b/lib/Catalyst/Controller/CGIBin.pm new file mode 100644 index 0000000..e3f6437 --- /dev/null +++ b/lib/Catalyst/Controller/CGIBin.pm @@ -0,0 +1,192 @@ +package Catalyst::Controller::CGIBin; + +use strict; +use warnings; + +use Class::C3; +use URI::Escape; +use File::Slurp 'slurp'; +use File::Find::Rule (); +use Cwd; +use Catalyst::Exception (); +use File::Spec::Functions 'splitdir'; + +use parent 'Catalyst::Controller::WrapCGI'; + +=head1 NAME + +Catalyst::Controller::CGIBin - Serve CGIs from root/cgi-bin + +=head1 VERSION + +Version 0.001 + +=cut + +our $VERSION = '0.001'; + +=head1 SYNOPSIS + +In your controller: + + package MyApp::Controller::Foo; + + use parent qw/Catalyst::Controller::CGIBin/; + + # example of a forward to /cgi-bin/hlagh/mtfnpy.cgi + sub dongs : Local Args(0) { + my ($self, $c) = @_; + $c->forward($self->cgi_action('hlagh/mtfnpy.cgi')); + } + +In your .conf: + + + + username_field username # used for REMOTE_USER env var + pass_env PERL5LIB + pass_env PATH + pass_env /^MYAPP_/ + + + +=head1 DESCRIPTION + +Dispatches to executable CGI files in root/cgi-bin for /cgi-bin/ paths. + +A path such as C will get the private path +C, for controller Foo, with the Cs converted to C<_>s +and prepended with C, as well as all non-word characters converted to +C<_>s. This is because L action names can't have non-word characters +in them. + +Inherits from L, see the documentation for that +module for configuration information. + +=cut + +sub register_actions { + my ($self, $c) = @_; + + my $cwd = getcwd; + + my $cgi_bin = $c->path_to('root', 'cgi-bin'); + + chdir $cgi_bin || + Catalyst::Exception->throw( + message => 'You have no root/cgi-bin directory' + ); + + my $namespace = $self->action_namespace($c); + + my $class = ref $self || $self; + + for my $file (File::Find::Rule->executable->file->in(".")) { + my ($cgi, $type); + my $code = do { no warnings; eval 'sub { '.slurp($file).' }' }; + + if (!$@) { + $cgi = $code; + $type = 'Perl'; + } else { + $cgi = sub { system "$cgi_bin/$file" }; + $type = 'Non-Perl'; + undef $@; + } + + $c->log->info("Registering root/cgi_bin/$file as a $type CGI.") + if $c->debug; + + my $action_name = $self->cgi_action($file); + my $path = join '/' => splitdir($file); + my $reverse = $namespace ? "$namespace/$action_name" : $action_name; + my $attrs = { Path => [ "cgi-bin/$path" ], Args => [ 0 ] }; + + $code = sub { + my ($controller, $context) = @_; + $controller->cgi_to_response($context, $cgi) + }; + + my $action = $self->create_action( + name => $action_name, + code => $code, + reverse => $reverse, + namespace => $namespace, + class => $class, + attributes => $attrs + ); + + $c->dispatcher->register($c, $action); + } + + chdir $cwd; + + $self->next::method($c, @_); +} + +=head1 METHODS + +=head2 $self->cgi_action($cgi_path) + +Takes a path to a CGI from C such as C and returns +the action name it is registered as. + +=cut + +sub cgi_action { + my ($self, $cgi) = @_; + + my $action_name = 'CGI_' . join '_' => splitdir($cgi); + $action_name =~ s/\W/_/g; + + $action_name +} + +=head1 AUTHOR + +Rafael Kitover, C<< >> + +=head1 BUGS + +Please report any bugs or feature requests to C, or through the web interface at +L. +I will be notified, and then you'll automatically be notified of progress on +your bug as I make changes. + +=head1 SUPPORT + +More information at: + +=over 4 + +=item * RT: CPAN's request tracker + +L + +=item * AnnoCPAN: Annotated CPAN documentation + +L + +=item * CPAN Ratings + +L + +=item * Search CPAN + +L + +=back + +=head1 COPYRIGHT & LICENSE + +Copyright (c) 2008 Rafael Kitover + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=cut + +1; # End of Catalyst::Controller::CGIBin + +# vim: expandtab shiftwidth=4 ts=4 tw=80: diff --git a/lib/Catalyst/Controller/WrapCGI.pm b/lib/Catalyst/Controller/WrapCGI.pm index 7338efe..39657e7 100644 --- a/lib/Catalyst/Controller/WrapCGI.pm +++ b/lib/Catalyst/Controller/WrapCGI.pm @@ -7,6 +7,7 @@ use parent 'Catalyst::Controller'; use HTTP::Request::AsCGI; use HTTP::Request; use URI; +use Catalyst::Exception (); =head1 NAME @@ -14,11 +15,11 @@ Catalyst::Controller::WrapCGI - Run CGIs in Catalyst =head1 VERSION -Version 0.001 +Version 0.002 =cut -our $VERSION = '0.001'; +our $VERSION = '0.002'; =head1 SYNOPSIS @@ -42,9 +43,10 @@ In your .conf, configure which environment variables to pass: + username_field username # used for REMOTE_USER env var pass_env PERL5LIB pass_env PATH - pass_env HLAGH + pass_env /^MYAPP_/ @@ -53,6 +55,21 @@ In your .conf, configure which environment variables to pass: Allows you to run Perl code in a CGI environment derived from your L context. +If you just want to run CGIs from files, see L. + +=head1 CONFIGURATION + +C<$your_controller->{CGI}{pass_env}> should be an array of environment variables +or regular expressions to pass through to your CGIs. Entries surrounded by C +characters are considered regular expressions. + +Default is to pass the whole of C<%ENV>. + +C<{CGI}{username_field}> should be the field for your user's name, which will be +read from C<$c->user->obj>. Defaults to 'username'. + +See L for an example. + =cut # Hack-around because Catalyst::Engine::HTTP goes and changes @@ -101,7 +118,7 @@ The environment variables to pass on are taken from the configuration for your Controller, see L for an example. If you don't supply a list of environment variables to pass, the whole of %ENV is used. -Used by cgi_to_response, which is probably what you want to use as well. +Used by cgi_to_response (above), which is probably what you want to use as well. =cut @@ -127,16 +144,30 @@ sub wrap_cgi { } } - my @env = @{ $self->{CGI}{pass_env} || [ keys %ENV ] }; + my @env; + + for (@{ $self->{CGI}{pass_env} }) { + if (m!^/(.*)/\z!) { + my $re = qr/$1/; + push @env, grep /$re/, keys %ENV; + } else { + push @env, $_; + } + } + + @env = keys %ENV unless @env; $req->content($body_content); $req->content_length(length($body_content)); - my $user = (($c->can('user_exists') && $c->user_exists) - ? eval { $c->user->obj->username } + + my $username_field = $self->{CGI}{username_field} || 'username'; + + my $username = (($c->can('user_exists') && $c->user_exists) + ? eval { $c->user->obj->$username_field } : ''); my $env = HTTP::Request::AsCGI->new( $req, - REMOTE_USER => $user, + ($username ? (REMOTE_USER => $username) : ()), map { ($_, $ENV{$_}) } @env ); @@ -155,8 +186,9 @@ sub wrap_cgi { select($old); - warn "CGI invoke failed: $saved_error" if $saved_error; - + Catalyst::Exception->throw( + message => "CGI invocation failed: $saved_error" + ) if $saved_error; } return $env->response; @@ -168,7 +200,7 @@ Original development sponsored by L =head1 SEE ALSO -L, L, +L, L, L, L, L =head1 AUTHOR @@ -218,4 +250,4 @@ under the same terms as Perl itself. 1; # End of Catalyst::Controller::WrapCGI -# vim: expandtab shiftwidth=4 ts=4 tw=80: +# vim: expandtab shiftwidth=2 ts=2 tw=80: diff --git a/lib/Catalyst/Plugin/CGIBin.pm b/lib/Catalyst/Plugin/CGIBin.pm deleted file mode 100644 index 611c5e9..0000000 --- a/lib/Catalyst/Plugin/CGIBin.pm +++ /dev/null @@ -1,152 +0,0 @@ -package Catalyst::Plugin::CGIBin; - -use strict; -use warnings; - -use Class::C3; -use URI::Escape; -use File::Slurp 'slurp'; -use File::Find::Rule (); -use Cwd; -use Catalyst::Exception (); - -=head1 NAME - -Catalyst::Plugin::CGIBin - Serve CGIs from root/cgi-bin - -=head1 VERSION - -Version 0.001 - -=cut - -our $VERSION = '0.001'; - -=head1 SYNOPSIS - -In MyApp.pm: - - use Catalyst; - - __PACKAGE__->setup(qw/CGIBin/); - -In your .conf: - - - controller Foo - - - - - pass_env PERL5LIB - pass_env PATH - - - -=head1 DESCRIPTION - -Dispatches to executable CGI files in root/cgi-bin through the configured -controller, which must inherit from L. - -=cut - -my ($cgi_controller, $cgis); - -sub setup { - my $app = shift; - - my $cwd = getcwd; - - my $cgi_bin = $app->path_to('root', 'cgi-bin'); - - chdir $cgi_bin || - Catalyst::Exception->throw( - message => 'You have no root/cgi-bin directory' - ); - - $cgi_controller = $app->config->{'Plugin::CGIBin'}{controller} || - Catalyst::Exception->throw( - message => 'You must configure a controller for Plugin::CGIBin' - ); - - for my $cgi (File::Find::Rule->executable->file->in(".")) { - my $code = do { no warnings; eval 'sub { '.slurp($cgi).' }' }; - if (!$@) { # Perl source - $cgis->{$cgi} = $code; - undef $@; - } else { # some other type of executable - $cgis->{$cgi} = sub { system "$cgi_bin/$cgi" }; - } - } - - chdir $cwd; - - $app->next::method(@_); -} - -sub dispatch { - my $c = shift; - my $path = uri_unescape($c->req->path); - - if ($path =~ m!^cgi-bin/(.*)!) { - my $cgi = $cgis->{$1}; - - if ($cgi) { - $c->controller($cgi_controller)->cgi_to_response( - $c, $cgi - ); - return; - } - } - - $c->next::method(@_); -} - -=head1 AUTHOR - -Rafael Kitover, C<< >> - -=head1 BUGS - -Please report any bugs or feature requests to C, or through the web interface at -L. -I will be notified, and then you'll automatically be notified of progress on -your bug as I make changes. - -=head1 SUPPORT - -More information at: - -=over 4 - -=item * RT: CPAN's request tracker - -L - -=item * AnnoCPAN: Annotated CPAN documentation - -L - -=item * CPAN Ratings - -L - -=item * Search CPAN - -L - -=back - -=head1 COPYRIGHT & LICENSE - -Copyright (c) 2008 Rafael Kitover - -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. - -=cut - -1; # End of Catalyst::Plugin::CGIBin - -# vim: expandtab shiftwidth=4 ts=4 tw=80: diff --git a/lib/CatalystX/GlobalContext.pm b/lib/CatalystX/GlobalContext.pm index f76d8d3..d3f13b5 100644 --- a/lib/CatalystX/GlobalContext.pm +++ b/lib/CatalystX/GlobalContext.pm @@ -43,16 +43,17 @@ our $VERSION = '0.01'; =head1 DESCRIPTION -This module, in combination with L is for helping -you run legacy mod_perl code in L. +This module, in combination with L or +L is for helping you run legacy mod_perl code in +L. You save a copy of $c somewhere at the beginning of the request cycle, and it is then accessible through an export where you need it. -You can then rip out Apache:: type things, and replace them with things based on -$c. +You can then rip out C type things, and replace them with things based on +C<$c>. -What we really need is a set of Apache:: compatibility classes, but that doesn't +What we really need is a set of C compatibility classes, but that doesn't exist yet. DO NOT USE THIS MODULE IN NEW CODE @@ -71,6 +72,11 @@ sub set_context { weaken $c; } +=head1 SEE ALSO + +L, L, +L + =head1 AUTHOR Rafael Kitover, C<< >> diff --git a/t/00-load.t b/t/00-load.t index 08510b8..bdb1a62 100644 --- a/t/00-load.t +++ b/t/00-load.t @@ -4,7 +4,7 @@ use Test::More tests => 3; BEGIN { use_ok( 'Catalyst::Controller::WrapCGI' ); - use_ok( 'Catalyst::Plugin::CGIBin' ); + use_ok( 'Catalyst::Controller::CGIBin' ); use_ok( 'CatalystX::GlobalContext' ); } diff --git a/t/boilerplate.t b/t/boilerplate.t index 93ddf47..4a254d9 100644 --- a/t/boilerplate.t +++ b/t/boilerplate.t @@ -49,7 +49,7 @@ TODO: { ); module_boilerplate_ok('lib/Catalyst/Controller/WrapCGI.pm'); - module_boilerplate_ok('lib/Catalyst/Plugin/CGIBin.pm'); + module_boilerplate_ok('lib/Catalyst/Controller/CGIBin.pm'); module_boilerplate_ok('lib/CatalystX/GlobalContext.pm'); diff --git a/t/cgibin.t b/t/cgibin.t new file mode 100644 index 0000000..52fa7fc --- /dev/null +++ b/t/cgibin.t @@ -0,0 +1,42 @@ +#!perl + +use strict; +use warnings; + +use FindBin '$Bin'; +use lib "$Bin/lib"; + +use Test::More tests => 4; + +use Catalyst::Test 'TestCGIBin'; +use HTTP::Request::Common; + +my $response = request POST '/cgi-bin/test.pl', [ + foo => 'bar', + bar => 'baz' +]; + +is($response->content, 'foo:bar bar:baz', 'POST to Perl CGI File'); + +$response = request POST '/cgihandler/dongs', [ + foo => 'bar', + bar => 'baz' +]; + +is($response->content, 'foo:bar bar:baz', + 'POST to Perl CGI File through a forward'); + +$response = request POST '/cgihandler/mtfnpy', [ + foo => 'bar', + bar => 'baz' +]; + +is($response->content, 'foo:bar bar:baz', + 'POST to Perl CGI File through a forward via cgi_action'); + +SKIP: { + skip "Can't run shell scripts on non-*nix", 1 + if $^O eq 'MSWin32' || $^O eq 'VMS'; + + is(get('/cgi-bin/test.sh'), "Hello!\n", 'Non-Perl CGI File'); +} diff --git a/t/lib/TestCGIBin.pm b/t/lib/TestCGIBin.pm new file mode 100644 index 0000000..a63b6b0 --- /dev/null +++ b/t/lib/TestCGIBin.pm @@ -0,0 +1,7 @@ +package TestCGIBin; + +use Catalyst; + +__PACKAGE__->setup; + +1; diff --git a/t/lib/TestCGIBin/Controller/CGIHandler.pm b/t/lib/TestCGIBin/Controller/CGIHandler.pm new file mode 100644 index 0000000..41e20f5 --- /dev/null +++ b/t/lib/TestCGIBin/Controller/CGIHandler.pm @@ -0,0 +1,17 @@ +package TestCGIBin::Controller::CGIHandler; + +use parent 'Catalyst::Controller::CGIBin'; + +# try out a forward +sub dongs : Local Args(0) { + my ($self, $c) = @_; + $c->forward('/cgihandler/CGI_test_pl'); +} + +# try resolved forward +sub mtfnpy : Local Args(0) { + my ($self, $c) = @_; + $c->forward($self->cgi_action('test.pl')); +} + +1; diff --git a/t/lib/TestPlugin/root/cgi-bin/test.pl b/t/lib/TestCGIBin/root/cgi-bin/test.pl similarity index 100% rename from t/lib/TestPlugin/root/cgi-bin/test.pl rename to t/lib/TestCGIBin/root/cgi-bin/test.pl diff --git a/t/lib/TestPlugin/root/cgi-bin/test.sh b/t/lib/TestCGIBin/root/cgi-bin/test.sh similarity index 100% rename from t/lib/TestPlugin/root/cgi-bin/test.sh rename to t/lib/TestCGIBin/root/cgi-bin/test.sh diff --git a/t/lib/TestPlugin.pm b/t/lib/TestPlugin.pm deleted file mode 100644 index 110bab9..0000000 --- a/t/lib/TestPlugin.pm +++ /dev/null @@ -1,11 +0,0 @@ -package TestPlugin; - -use Catalyst; - -__PACKAGE__->config->{'Plugin::CGIBin'} = { - controller => 'CGIHandler' -}; - -__PACKAGE__->setup(qw/CGIBin/); - -1; diff --git a/t/lib/TestPlugin/Controller/CGIHandler.pm b/t/lib/TestPlugin/Controller/CGIHandler.pm deleted file mode 100644 index 043e748..0000000 --- a/t/lib/TestPlugin/Controller/CGIHandler.pm +++ /dev/null @@ -1,5 +0,0 @@ -package TestPlugin::Controller::CGIHandler; - -use parent 'Catalyst::Controller::WrapCGI'; - -1; diff --git a/t/plugin-cgibin.t b/t/plugin-cgibin.t deleted file mode 100644 index 0062080..0000000 --- a/t/plugin-cgibin.t +++ /dev/null @@ -1,21 +0,0 @@ -#!perl - -use strict; -use warnings; - -use FindBin '$Bin'; -use lib "$Bin/lib"; - -use Test::More tests => 2; - -use Catalyst::Test 'TestPlugin'; -use HTTP::Request::Common; - -my $response = request POST '/cgi-bin/test.pl', [ - foo => 'bar', - bar => 'baz' -]; - -is($response->content, 'foo:bar bar:baz', 'POST to Perl CGI File'); - -is(get('/cgi-bin/test.sh'), "Hello!\n", 'Non-Perl CGI File');