From: Matt S. Trout Date: Mon, 9 Apr 2007 14:11:49 +0000 (+0000) Subject: initial import of CGI wrapping code X-Git-Tag: 0.030~72 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Controller-WrapCGI.git;a=commitdiff_plain;h=b2a17df2d9ea22f71f2827fac0e40266ce43199d initial import of CGI wrapping code --- b2a17df2d9ea22f71f2827fac0e40266ce43199d diff --git a/lib/CatalystX/Controller/WrapCGI.pm b/lib/CatalystX/Controller/WrapCGI.pm new file mode 100644 index 0000000..afcef2a --- /dev/null +++ b/lib/CatalystX/Controller/WrapCGI.pm @@ -0,0 +1,99 @@ +package CatalystX::Controller::WrapCGI; + +# AUTHOR: Matt S Trout, mst@shadowcatsystems.co.uk +# Original development sponsored by http://www.altinity.com/ + +use strict; +use warnings; +use base 'Catalyst::Controller'; + +use HTTP::Request::AsCGI; +use HTTP::Request; +use URI::Escape; + +# Hack-around because Catalyst::Engine::HTTP goes and changes +# them to be the remote socket, and FCGI.pm does even dumber things. + +open(*REAL_STDIN, "<&=".fileno(*STDIN)); +open(*REAL_STDOUT, ">>&=".fileno(*STDOUT)); + +sub cgi_to_response { + my ($self, $c, $script) = @_; + my $res = $self->wrap_cgi($c, $script); + + # if the CGI doesn't set the response code but sets location they were + # probably trying to redirect so set 302 for them + + if (length($res->headers->header('Location')) && $res->code == 200) { + $c->res->status(302); + } else { + $c->res->status($res->code); + } + $c->res->body($res->content); + $c->res->headers($res->headers); +} + +sub wrap_cgi { + my ($self, $c, $call) = @_; + my $req = HTTP::Request->new( + map { $c->req->$_ } qw/method uri headers/ + ); + my $body = $c->req->body; + my $body_content = ''; + + $req->content_type($c->req->content_type); # set this now so we can override + + if ($body) { # Slurp from body filehandle + local $/; $body_content = <$body>; + } else { + my $body_params = $c->req->body_parameters; + if (keys %$body_params) { + my @parts; + foreach my $key (keys %$body_params) { + my $raw = $body_params->{$key}; + foreach my $value (ref $raw ? @$raw : ($raw)) { + push(@parts, join('=', map { uri_escape($_) } ($key, $value))); + } + } + $body_content = join('&', @parts); + $req->content_type('application/x-www-form-urlencoded'); + } + } + + #warn "Body type: ".$req->content_type; + #warn "Body: ${body_content}"; + + $req->content($body_content); + $req->content_length(length($body_content)); + my $user = (($c->can('user_exists') && $c->user_exists) + ? $c->user_object->username + : ''); + my $env = HTTP::Request::AsCGI->new( + $req, + REMOTE_USER => $user, + PERL5LIB => $ENV{PERL5LIB} # propagate custom perl lib paths + ); + + { + local *STDIN = \*REAL_STDIN; # restore the real ones so the filenos + local *STDOUT = \*REAL_STDOUT; # are 0 and 1 for the env setup + + my $old = select(REAL_STDOUT); # in case somebody just calls 'print' + + my $saved_error; + + $env->setup; + eval { $call->() }; + $saved_error = $@; + $env->restore; + + select($old); + + warn "CGI invoke failed: $saved_error" if $saved_error; + + } + + return $env->response; +} + +1;