Merge 'trunk' into 'psgi'
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine.pm
index 4cc8c6d..1fdbfeb 100644 (file)
@@ -14,6 +14,8 @@ use Moose::Util::TypeConstraints;
 use Plack::Loader;
 use Plack::Middleware::Conditional;
 use Plack::Middleware::ReverseProxy;
+use Encode ();
+use utf8;
 
 use namespace::clean -except => 'meta';
 
@@ -155,6 +157,14 @@ sub finalize_error {
 
     $c->res->content_type('text/html; charset=utf-8');
     my $name = ref($c)->config->{name} || join(' ', split('::', ref $c));
+    
+    # Prevent Catalyst::Plugin::Unicode::Encoding from running.
+    # This is a little nasty, but it's the best way to be clean whether or
+    # not the user has an encoding plugin.
+
+    if ($c->can('encoding')) {
+      $c->{encoding} = '';
+    }
 
     my ( $title, $error, $infos );
     if ( $c->debug ) {
@@ -303,10 +313,12 @@ sub finalize_error {
 </body>
 </html>
 
-
-    # Trick IE
+    # Trick IE. Old versions of IE would display their own error page instead
+    # of ours if we'd give it less than 512 bytes.
     $c->res->{body} .= ( ' ' x 512 );
 
+    $c->res->{body} = Encode::encode("UTF-8", $c->res->{body});
+
     # Return 500
     $c->res->status(500);
 }
@@ -344,6 +356,8 @@ Clean up after uploads, deleting temp files.
 sub finalize_uploads {
     my ( $self, $c ) = @_;
 
+    # N.B. This code is theoretically entirely unneeded due to ->cleanup(1)
+    #      on the HTTP::Body object.
     my $request = $c->request;
     foreach my $key (keys %{ $request->uploads }) {
         my $upload = $request->uploads->{$key};
@@ -368,6 +382,7 @@ sub prepare_body {
         unless ( $request->_body ) {
             my $type = $request->header('Content-Type');
             $request->_body(HTTP::Body->new( $type, $length ));
+            $request->_body->cleanup(1); # Make extra sure!
             $request->_body->tmpdir( $appclass->config->{uploadtmp} )
               if exists $appclass->config->{uploadtmp};
         }
@@ -519,10 +534,24 @@ sub prepare_path {
     my $base_path = $env->{SCRIPT_NAME} || "/";
 
     # set the request URI
-    my $req_uri = $env->{REQUEST_URI};
-    $req_uri =~ s/\?.*$//;
-    my $path = $req_uri;
-    $path =~ s{^/+}{};
+    my $path;
+    if (!$ctx->config->{use_request_uri_for_path}) {
+        my $path_info = $env->{PATH_INFO};
+        if ( exists $env->{REDIRECT_URL} ) {
+            $base_path = $env->{REDIRECT_URL};
+            $base_path =~ s/\Q$path_info\E$//;
+        }
+        $path = $base_path . $path_info;
+        $path =~ s{^/+}{};
+        $path =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
+        $path =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
+    }
+    else {
+        my $req_uri = $env->{REQUEST_URI};
+        $req_uri =~ s/\?.*$//;
+        $path = $req_uri;
+        $path =~ s{^/+}{};
+    }
 
     # Using URI directly is way too slow, so we construct the URLs manually
     my $uri_class = "URI::$scheme";
@@ -537,7 +566,7 @@ sub prepare_path {
     my $query = $env->{QUERY_STRING} ? '?' . $env->{QUERY_STRING} : '';
     my $uri   = $scheme . '://' . $host . '/' . $path . $query;
 
-    $ctx->request->uri( bless \$uri, $uri_class );
+    $ctx->request->uri( (bless \$uri, $uri_class)->canonical );
 
     # set the base URI
     # base must end in a slash
@@ -650,7 +679,7 @@ sub prepare_uploads {
             my $u = Catalyst::Request::Upload->new
               (
                size => $upload->{size},
-               type => $headers->content_type,
+               type => scalar $headers->content_type,
                headers => $headers,
                tempname => $upload->{tempname},
                filename => $upload->{filename},
@@ -743,20 +772,32 @@ header.
 
 The amount of input data that has already been read.
 
-=head2 $self->run($c)
+=head2 $self->run($app, $server)
 
-Start the engine. Implemented by the various engine classes.
+Start the engine. Builds a PSGI application and calls the
+run method on the server passed in..
 
 =cut
 
 sub run {
     my ($self, $app, @args) = @_;
-    Carp::cluck("Run");
+    my $server = pop @args if blessed $args[-1];
+    $server ||= Plack::Loader->auto(); # We're not being called from a script,
+                                       # so auto detect what backend to run on.
+                                       # This does *NOT* cover mod_perl.
     # FIXME - Do something sensible with the options we're passed
-    $self->_run_psgi_app($self->_build_psgi_app($app, @args), @args);
+    my $psgi = $self->build_psgi_app($app, @args);
+    $server->run($psgi);
 }
 
-sub _build_psgi_app {
+=head2 build_psgi_app ($app, @args)
+
+Builds and returns a PSGI application closure, wrapping it in the reverse proxy
+middleware if the using_frontend_proxy config setting is set.
+
+=cut
+
+sub build_psgi_app {
     my ($self, $app, @args) = @_;
 
     my $psgi_app = sub {
@@ -782,12 +823,6 @@ sub _build_psgi_app {
     return $psgi_app;
 }
 
-sub _run_psgi_app {
-    my ($self, $psgi_app, @args);
-    # FIXME - Need to be able to specify engine and pass options..
-    Plack::Loader->auto()->run($psgi_app);
-}
-
 =head2 $self->write($c, $buffer)
 
 Writes the buffer to the client.
@@ -831,13 +866,13 @@ sub unescape_uri {
 
 =head2 $self->env
 
-Hash containing enviroment variables including many special variables inserted
+Hash containing environment variables including many special variables inserted
 by WWW server - like SERVER_*, REMOTE_*, HTTP_* ...
 
-Before accesing enviroment variables consider whether the same information is
+Before accessing environment variables consider whether the same information is
 not directly available via Catalyst objects $c->request, $c->engine ...
 
-BEWARE: If you really need to access some enviroment variable from your Catalyst
+BEWARE: If you really need to access some environment variable from your Catalyst
 application you should use $c->engine->env->{VARNAME} instead of $ENV{VARNAME},
 as in some enviroments the %ENV hash does not contain what you would expect.