use Catalyst::Utils;
use Text::SimpleTable;
use Tree::Simple;
-use Tree::Simple::Visitor::FindByPath;
+use Class::Load qw(load_class try_load_class);
+use Encode 2.21 'decode_utf8';
use namespace::clean -except => 'meta';
}
else {
my $path = $c->req->path;
+ $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
+ $path = decode_utf8($path);
+
my $error = $path
? qq/Unknown resource "$path"/
: "No default action defined";
sub forward {
my $self = shift;
no warnings 'recursion';
- $self->_do_forward(forward => @_);
+ return $self->_do_forward(forward => @_);
}
sub _do_forward {
no warnings 'recursion';
$action->dispatch( $c );
+ #If there is an error, all bets off regarding state. Documentation
+ #Specifies that when you forward, if there's an error you must expect
+ #state to be 0.
+ if( @{ $c->error }) {
+ $c->state(0);
+ }
return $c->state;
}
sub detach {
my ( $self, $c, $command, @args ) = @_;
$self->_do_forward(detach => $c, $command, @args ) if $command;
+ $c->state(0); # Needed in order to skip any auto functions
Catalyst::Exception::Detach->throw;
}
s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg for grep { defined } @{$req->captures||[]};
- $c->log->debug( 'Path is "' . $req->match . '"' )
- if ( $c->debug && defined $req->match && length $req->match );
+ if($c->debug && defined $req->match && length $req->match) {
+ my $match = $req->match;
+ $match =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
+ $match = decode_utf8($match);
+ $c->log->debug( 'Path is "' . $match . '"' )
+ }
- $c->log->debug( 'Arguments are "' . join( '/', @args ) . '"' )
+ $c->log->debug( 'Arguments are "' . join( '/', map { decode_utf8 $_ } @args ) . '"' )
if ( $c->debug && @args );
}
-=head2 $self->get_action( $action, $namespace )
+=head2 $self->get_action( $action_name, $namespace )
-returns a named action from a given namespace.
+returns a named action from a given namespace. C<$action_name>
+may be a relative path on that C<$namespace> such as
+
+ $self->get_action('../bar', 'foo/baz');
+
+In which case we look for the action at 'foo/bar'.
=cut
$namespace = join( "/", grep { length } split '/', ( defined $namespace ? $namespace : "" ) );
- return $self->_action_hash->{"${namespace}/${name}"};
+ return $self->get_action_by_path("${namespace}/${name}");
}
=head2 $self->get_action_by_path( $path );
Returns the named action by its full private path.
+This method performs some normalization on C<$path> so that if
+it includes '..' it will do the right thing (for example if
+C<$path> is '/foo/../bar' that is normalized to '/bar'.
+
=cut
sub get_action_by_path {
my ( $self, $path ) = @_;
+ $path =~s/[^\/]+\/\.\.\/// while $path=~m/[^\/]+\/\.\.\//;
$path =~ s/^\///;
$path = "/$path" unless $path =~ /\//;
$self->_action_hash->{$path};
unless ( $registered->{$class} ) {
# FIXME - Some error checking and re-throwing needed here, as
# we eat exceptions loading dispatch types.
- eval { Class::MOP::load_class($class) };
+ # see also try_load_class
+ eval { load_class($class) };
my $load_failed = $@;
- $self->_check_depreciated_dispatch_type( $key, $load_failed );
+ $self->_check_deprecated_dispatch_type( $key, $load_failed );
push( @{ $self->dispatch_types }, $class->new ) unless $load_failed;
$registered->{$class} = 1;
}
$self->_load_dispatch_types( @{ $self->preload_dispatch_types } );
@{ $self->_registered_dispatch_types }{@classes} = (1) x @classes;
- foreach my $comp ( values %{ $c->components } ) {
+ foreach my $comp ( map @{$_}{sort keys %$_}, $c->components ) {
+ $comp = $comp->() if ref($comp) eq 'CODE';
$comp->register_actions($c) if $comp->can('register_actions');
}
# first param is undef because we cannot get the appclass
my $class = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $type);
- eval { Class::MOP::load_class($class) };
- Catalyst::Exception->throw( message => qq/Couldn't load "$class"/ )
- if $@;
+ my ($success, $error) = try_load_class($class);
+ Catalyst::Exception->throw( message => $error ) if not $success;
push @{ $self->dispatch_types }, $class->new;
push @loaded, $class;
return undef;
}
-sub _check_depreciated_dispatch_type {
+sub _check_deprecated_dispatch_type {
my ($self, $key, $load_failed) = @_;
return unless $key =~ /^(Local)?Regexp?/;
. " Use Chained methods or install the standalone\n"
. " Catalyst::DispatchType::Regex if necessary.\n" );
} elsif ( !defined $Catalyst::DispatchType::Regex::VERSION
- || $Catalyst::DispatchType::Regex::VERSION <= 5.90020 ) {
+ || $Catalyst::DispatchType::Regex::VERSION le '5.90020' ) {
# We loaded the old core version of the Regex module this will break
warn( "The $key DispatchType has been removed from Catalyst core.\n"
. " An old version of the core Catalyst::DispatchType::Regex\n"
. " has been loaded and will likely fail. Please remove\n"
- . " $INC{'Catalyst::DispatchType::Regex'}\n"
+ . " $INC{'Catalyst/DispatchType/Regex.pm'}\n"
. " and use Chained methods or install the standalone\n"
. " Catalyst::DispatchType::Regex if necessary.\n" );
}