Permalink
Browse files

merge doc updates by markstos, rely on CGI::Emulate::PSGI on setting …

…up req. env. and response
  • Loading branch information...
kazuho committed Jan 7, 2010
1 parent e515157 commit 8f88f88395267e24921cde21b644e0b691b93a68
Showing with 65 additions and 38 deletions.
  1. +5 −1 Makefile.PL
  2. +21 −7 README
  3. +8 −30 lib/CGI/Application/Emulate/PSGI.pm
  4. +31 −0 t/00base.t
View
@@ -3,7 +3,11 @@ use inc::Module::Install;
all_from 'lib/CGI/Application/Emulate/PSGI.pm';
readme_from 'lib/CGI/Application/Emulate/PSGI.pm';
-test_requires 'Test::More' => 0.88;
+requires 'CGI::Application';
+requires 'CGI::Emulate::PSGI' => '0.05';
+requires 'Plack';
+
+test_requires 'Test::More' => '0.88';
auto_include;
WriteAll;
View
28 README
@@ -3,32 +3,46 @@ NAME
for CGI::Application
SYNOPSIS
+ Create a PSGI application from a CGI::Application project:
+
# if using CGI::Application
- my $app = CGI::Application::Emulate::PSGI->handler(sub {
+ my $psgi_app = CGI::Application::Emulate::PSGI->handler(sub {
my $webapp = WebApp->new();
$webapp->run();
});
# if using CGI::Application::Dispatch
- my $app = CGI::Application::Emulate::PSGI->handler(sub {
+ my $psgi_app = CGI::Application::Emulate::PSGI->handler(sub {
WebApp::Dispatch->dispatch();
});
+ See plackup for options for running a PSGI application.
+
DESCRIPTION
- CGI::Application::Emulate::PSGI is a runner to run CGI::Application as a
- PSGI application. Differences from CGI::Application::PSGI are:
+ CGI::Application::Emulate::PSGI allows a project based on
+ CGI::Application to run as a PSGI application. Differences from
+ CGI::Application::PSGI are:
- uses CGI.pm instead of CGI::PSGI
+ uses CGI.pm directly instead of CGI::PSGI
CGI::Application::PSGI (that uses CGI::PSGI) does not support
programs calling CGI.pm in func-style (like CGI::virtual_host()).
CGI::Application::Emulate::PSGI sets up environment variables so
- that codes using CGI.pm will work.
+ that code using CGI.pm will work. Both approaches explictly use
+ CGI.pm as the query object.
compatible with CGI::Application::Dispatch
The interface of CGI::Application::Emulate::PSGI is different from
CGI::Application::PSGI, and is compatible with
CGI::Application::Dispatch.
+ headers are parsed and re-generated.
+ This difference is in favor of CGI::Application::PSGI, which more
+ directly generates the HTTP headers in PSGI format. This module
+ requires additional processing: First CGI::Application builds the
+ full response including the headers and body, then we parse the
+ final result back into the header and body format called for by the
+ PSGI spec.
+
AUTHOR
Kazuho Oku <kazuhooku@gmail.com>
@@ -37,5 +51,5 @@ LICENSE
under the same terms as Perl itself.
SEE ALSO
- CGI::Application::PSGI
+ CGI::Application::PSGI, CGI
@@ -4,6 +4,8 @@ use 5.008;
use strict;
use warnings;
use CGI;
+use CGI::Emulate::PSGI;
+use CGI::Parse::PSGI;
our $VERSION = '0.01';
@@ -12,42 +14,18 @@ sub handler {
return sub {
my $env = shift;
- my $environment = {
- GATEWAY_INTERFACE => 'CGI/1.1',
- # not in RFC 3875
- HTTPS => ( ( $env->{'psgi.url_scheme'} eq 'https' ) ? 'ON' : 'OFF' ),
- SERVER_SOFTWARE => "CGI-Emulate-PSGI",
- REMOTE_ADDR => '127.0.0.1',
- REMOTE_HOST => 'localhost',
- REMOTE_PORT => int( rand(64000) + 1000 ), # not in RFC 3875
- # REQUEST_URI => $uri->path_query, # not in RFC 3875
- ( map { $_ => $env->{$_} } grep !/^psgi\./, keys %$env ),
- CGI_APP_RETURN_ONLY => 1,
- };
my $output = do {
+ local %ENV = (
+ %ENV,
+ CGI::Emulate::PSGI->emulate_environment($env),
+ CGI_APP_RETURN_ONLY => 1,
+ );
local *STDIN = $env->{'psgi.input'};
local *STDERR = $env->{'psgi.errors'};
- local @ENV{keys %$environment} = values %$environment;
CGI::initialize_globals();
$code->();
};
- my $status = 200;
- my ($headers, $body) = split /\r?\n\r?\n/, $output, 2;
- my @headers = map { split /:\s*/, $_, 2 } split /\r?\n/, $headers;
- for (my $i = 0; $i < @headers;) {
- if ($headers[$i] =~ /^status$/i) {
- $status = $headers[$i + 1];
- $status =~ s/\s+.*$//; # only keep the digits
- splice @headers, $i, 2;
- } else {
- $i += 2;
- }
- }
- return [
- $status,
- \@headers,
- [ $body ],
- ];
+ return CGI::Parse::PSGI::parse_cgi_output(\$output);
};
}
View
@@ -1,7 +1,38 @@
use strict;
use warnings;
+
+use Plack::Test;
use Test::More;
use_ok 'CGI::Application::Emulate::PSGI';
+
+test_psgi
+ app => CGI::Application::Emulate::PSGI->handler(sub {
+ my $ca = MyCGIApp->new;
+ $ca->run;
+ }),
+ client => sub {
+ my $cb = shift;
+ my $req = HTTP::Request->new(GET => 'http://localhost/');
+ my $res = $cb->($req);
+ is $res->code, 200, 'status code is 200';
+ is $res->content_type, 'application/x-hello-world', 'content-type';
+ is $res->content, 'hello world', 'body';
+ };
+
done_testing;
+package MyCGIApp;
+
+use base qw(CGI::Application);
+
+sub setup {
+ my $self = shift;
+ $self->run_modes('start' => 'start');
+}
+
+sub start {
+ my $self = shift;
+ $self->header_add(-type => 'application/x-hello-world');
+ "hello world";
+}

4 comments on commit 8f88f88

Thanks for the update. It would also be an interesting to include a test for a header that spans multiple lines.

multiline header value should now be addressed with the latest release of CGI::Emulate::PSGI, where it basically removes newlines embedded in the header values, since they're invalid in PSGI ("Headers" in the PSGI.pod). See also https://github.com/miyagawa/Plack/pull/222 and https://github.com/miyagawa/Plack/pull/224

I modified the multi-lines header test to test with the latest CGI::Application::Emulate::PSGI and CGI::Emulate::PSGI http://gist.github.com/1019207 and it now fails with:

ok 1 - got 200 status
ok 2 - Zoo matches 'single'
ok 3 - header header value matches text/html
Invalid header value contains a newline not followed by whitespace: foo="multi-line: header
 fools: you?" at (eval 22) line 25
        CGI::header('CGI=HASH(0x100a04558)', '-foo', 'multi-line: header\x{a} fools: you?') called at /Users/miyagawa/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/CGI/Application.pm line 610
        CGI::Application::_send_headers('CGI::Application=HASH(0x1009f10d0)') called at /Users/miyagawa/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/CGI/Application.pm line 200
        CGI::Application::run('CGI::Application=HASH(0x1009f10d0)') called at t/multi_line_header.t line 33
        main::__ANON__() called at /Users/miyagawa/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/CGI/Application/Emulate/PSGI.pm line 26
        CGI::Application::Emulate::PSGI::__ANON__('HASH(0x10096ba30)') called at t/multi_line_header.t line 36
1..3
# Looks like your test exited with 255 just after 3.

Seems CGI.pm throws exceptions when given newlines in the header. I guess this is due to the change in CGI.pm 3.51 and CVE-2010-4411. CGI.pm could alternatively escape these newlines and align them with single newline and whitespaces, that way CGI::Emulate::PSGI will mangle them back with newline-free header values (because PSGI doesn't allow newlines in the header), but it might be too late to update CGI.pm again. So the current state isn't so bad.

Please sign in to comment.