use Plack::Middleware::Head;
use Plack::Middleware::HTTPExceptions;
use Plack::Middleware::FixMissingBodyInRedirect;
+use Plack::Middleware::MethodOverride;
+use Plack::Middleware::RemoveRedundantBody;
use Plack::Util;
use Class::Load 'load_class';
# Remember to update this in Catalyst::Runtime as well!
-our $VERSION = '5.90059_004';
+our $VERSION = '5.90069_001';
sub import {
my ( $class, @arguments ) = @_;
$c->error(0);
}
+=head2 $c->has_errors
+
+Returns true if you have errors
+
+=cut
+
+sub has_errors { scalar(@{shift->error}) ? 1:0 }
+
sub _comp_search_prefixes {
my $c = shift;
return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_);
$class->setup_log( delete $flags->{log} );
$class->setup_plugins( delete $flags->{plugins} );
- # 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;
- }
-
- $class->setup_middleware();
$class->setup_data_handlers();
$class->setup_dispatcher( delete $flags->{dispatcher} );
if (my $engine = delete $flags->{engine}) {
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;
+ }
+
+ $class->setup_middleware();
+
# Initialize our data structure
$class->components( {} );
}
$class->setup_finalize;
- # Should be the last thing we do so that user things hooking
- # setup_finalize can log..
+
+ # Flush the log for good measure (in case something turned off 'autoflush' early)
$class->log->_flush() if $class->log->can('_flush');
- return 1; # Explicit return true as people have __PACKAGE__->setup as the last thing in their class. HATE.
+
+ return $class || 1; # Just in case someone named their Application 0...
}
=head2 $app->setup_finalize
my $last = pop( @{ $c->stack } );
if ( my $error = $@ ) {
+ #rethow if this can be handled by middleware
+ if(blessed $error && ($error->can('as_psgi') || $error->can('code'))) {
+ foreach my $err (@{$c->error}) {
+ $c->log->error($err);
+ }
+ $c->clear_errors;
+ $c->log->_flush if $c->log->can('_flush');
+
+ $error->can('rethrow') ? $error->rethrow : croak $error;
+ }
if ( blessed($error) and $error->isa('Catalyst::Exception::Detach') ) {
$error->rethrow if $c->depth > 1;
}
=head2 $c->finalize_error
-Finalizes error.
+Finalizes error. If there is only one error in L</error> and it is an object that
+does C<as_psgi> or C<code> we rethrow the error and presume it caught by middleware
+up the ladder. Otherwise we return the debugging error page (in debug mode) or we
+return the default error page (production mode).
=cut
# In the case where the error 'knows what it wants', becauses its PSGI
# aware, just rethow and let middleware catch it
$error->can('rethrow') ? $error->rethrow : croak $error;
- croak $error;
} else {
$c->engine->finalize_error( $c, @_ )
}
# Remove incorrectly added body and content related meta data when returning
# an information response, or a response the is required to not include a body
- if ( $response->status =~ /^(1\d\d|[23]04)$/ ) {
- if($response->has_body) {
- $c->log->debug('Removing body for informational or no content http responses');
- $response->body('');
- $response->headers->remove_header("Content-Length");
- }
- }
-
$c->finalize_cookies;
$c->response->finalize_headers();
$c->dispatch;
$status = $c->finalize;
} catch {
- chomp(my $error = $_);
- $class->log->error(qq/Caught exception in engine "$error"/);
#rethow if this can be handled by middleware
- if(blessed $error && ($error->can('as_psgi') || $error->can('code'))) {
- $error->can('rethrow') ? $error->rethrow : croak $error;
+ if(blessed $_ && ($_->can('as_psgi') || $_->can('code'))) {
+ $_->can('rethrow') ? $_->rethrow : croak $_;
}
+ chomp(my $error = $_);
+ $class->log->error(qq/Caught exception in engine "$error"/);
};
$COUNT++;
my $class = shift;
my $config = shift;
- my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
+ my @paths = qw( ::M ::Model ::V ::View ::C ::Controller );
my $extra = delete $config->{ search_extra } || [];
- push @paths, @$extra;
-
- my $locator = Module::Pluggable::Object->new(
- search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
- %$config
- );
+ unshift @paths, @$extra;
- # XXX think about ditching this sort entirely
- my @comps = sort { length $a <=> length $b } $locator->plugins;
+ my @comps = map { sort { length($a) <=> length($b) } Module::Pluggable::Object->new(
+ search_path => [ map { s/^(?=::)/$class/; $_; } ($_) ],
+ %$config
+ )->plugins } @paths;
return @comps;
}
experience with L<Plack::Builder> or if you previously used the plugin
L<Catalyst::Plugin::EnableMiddleware> (which is now considered deprecated)
+So basically your middleware handles an incoming request from the first
+registered middleware, down and handles the response from the last middleware
+up.
+
=cut
sub registered_middlewares {
if(my $middleware = $class->_psgi_middleware) {
return (
Plack::Middleware::HTTPExceptions->new,
+ Plack::Middleware::RemoveRedundantBody->new,
Plack::Middleware::FixMissingBodyInRedirect->new,
Plack::Middleware::ContentLength->new,
+ Plack::Middleware::MethodOverride->new,
Plack::Middleware::Head->new,
@$middleware);
} else {
sub setup_middleware {
my $class = shift;
my @middleware_definitions = @_ ?
- @_ : reverse(@{$class->config->{'psgi_middleware'}||[]});
+ reverse(@_) : reverse(@{$class->config->{'psgi_middleware'}||[]});
my @middleware = ();
while(my $next = shift(@middleware_definitions)) {
=back
+=head1 EXCEPTIONS
+
+Generally when you throw an exception inside an Action (or somewhere in
+your stack, such as in a model that an Action is calling) that exception
+is caught by Catalyst and unless you either catch it yourself (via eval
+or something like L<Try::Tiny> or by reviewing the L</error> stack, it
+will eventually reach L</finalize_errors> and return either the debugging
+error stack page, or the default error page. However, if your exception
+can be caught by L<Plack::Middleware::HTTPExceptions>, L<Catalyst> will
+instead rethrow it so that it can be handled by that middleware (which
+is part of the default middleware). For example this would allow
+
+ use HTTP::Throwable::Factory 'http_throw';
+
+ sub throws_exception :Local {
+ my ($self, $c) = @_;
+
+ http_throw(SeeOther => { location =>
+ $c->uri_for($self->action_for('redirect')) });
+
+ }
+
=head1 INTERNAL ACTIONS
Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
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
+The C<data_handlers> configuration 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.
Ulf Edvinsson
+vanstyn: Henry Van Styn <vanstyn@cpan.org>
+
Viljo Marrandi C<vilts@yahoo.com>
Will Hawes C<info@whawes.co.uk>
=head1 COPYRIGHT
-Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS.
+Copyright (c) 2005-2014, the above named PROJECT FOUNDER and CONTRIBUTORS.
=head1 LICENSE