fixed first block of startup debug messages missing when using a custom logger that...
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
index f69afe0..5002763 100644 (file)
@@ -4,7 +4,7 @@ use Moose;
 use Moose::Meta::Class ();
 extends 'Catalyst::Component';
 use Moose::Util qw/find_meta/;
-use B::Hooks::EndOfScope ();
+use namespace::clean -except => 'meta';
 use Catalyst::Exception;
 use Catalyst::Exception::Detach;
 use Catalyst::Exception::Go;
@@ -23,6 +23,7 @@ use Path::Class::File ();
 use URI ();
 use URI::http;
 use URI::https;
+use HTML::Entities;
 use Tree::Simple qw/use_weak_refs/;
 use Tree::Simple::Visitor::FindByUID;
 use Class::C3::Adopt::NEXT;
@@ -33,12 +34,17 @@ use Catalyst::EngineLoader;
 use utf8;
 use Carp qw/croak carp shortmess/;
 use Try::Tiny;
+use Safe::Isa;
+use Moose::Util 'find_meta';
 use Plack::Middleware::Conditional;
 use Plack::Middleware::ReverseProxy;
 use Plack::Middleware::IIS6ScriptNameFix;
+use Plack::Middleware::IIS7KeepAliveFix;
 use Plack::Middleware::LighttpdScriptNameFix;
+use Plack::Util;
+use Class::Load 'load_class';
 
-BEGIN { require 5.008004; }
+BEGIN { require 5.008003; }
 
 has stack => (is => 'ro', default => sub { [] });
 has stash => (is => 'rw', default => sub { {} });
@@ -46,8 +52,37 @@ has state => (is => 'rw', default => 0);
 has stats => (is => 'rw');
 has action => (is => 'rw');
 has counter => (is => 'rw', default => sub { {} });
-has request => (is => 'rw', default => sub { $_[0]->request_class->new({}) }, required => 1, lazy => 1);
-has response => (is => 'rw', default => sub { $_[0]->response_class->new({}) }, required => 1, lazy => 1);
+has request => (
+    is => 'rw',
+    default => sub {
+        my $self = shift;
+        $self->request_class->new($self->_build_request_constructor_args);
+    },
+    lazy => 1,
+);
+sub _build_request_constructor_args {
+    my $self = shift;
+    my %p = ( _log => $self->log );
+    $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp;
+    $p{data_handlers} = {$self->registered_data_handlers};
+    $p{_use_hash_multivalue} = $self->config->{use_hash_multivalue_in_request}
+      if $self->config->{use_hash_multivalue_in_request};
+    \%p;
+}
+
+has response => (
+    is => 'rw',
+    default => sub {
+        my $self = shift;
+        $self->response_class->new($self->_build_response_constructor_args);
+    },
+    lazy => 1,
+);
+sub _build_response_constructor_args {
+    my $self = shift;
+    { _log => $self->log };
+}
+
 has namespace => (is => 'rw');
 
 sub depth { scalar @{ shift->stack || [] }; }
@@ -75,7 +110,8 @@ our $GO        = Catalyst::Exception::Go->new;
 __PACKAGE__->mk_classdata($_)
   for qw/components arguments dispatcher engine log dispatcher_class
   engine_loader context_class request_class response_class stats_class
-  setup_finished _psgi_app loading_psgi_file run_options/;
+  setup_finished _psgi_app loading_psgi_file run_options _psgi_middleware
+  _data_handlers/;
 
 __PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
 __PACKAGE__->request_class('Catalyst::Request');
@@ -84,7 +120,7 @@ __PACKAGE__->stats_class('Catalyst::Stats');
 
 # Remember to update this in Catalyst::Runtime as well!
 
-our $VERSION = '5.90005';
+our $VERSION = '5.90051';
 
 sub import {
     my ( $class, @arguments ) = @_;
@@ -119,6 +155,8 @@ sub import {
 
 sub _application { $_[0] }
 
+=encoding UTF-8
+
 =head1 NAME
 
 Catalyst - The Elegant MVC Web Application Framework
@@ -236,9 +274,9 @@ MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
 
 If none of these are set, Catalyst will attempt to automatically detect the
 home directory. If you are working in a development environment, Catalyst
-will try and find the directory containing either Makefile.PL, Build.PL or
-dist.ini. If the application has been installed into the system (i.e.
-you have done C<make install>), then Catalyst will use the path to your
+will try and find the directory containing either Makefile.PL, Build.PL,
+dist.ini, or cpanfile. If the application has been installed into the system
+(i.e. you have done C<make install>), then Catalyst will use the path to your
 application module, without the .pm extension (e.g., /foo/MyApp if your
 application was installed at /foo/MyApp.pm)
 
@@ -291,7 +329,18 @@ cookies, HTTP headers, etc.). See L<Catalyst::Request>.
 
 =head2 $c->forward( $class, $method, [, \@arguments ] )
 
-Forwards processing to another action, by its private name. If you give a
+This is one way of calling another action (method) in the same or
+a different controller. You can also use C<< $self->my_method($c, @args) >>
+in the same controller or C<< $c->controller('MyController')->my_method($c, @args) >>
+in a different controller.
+The main difference is that 'forward' uses some of the Catalyst request
+cycle overhead, including debugging, which may be useful to you. On the
+other hand, there are some complications to using 'forward', restrictions
+on values returned from 'forward', and it may not handle errors as you prefer.
+Whether you use 'forward' or not is up to you; it is not considered superior to
+the other ways to call a method.
+
+'forward' calls  another action, by its private name. If you give a
 class name but no method, C<process()> is called. You may also optionally
 pass arguments in an arrayref. The action will receive the arguments in
 C<@_> and C<< $c->req->args >>. Upon returning from the function,
@@ -356,8 +405,12 @@ When called with no arguments it escapes the processing chain entirely.
 
 sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
 
+=head2 $c->visit( $action [, \@arguments ] )
+
 =head2 $c->visit( $action [, \@captures, \@arguments ] )
 
+=head2 $c->visit( $class, $method, [, \@arguments ] )
+
 =head2 $c->visit( $class, $method, [, \@captures, \@arguments ] )
 
 Almost the same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>,
@@ -386,8 +439,12 @@ transfer control to another action as if it had been reached directly from a URL
 
 sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) }
 
+=head2 $c->go( $action [, \@arguments ] )
+
 =head2 $c->go( $action [, \@captures, \@arguments ] )
 
+=head2 $c->go( $class, $method, [, \@arguments ] )
+
 =head2 $c->go( $class, $method, [, \@captures, \@arguments ] )
 
 The relationship between C<go> and
@@ -520,13 +577,13 @@ sub _comp_names_search_prefixes {
     # undef for a name will return all
     return keys %eligible if !defined $name;
 
-    my $query  = ref $name ? $name : qr/^$name$/i;
+    my $query  = $name->$_isa('Regexp') ? $name : qr/^$name$/i;
     my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
 
     return @result if @result;
 
     # if we were given a regexp to search against, we're done.
-    return if ref $name;
+    return if $name->$_isa('Regexp');
 
     # skip regexp fallback if configured
     return
@@ -617,7 +674,7 @@ sub controller {
 
     my $appclass = ref($c) || $c;
     if( $name ) {
-        unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps
+        unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps
             my $comps = $c->components;
             my $check = $appclass."::Controller::".$name;
             return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check};
@@ -655,7 +712,7 @@ sub model {
     my ( $c, $name, @args ) = @_;
     my $appclass = ref($c) || $c;
     if( $name ) {
-        unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps
+        unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps
             my $comps = $c->components;
             my $check = $appclass."::Model::".$name;
             return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check};
@@ -714,7 +771,7 @@ sub view {
 
     my $appclass = ref($c) || $c;
     if( $name ) {
-        unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps
+        unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps
             my $comps = $c->components;
             my $check = $appclass."::View::".$name;
             if( exists $comps->{$check} ) {
@@ -1069,6 +1126,8 @@ sub setup {
 
     $class->setup_log( delete $flags->{log} );
     $class->setup_plugins( delete $flags->{plugins} );
+    $class->setup_middleware();
+    $class->setup_data_handlers();
     $class->setup_dispatcher( delete $flags->{dispatcher} );
     if (my $engine = delete $flags->{engine}) {
         $class->log->warn("Specifying the engine in ->setup is no longer supported, see Catalyst::Upgrading");
@@ -1100,6 +1159,19 @@ You are running an old script!
 EOF
     }
 
+    # Call plugins setup, this is stupid and evil.
+    # Also screws C3 badly on 5.10, hack to avoid.
+    {
+        no warnings qw/redefine/;
+        local *setup = sub { };
+        $class->setup unless $Catalyst::__AM_RESTARTING;
+    }
+
+    # Initialize our data structure
+    $class->components( {} );
+
+    $class->setup_components;
+
     if ( $class->debug ) {
         my @plugins = map { "$_  " . ( $_->VERSION || '' ) } $class->registered_plugins;
 
@@ -1110,6 +1182,27 @@ EOF
             $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
         }
 
+        my @middleware = map {
+          ref $_ eq 'CODE' ? 
+            "Inline Coderef" : 
+              (ref($_) .'  '. ($_->can('VERSION') ? $_->VERSION || '' : '') 
+                || '')  } $class->registered_middlewares;
+
+        if (@middleware) {
+            my $column_width = Catalyst::Utils::term_width() - 6;
+            my $t = Text::SimpleTable->new($column_width);
+            $t->row($_) for @middleware;
+            $class->log->debug( "Loaded PSGI Middleware:\n" . $t->draw . "\n" );
+        }
+
+        my %dh = $class->registered_data_handlers;
+        if (my @data_handlers = keys %dh) {
+            my $column_width = Catalyst::Utils::term_width() - 6;
+            my $t = Text::SimpleTable->new($column_width);
+            $t->row($_) for @data_handlers;
+            $class->log->debug( "Loaded Request Data Handlers:\n" . $t->draw . "\n" );
+        }
+
         my $dispatcher = $class->dispatcher;
         my $engine     = $class->engine;
         my $home       = $class->config->{home};
@@ -1122,22 +1215,7 @@ EOF
           ? $class->log->debug(qq/Found home "$home"/)
           : $class->log->debug(qq/Home "$home" doesn't exist/)
           : $class->log->debug(q/Couldn't find home/);
-    }
-
-    # Call plugins setup, this is stupid and evil.
-    # Also screws C3 badly on 5.10, hack to avoid.
-    {
-        no warnings qw/redefine/;
-        local *setup = sub { };
-        $class->setup unless $Catalyst::__AM_RESTARTING;
-    }
-
-    # Initialize our data structure
-    $class->components( {} );
 
-    $class->setup_components;
-
-    if ( $class->debug ) {
         my $column_width = Catalyst::Utils::term_width() - 8 - 9;
         my $t = Text::SimpleTable->new( [ $column_width, 'Class' ], [ 8, 'Type' ] );
         for my $comp ( sort keys %{ $class->components } ) {
@@ -1160,29 +1238,6 @@ EOF
         $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
     }
 
-    # Make sure that the application class becomes immutable at this point,
-    B::Hooks::EndOfScope::on_scope_end {
-        return if $@;
-        my $meta = Class::MOP::get_metaclass_by_name($class);
-        if (
-            $meta->is_immutable
-            && ! { $meta->immutable_options }->{replace_constructor}
-            && (
-                   $class->isa('Class::Accessor::Fast')
-                || $class->isa('Class::Accessor')
-            )
-        ) {
-            warn "You made your application class ($class) immutable, "
-                . "but did not inline the\nconstructor. "
-                . "This will break catalyst, as your app \@ISA "
-                . "Class::Accessor(::Fast)?\nPlease pass "
-                . "(replace_constructor => 1)\nwhen making your class immutable.\n";
-        }
-        $meta->make_immutable(
-            replace_constructor => 1,
-        ) unless $meta->is_immutable;
-    };
-
     if ($class->config->{case_sensitive}) {
         $class->log->warn($class . "->config->{case_sensitive} is set.");
         $class->log->warn("This setting is deprecated and planned to be removed in Catalyst 5.81.");
@@ -1265,7 +1320,7 @@ path, use C<< $c->uri_for_action >> instead.
 sub uri_for {
     my ( $c, $path, @args ) = @_;
 
-    if (blessed($path) && $path->isa('Catalyst::Controller')) {
+    if ( $path->$_isa('Catalyst::Controller') ) {
         $path = $path->path_prefix;
         $path =~ s{/+\z}{};
         $path .= '/';
@@ -1282,7 +1337,7 @@ sub uri_for {
         $arg =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
     }
 
-    if ( blessed($path) ) { # action object
+    if ( $path->$_isa('Catalyst::Action') ) { # action object
         s|/|%2F|g for @args;
         my $captures = [ map { s|/|%2F|g; $_; }
                         ( scalar @args && ref $args[0] eq 'ARRAY'
@@ -1326,9 +1381,13 @@ sub uri_for {
     my $args = join('/', grep { defined($_) } @args);
     $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
     $args =~ s!^/+!!;
-    my $base = $c->req->base;
-    my $class = ref($base);
-    $base =~ s{(?<!/)$}{/};
+
+    my ($base, $class) = ('/', 'URI::_generic');
+    if(blessed($c)) {
+      $base = $c->req->base;
+      $class = ref($base);
+      $base =~ s{(?<!/)$}{/};
+    }
 
     my $query = '';
 
@@ -1529,18 +1588,18 @@ sub welcome_message {
                     We do, however, provide you with a few starting points.</p>
                  <p>If you want to jump right into web development with Catalyst
                     you might want to start with a tutorial.</p>
-<pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
+<pre>perldoc <a href="https://metacpan.org/module/Catalyst::Manual::Tutorial">Catalyst::Manual::Tutorial</a></code>
 </pre>
 <p>Afterwards you can go on to check out a more complete look at our features.</p>
 <pre>
-<code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
+<code>perldoc <a href="https://metacpan.org/module/Catalyst::Manual::Intro">Catalyst::Manual::Intro</a>
 <!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
 </code></pre>
                  <h2>What to do next?</h2>
                  <p>Next it's time to write an actual application. Use the
-                    helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&amp;mode=all">controllers</a>,
-                    <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&amp;mode=all">models</a>, and
-                    <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&amp;mode=all">views</a>;
+                    helper scripts to generate <a href="https://metacpan.org/search?q=Catalyst%3A%3AController">controllers</a>,
+                    <a href="https://metacpan.org/search?q=Catalyst%3A%3AModel">models</a>, and
+                    <a href="https://metacpan.org/search?q=Catalyst%3A%3AView">views</a>;
                     they can save you a lot of work.</p>
                     <pre><code>script/${prefix}_create.pl --help</code></pre>
                     <p>Also, be sure to check out the vast and growing
@@ -1576,7 +1635,7 @@ EOF
 =head2 run_options
 
 Contains a hash of options passed from the application script, including
-the original ARGV the script receieved, the processed values from that
+the original ARGV the script received, the processed values from that
 ARGV and any extra arguments to the script which were not processed.
 
 This can be used to add custom options to your application's scripts
@@ -1773,6 +1832,14 @@ sub finalize {
         $c->log->error($error);
     }
 
+    # Support skipping finalize for psgix.io style 'jailbreak'.  Used to support
+    # stuff like cometd and websockets
+    
+    if($c->request->_has_io_fh) {
+      $c->log_response;
+      return;
+    }
+
     # Allow engine to handle finalize flow (for POE)
     my $engine = $c->engine;
     if ( my $code = $engine->can('finalize') ) {
@@ -1787,7 +1854,7 @@ sub finalize {
             $c->finalize_error;
         }
 
-        $c->finalize_headers;
+        $c->finalize_headers unless $c->response->finalized_headers;
 
         # HEAD request
         if ( $c->request->method eq 'HEAD' ) {
@@ -1800,7 +1867,7 @@ sub finalize {
     $c->log_response;
 
     if ($c->use_stats) {
-        my $elapsed = sprintf '%f', $c->stats->elapsed;
+        my $elapsed = $c->stats->elapsed;
         my $av = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed;
         $c->log->info(
             "Request took ${elapsed}s ($av/s)\n" . $c->stats->report . "\n" );
@@ -1854,6 +1921,7 @@ sub finalize_headers {
 
         if ( !$response->has_body ) {
             # Add a default body if none is already present
+            my $encoded_location = encode_entities($location);
             $response->body(<<"EOF");
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml"> 
@@ -1861,7 +1929,7 @@ sub finalize_headers {
     <title>Moved</title>
   </head>
   <body>
-     <p>This item has moved <a href="$location">here</a>.</p>
+     <p>This item has moved <a href="$encoded_location">here</a>.</p>
   </body>
 </html>
 EOF
@@ -1897,7 +1965,7 @@ EOF
 
     $c->finalize_cookies;
 
-    $c->engine->finalize_headers( $c, @_ );
+    $c->response->finalize_headers();
 
     # Done
     $response->finalized_headers(1);
@@ -1983,6 +2051,11 @@ etc.).
 
 =cut
 
+has _uploadtmp => (
+    is => 'ro',
+    predicate => '_has_uploadtmp',
+);
+
 sub prepare {
     my ( $class, @arguments ) = @_;
 
@@ -1991,10 +2064,9 @@ sub prepare {
     # into the application.
     $class->context_class( ref $class || $class ) unless $class->context_class;
 
-    my $c = $class->context_class->new({});
+    my $uploadtmp = $class->config->{uploadtmp};
+    my $c = $class->context_class->new({ $uploadtmp ? (_uploadtmp => $uploadtmp) : ()});
 
-    # For on-demand data
-    $c->request->_context($c);
     $c->response->_context($c);
 
     #surely this is not the most efficient way to do things...
@@ -2012,8 +2084,8 @@ sub prepare {
             $c->prepare_request(@arguments);
             $c->prepare_connection;
             $c->prepare_query_parameters;
-            $c->prepare_headers;
-            $c->prepare_cookies;
+            $c->prepare_headers; # Just hooks, no longer needed - they just
+            $c->prepare_cookies; # cause the lazy attribute on req to build
             $c->prepare_path;
 
             # Prepare the body for reading, either by prepare_body
@@ -2025,6 +2097,7 @@ sub prepare {
                 $c->prepare_body;
             }
         }
+        $c->prepare_action;
     }
     # VERY ugly and probably shouldn't rely on ->finalize actually working
     catch {
@@ -2032,19 +2105,19 @@ sub prepare {
         $c->response->status(400);
         $c->response->content_type('text/plain');
         $c->response->body('Bad Request');
+        # Note we call finalize and then die here, which escapes
+        # finalize being called in the enclosing block..
+        # It in fact couldn't be called, as we don't return $c..
+        # This is a mess - but I'm unsure you can fix this without
+        # breaking compat for people doing crazy things (we should set
+        # the 400 and just return the ctx here IMO, letting finalize get called
+        # above...
         $c->finalize;
         die $_;
     };
 
-    my $method  = $c->req->method  || '';
-    my $path    = $c->req->path;
-    $path       = '/' unless length $path;
-    my $address = $c->req->address || '';
-
     $c->log_request;
 
-    $c->prepare_action;
-
     return $c;
 }
 
@@ -2105,24 +2178,28 @@ Prepares connection.
 
 sub prepare_connection {
     my $c = shift;
-    $c->engine->prepare_connection( $c, @_ );
+    # XXX - This is called on the engine (not the request) to maintain
+    #       Engine::PSGI back compat.
+    $c->engine->prepare_connection($c);
 }
 
 =head2 $c->prepare_cookies
 
-Prepares cookies.
+Prepares cookies by ensuring that the attribute on the request
+object has been built.
 
 =cut
 
-sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
+sub prepare_cookies { my $c = shift; $c->request->cookies }
 
 =head2 $c->prepare_headers
 
-Prepares headers.
+Prepares request headers by ensuring that the attribute on the request
+object has been built.
 
 =cut
 
-sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
+sub prepare_headers { my $c = shift; $c->request->headers }
 
 =head2 $c->prepare_parameters
 
@@ -2405,7 +2482,7 @@ $c->request.  You must handle all body parsing yourself.
 
 =cut
 
-sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
+sub read { my $c = shift; return $c->request->read( @_ ) }
 
 =head2 $c->run
 
@@ -2415,11 +2492,35 @@ Starts the engine.
 
 sub run {
   my $app = shift;
+  $app->_make_immutable_if_needed;
   $app->engine_loader->needs_psgi_engine_compat_hack ?
     $app->engine->run($app, @_) :
       $app->engine->run( $app, $app->_finalized_psgi_app, @_ );
 }
 
+sub _make_immutable_if_needed {
+    my $class = shift;
+    my $meta = find_meta($class);
+    my $isa_ca = $class->isa('Class::Accessor::Fast') || $class->isa('Class::Accessor');
+    if (
+        $meta->is_immutable
+        && ! { $meta->immutable_options }->{replace_constructor}
+        && $isa_ca
+    ) {
+        warn("You made your application class ($class) immutable, "
+            . "but did not inline the\nconstructor. "
+            . "This will break catalyst, as your app \@ISA "
+            . "Class::Accessor(::Fast)?\nPlease pass "
+            . "(replace_constructor => 1)\nwhen making your class immutable.\n");
+    }
+    unless ($meta->is_immutable) {
+        # XXX - FIXME warning here as you should make your app immutable yourself.
+        $meta->make_immutable(
+            replace_constructor => 1,
+        );
+    }
+}
+
 =head2 $c->set_action( $action, $code, $namespace, $attrs )
 
 Sets an action in a given namespace.
@@ -2590,7 +2691,7 @@ sub setup_dispatcher {
         $dispatcher = $class->dispatcher_class;
     }
 
-    Class::MOP::load_class($dispatcher);
+    load_class($dispatcher);
 
     # dispatcher instance
     $class->dispatcher( $dispatcher->new );
@@ -2640,7 +2741,7 @@ sub setup_engine {
     # Don't really setup_engine -- see _setup_psgi_app for explanation.
     return if $class->loading_psgi_file;
 
-    Class::MOP::load_class($engine);
+    load_class($engine);
 
     if ($ENV{MOD_PERL}) {
         my $apache = $class->engine_loader->auto;
@@ -2652,7 +2753,7 @@ sub setup_engine {
 
         $meta->add_method(handler => sub {
             my $r = shift;
-            my $psgi_app = $class->psgi_app;
+            my $psgi_app = $class->_finalized_psgi_app;
             $apache->call_app($r, $psgi_app);
         });
 
@@ -2664,6 +2765,11 @@ sub setup_engine {
     return;
 }
 
+## This exists just to supply a prebuild psgi app for mod_perl and for the 
+## build in server support (back compat support for pre psgi port behavior).
+## This is so that we don't build a new psgi app for each request when using
+## the mod_perl handler or the built in servers (http and fcgi, etc).
+
 sub _finalized_psgi_app {
     my ($app) = @_;
 
@@ -2675,6 +2781,12 @@ sub _finalized_psgi_app {
     return $app->_psgi_app;
 }
 
+## Look for a psgi file like 'myapp_web.psgi' (if the app is MyApp::Web) in the
+## home directory and load that and return it (just assume it is doing the 
+## right thing :) ).  If that does not exist, call $app->psgi_app, wrap that
+## in default_middleware and return it ( this is for backward compatibility
+## with pre psgi port behavior ).
+
 sub _setup_psgi_app {
     my ($app) = @_;
 
@@ -2743,13 +2855,32 @@ sub apply_default_middlewares {
 
     # If we're running under Lighttpd, swap PATH_INFO and SCRIPT_NAME
     # http://lists.scsys.co.uk/pipermail/catalyst/2006-June/008361.html
-    $psgi_app = Plack::Middleware::LighttpdScriptNameFix->wrap($psgi_app);
+    $psgi_app = Plack::Middleware::Conditional->wrap(
+        $psgi_app,
+        builder   => sub { Plack::Middleware::LighttpdScriptNameFix->wrap($_[0]) },
+        condition => sub {
+            my ($env) = @_;
+            return unless $env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ m!lighttpd[-/]1\.(\d+\.\d+)!;
+            return unless $1 < 4.23;
+            1;
+        },
+    );
 
     # we're applying this unconditionally as the middleware itself already makes
     # sure it doesn't fuck things up if it's not running under one of the right
     # IIS versions
     $psgi_app = Plack::Middleware::IIS6ScriptNameFix->wrap($psgi_app);
 
+    # And another IIS issue, this time with IIS7.
+    $psgi_app = Plack::Middleware::Conditional->wrap(
+        $psgi_app,
+        builder => sub { Plack::Middleware::IIS7KeepAliveFix->wrap($_[0]) },
+        condition => sub {
+            my ($env) = @_;
+            return $env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ m!IIS/7\.[0-9]!;
+        },
+    );
+
     return $psgi_app;
 }
 
@@ -2766,7 +2897,8 @@ reference of your Catalyst application for use in F<.psgi> files.
 
 sub psgi_app {
     my ($app) = @_;
-    return $app->engine->build_psgi_app($app);
+    my $psgi = $app->engine->build_psgi_app($app);
+    return $app->Catalyst::Utils::apply_registered_middleware($psgi);
 }
 
 =head2 $c->setup_home
@@ -2885,21 +3017,42 @@ the plugin name does not begin with C<Catalyst::Plugin::>.
         my ( $proto, $plugin, $instant ) = @_;
         my $class = ref $proto || $proto;
 
-        Class::MOP::load_class( $plugin );
+        load_class( $plugin );
         $class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is deprecated and will not work in 5.81" )
             if $plugin->isa( 'Catalyst::Component' );
-        $proto->_plugins->{$plugin} = 1;
-        unless ($instant) {
+        my $plugin_meta = Moose::Meta::Class->create($plugin);
+        if (!$plugin_meta->has_method('new')
+            && ( $plugin->isa('Class::Accessor::Fast') || $plugin->isa('Class::Accessor') ) ) {
+            $plugin_meta->add_method('new', Moose::Object->meta->get_method('new'))
+        }
+        if (!$instant && !$proto->_plugins->{$plugin}) {
             my $meta = Class::MOP::get_metaclass_by_name($class);
             $meta->superclasses($plugin, $meta->superclasses);
         }
+        $proto->_plugins->{$plugin} = 1;
         return $class;
     }
 
+    sub _default_plugins { return qw(Unicode::Encoding) }
+
     sub setup_plugins {
         my ( $class, $plugins ) = @_;
 
         $class->_plugins( {} ) unless $class->_plugins;
+        $plugins = [ grep {
+            m/Unicode::Encoding/ ? do {
+                $class->log->warn(
+                    'Unicode::Encoding plugin is auto-applied,'
+                    . ' please remove this from your appclass'
+                    . ' and make sure to define "encoding" config'
+                );
+                unless (exists $class->config->{'encoding'}) {
+                  $class->config->{'encoding'} = 'UTF-8';
+                }
+                () }
+                : $_
+        } @$plugins ];
+        push @$plugins, $class->_default_plugins;
         $plugins = Data::OptList::mkopt($plugins || []);
 
         my @plugins = map {
@@ -2912,7 +3065,7 @@ the plugin name does not begin with C<Catalyst::Plugin::>.
          } @{ $plugins };
 
         for my $plugin ( reverse @plugins ) {
-            Class::MOP::load_class($plugin->[0], $plugin->[1]);
+            load_class($plugin->[0], $plugin->[1]);
             my $meta = find_meta($plugin->[0]);
             next if $meta && $meta->isa('Moose::Meta::Role');
 
@@ -2929,6 +3082,139 @@ the plugin name does not begin with C<Catalyst::Plugin::>.
             $class => @roles
         ) if @roles;
     }
+}    
+
+=head2 registered_middlewares
+
+Read only accessor that returns an array of all the middleware in the order
+that they were added (which is the REVERSE of the order they will be applied).
+
+The values returned will be either instances of L<Plack::Middleware> or of a
+compatible interface, or a coderef, which is assumed to be inlined middleware
+
+=head2 setup_middleware (?@middleware)
+
+Read configuration information stored in configuration key C<psgi_middleware> or
+from passed @args.
+
+See under L</CONFIGURATION> information regarding C<psgi_middleware> and how
+to use it to enable L<Plack::Middleware>
+
+This method is automatically called during 'setup' of your application, so
+you really don't need to invoke it.
+
+When we read middleware definitions from configuration, we reverse the list
+which sounds odd but is likely how you expect it to work if you have prior
+experience with L<Plack::Builder> or if you previously used the plugin
+L<Catalyst::Plugin::EnableMiddleware> (which is now considered deprecated)
+
+=cut
+
+sub registered_middlewares {
+    my $class = shift;
+    if(my $middleware = $class->_psgi_middleware) {
+        return @$middleware;
+    } else {
+        die "You cannot call ->registered_middlewares until middleware has been setup";
+    }
+}
+
+sub setup_middleware {
+    my ($class, @middleware_definitions) = @_;
+    push @middleware_definitions, reverse(
+      @{$class->config->{'psgi_middleware'}||[]});
+
+    my @middleware = ();
+    while(my $next = shift(@middleware_definitions)) {
+        if(ref $next) {
+            if(Scalar::Util::blessed $next && $next->can('wrap')) {
+                push @middleware, $next;
+            } elsif(ref $next eq 'CODE') {
+                push @middleware, $next;
+            } elsif(ref $next eq 'HASH') {
+                my $namespace = shift @middleware_definitions;
+                my $mw = $class->Catalyst::Utils::build_middleware($namespace, %$next);
+                push @middleware, $mw;
+            } else {
+              die "I can't handle middleware definition ${\ref $next}";
+            }
+        } else {
+          my $mw = $class->Catalyst::Utils::build_middleware($next);
+          push @middleware, $mw;
+        }
+    }
+
+    $class->_psgi_middleware(\@middleware);
+}
+
+=head2 registered_data_handlers
+
+A read only copy of registered Data Handlers returned as a Hash, where each key
+is a content type and each value is a subref that attempts to decode that content
+type.
+
+=head2 setup_data_handlers (?@data_handler)
+
+Read configuration information stored in configuration key C<data_handlers> or
+from passed @args.
+
+See under L</CONFIGURATION> information regarding C<data_handlers>.
+
+This method is automatically called during 'setup' of your application, so
+you really don't need to invoke it.
+
+=head2 default_data_handlers
+
+Default Data Handlers that come bundled with L<Catalyst>.  Currently there are
+only two default data handlers, for 'application/json' and an alternative to
+'application/x-www-form-urlencoded' which supposed nested form parameters via
+L<CGI::Struct> or via L<CGI::Struct::XS> IF you've installed it.
+
+The 'application/json' data handler is used to parse incoming JSON into a Perl
+data structure.  It used either L<JSON::MaybeXS> or L<JSON>, depending on which
+is installed.  This allows you to fail back to L<JSON:PP>, which is a Pure Perl
+JSON decoder, and has the smallest dependency impact.
+
+Because we don't wish to add more dependencies to L<Catalyst>, if you wish to
+use this new feature we recommend installing L<JSON> or L<JSON::MaybeXS> in
+order to get the best performance.  You should add either to your dependency
+list (Makefile.PL, dist.ini, cpanfile, etc.)
+
+=cut
+
+sub registered_data_handlers {
+    my $class = shift;
+    if(my $data_handlers = $class->_data_handlers) {
+        return %$data_handlers;
+    } else {
+        die "You cannot call ->registered_data_handlers until data_handers has been setup";
+    }
+}
+
+sub setup_data_handlers {
+    my ($class, %data_handler_callbacks) = @_;
+    %data_handler_callbacks = (
+      %{$class->default_data_handlers},
+      %{$class->config->{'data_handlers'}||+{}},
+      %data_handler_callbacks);
+
+    $class->_data_handlers(\%data_handler_callbacks);
+}
+
+sub default_data_handlers {
+    my ($class) = @_;
+    return +{
+      'application/x-www-form-urlencoded' => sub {
+          my ($fh, $req) = @_;
+          my $params = $req->_use_hash_multivalue ? $req->body_parameters->mixed : $req->body_parameters;
+          Class::Load::load_first_existing_class('CGI::Struct::XS', 'CGI::Struct')
+            ->can('build_cgi_struct')->($params);
+      },
+      'application/json' => sub {
+          Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON')
+            ->can('decode_json')->(do { local $/; $_->getline });
+      },
+    };
 }
 
 =head2 $c->stack
@@ -2974,10 +3260,10 @@ your output data, if known.
 sub write {
     my $c = shift;
 
-    # Finalize headers if someone manually writes output
+    # Finalize headers if someone manually writes output (for compat)
     $c->finalize_headers;
 
-    return $c->engine->write( $c, @_ );
+    return $c->response->write( @_ );
 }
 
 =head2 version
@@ -3091,12 +3377,61 @@ is having paths rewritten into it (e.g. as a .cgi/fcgi in a public_html director
 at other URIs than that which the app is 'normally' based at with C<mod_rewrite>), the resolution of
 C<< $c->request->base >> will be incorrect.
 
-=back
+=back 
 
 =item *
 
 C<using_frontend_proxy> - See L</PROXY SUPPORT>.
 
+=item *
+
+C<encoding> - See L</ENCODING>
+
+=item *
+
+C<abort_chain_on_error_fix>
+
+When there is an error in an action chain, the default behavior is to continue
+processing the remaining actions and then catch the error upon chain end.  This
+can lead to running actions when the application is in an unexpected state.  If
+you have this issue, setting this config value to true will promptly exit a
+chain when there is an error raised in any action (thus terminating the chain 
+early.)
+
+use like:
+
+    __PACKAGE__->config(abort_chain_on_error_fix => 1);
+
+In the future this might become the default behavior.
+
+=item *
+
+C<use_hash_multivalue_in_request>
+
+In L<Catalyst::Request> the methods C<query_parameters>, C<body_parametes>
+and C<parameters> return a hashref where values might be scalar or an arrayref
+depending on the incoming data.  In many cases this can be undesirable as it
+leads one to writing defensive code like the following:
+
+    my ($val) = ref($c->req->parameters->{a}) ?
+      @{$c->req->parameters->{a}} :
+        $c->req->parameters->{a};
+
+Setting this configuration item to true will make L<Catalyst> populate the
+attributes underlying these methods with an instance of L<Hash::MultiValue>
+which is used by L<Plack::Request> and others to solve this very issue.  You
+may prefer this behavior to the default, if so enable this option (be warned
+if you enable it in a legacy application we are not sure if it is completely
+backwardly compatible).
+
+=item *
+
+C<psgi_middleware> - See L<PSGI MIDDLEWARE>.
+
+=item *
+
+C<data_handlers> - See L<DATA HANDLERS>.
+
 =back
 
 =head1 INTERNAL ACTIONS
@@ -3188,6 +3523,218 @@ If you plan to operate in a threaded environment, remember that all other
 modules you are using must also be thread-safe. Some modules, most notably
 L<DBD::SQLite>, are not thread-safe.
 
+=head1 DATA HANDLERS
+
+The L<Catalyst::Request> object uses L<HTTP::Body> to populate 'classic' HTML
+form parameters and URL search query fields.  However it has become common
+for various alternative content types to be PUT or POSTed to your controllers
+and actions.  People working on RESTful APIs, or using AJAX often use JSON,
+XML and other content types when communicating with an application server.  In
+order to better support this use case, L<Catalyst> defines a global configuration
+option, C<data_handlers>, which lets you associate a content type with a coderef
+that parses that content type into something Perl can readily access.
+
+    package MyApp::Web;
+    use Catalyst;
+    use JSON::Maybe;
+    __PACKAGE__->config(
+      data_handlers => {
+        'application/json' => sub { local $/; decode_json $_->getline },
+      },
+      ## Any other configuration.
+    );
+    __PACKAGE__->setup;
+
+By default L<Catalyst> comes with a generic JSON data handler similar to the
+example given above, which uses L<JSON::Maybe> to provide either L<JSON::PP>
+(a pure Perl, dependency free JSON parser) or L<Cpanel::JSON::XS> if you have
+it installed (if you want the faster XS parser, add it to you project Makefile.PL
+or dist.ini, cpanfile, etc.)
+
+The C<data_handlers> configuation is a hashref whose keys are HTTP Content-Types
+(matched against the incoming request type using a regexp such as to be case
+insensitive) and whose values are coderefs that receive a localized version of
+C<$_> which is a filehandle object pointing to received body.
+
+This feature is considered an early access release and we reserve the right
+to alter the interface in order to provide a performant and secure solution to
+alternative request body content.  Your reports welcomed!
+
+=head1 PSGI MIDDLEWARE
+
+You can define middleware, defined as L<Plack::Middleware> or a compatible
+interface in configuration.  Your middleware definitions are in the form of an
+arrayref under the configuration key C<psgi_middleware>.  Here's an example
+with details to follow:
+
+    package MyApp::Web;
+    use Catalyst;
+    use Plack::Middleware::StackTrace;
+    my $stacktrace_middleware = Plack::Middleware::StackTrace->new;
+    __PACKAGE__->config(
+      'psgi_middleware', [
+        'Debug',
+        '+MyApp::Custom',
+        $stacktrace_middleware,
+        'Session' => {store => 'File'},
+        sub {
+          my $app = shift;
+          return sub {
+            my $env = shift;
+            $env->{myapp.customkey} = 'helloworld';
+            $app->($env);
+          },
+        },
+      ],
+    );
+    __PACKAGE__->setup;
+
+So the general form is:
+
+    __PACKAGE__->config(psgi_middleware => \@middleware_definitions);
+
+Where C<@middleware> is one or more of the following, applied in the REVERSE of
+the order listed (to make it function similarly to L<Plack::Builder>:
+=over 4
+=item Middleware Object
+An already initialized object that conforms to the L<Plack::Middleware>
+specification:
+    my $stacktrace_middleware = Plack::Middleware::StackTrace->new;
+    __PACKAGE__->config(
+      'psgi_middleware', [
+        $stacktrace_middleware,
+      ]);
+=item coderef
+A coderef that is an inlined middleware:
+    __PACKAGE__->config(
+      'psgi_middleware', [
+        sub {
+          my $app = shift;
+          return sub {
+            my $env = shift;
+            if($env->{PATH_INFO} =~m/forced/) {
+              Plack::App::File
+                ->new(file=>TestApp->path_to(qw/share static forced.txt/))
+                ->call($env);
+            } else {
+              return $app->($env);
+            }
+         },
+      },
+    ]);
+=item a scalar
+We assume the scalar refers to a namespace after normalizing it using the
+following rules:
+
+(1) If the scalar is prefixed with a "+" (as in C<+MyApp::Foo>) then the full string
+is assumed to be 'as is', and we just install and use the middleware.
+
+(2) If the scalar begins with "Plack::Middleware" or your application namespace
+(the package name of your Catalyst application subclass), we also assume then
+that it is a full namespace, and use it.
+
+(3) Lastly, we then assume that the scalar is a partial namespace, and attempt to
+resolve it first by looking for it under your application namespace (for example
+if you application is "MyApp::Web" and the scalar is "MyMiddleware", we'd look
+under "MyApp::Web::Middleware::MyMiddleware") and if we don't find it there, we
+will then look under the regular L<Plack::Middleware> namespace (i.e. for the
+previous we'd try "Plack::Middleware::MyMiddleware").  We look under your application
+namespace first to let you 'override' common L<Plack::Middleware> locally, should
+you find that a good idea.
+
+Examples:
+
+    package MyApp::Web;
+
+    __PACKAGE__->config(
+      'psgi_middleware', [
+        'Debug',  ## MyAppWeb::Middleware::Debug->wrap or Plack::Middleware::Debug->wrap
+        'Plack::Middleware::Stacktrace', ## Plack::Middleware::Stacktrace->wrap
+        '+MyApp::Custom',  ## MyApp::Custom->wrap
+      ],
+    );
+=item a scalar followed by a hashref
+Just like the previous, except the following C<HashRef> is used as arguments
+to initialize the middleware object.
+    __PACKAGE__->config(
+      'psgi_middleware', [
+         'Session' => {store => 'File'},
+    ]);
+
+=back
+
+Please see L<PSGI> for more on middleware.
+
+=head1 ENCODING
+
+On request, decodes all params from encoding into a sequence of
+logical characters. On response, encodes body into encoding.
+
+=head2 Methods
+
+=over 4
+
+=item encoding
+
+Returns an instance of an C<Encode> encoding
+
+    print $c->encoding->name
+
+=item handle_unicode_encoding_exception ($exception_context)
+
+Method called when decoding process for a request fails.
+
+An C<$exception_context> hashref is provided to allow you to override the
+behaviour of your application when given data with incorrect encodings.
+
+The default method throws exceptions in the case of invalid request parameters
+(resulting in a 500 error), but ignores errors in upload filenames.
+
+The keys passed in the C<$exception_context> hash are:
+
+=over
+
+=item param_value
+
+The value which was not able to be decoded.
+
+=item error_msg
+
+The exception received from L<Encode>.
+
+=item encoding_step
+
+What type of data was being decoded. Valid values are (currently)
+C<params> - for request parameters / arguments / captures
+and C<uploads> - for request upload filenames.
+
+=back
+
+=back
+
 =head1 SUPPORT
 
 IRC:
@@ -3225,8 +3772,6 @@ Wiki:
 
 =head2 L<Catalyst::Test> - The test suite.
 
-=begin stopwords
-
 =head1 PROJECT FOUNDER
 
 sri: Sebastian Riedel <sri@cpan.org>
@@ -3317,6 +3862,8 @@ marcus: Marcus Ramberg <mramberg@cpan.org>
 
 miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
 
+mgrimes: Mark Grimes <mgrimes@cpan.org>
+
 mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
 
 mugwump: Sam Vilain
@@ -3361,7 +3908,7 @@ Will Hawes C<info@whawes.co.uk>
 
 willert: Sebastian Willert <willert@cpan.org>
 
-wreis: Wallace Reis <wallace@reis.org.br>
+wreis: Wallace Reis <wreis@cpan.org>
 
 Yuval Kogman, C<nothingmuch@woobling.org>
 
@@ -3369,8 +3916,6 @@ rainboxx: Matthias Dietrich, C<perl@rainboxx.de>
 
 dd070: Dhaval Dhanani <dhaval070@gmail.com>
 
-=end stopwords
-
 =head1 COPYRIGHT
 
 Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS.