From: John Napiorkowski Date: Thu, 26 Mar 2015 20:13:24 +0000 (-0500) Subject: make sure we can properly do utf8 constraints X-Git-Tag: 5.90089_002~20 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=commitdiff_plain;h=d2b583c3793b7ccf5ac228206c2fdad9bf7593aa make sure we can properly do utf8 constraints --- diff --git a/Changes b/Changes index 3bcb925..70cbe01 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ URL matches the defined args. - New top level document on Route matching. (Catalyst::RouteMatching). This document is still in development, but is worth review and comments, please! + - uri_for now does more aggressing testing and warning if your args and captures + do not match expected number and type. 5.90085 - 2015-03-25 - Small change to Catalyst::Action to prevent autovivication of Args value (dim1++) diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 576f0c4..20595e0 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -1447,6 +1447,10 @@ In general the scheme of the generated URI object will follow the incoming reque however if your targeted action or action chain has the Scheme attribute it will use that instead. +Also, if the targeted Action or Action chain declares Args/CaptureArgs that have +type constraints, we will require that your proposed URL verify on those declared +constraints. + =cut sub uri_for { @@ -1469,15 +1473,17 @@ sub uri_for { foreach my $arg (@args) { if(ref($arg)||'' eq 'ARRAY') { push @encoded_args, [map { - my $encoded = encode_utf8 $_; - $encoded =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; - $encoded; + # my $encoded = encode_utf8 $_; + # $encoded =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; + # $encoded; + $_ } @$arg]; } else { push @encoded_args, do { - my $encoded = encode_utf8 $arg; - $encoded =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; - $encoded; + # my $encoded = encode_utf8 $arg; + # $encoded =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; + # $encoded; + $arg; } } } @@ -1492,7 +1498,7 @@ sub uri_for { my $action = $path; my $expanded_action = $c->dispatcher->expand_action( $action ); - my $num_captures = $expanded_action->number_of_captures; + my $num_captures = $expanded_action->number_of_captures; # ->uri_for( $action, \@captures_and_args, \%query_values? ) if( !@encoded_args && $action->number_of_args ) { @@ -1501,7 +1507,7 @@ sub uri_for { if($num_captures) { unless($expanded_action->match_captures($c, $captures)) { - carp "captures [@{$captures}] do not match the type constraints in action '$action'"; + carp "captures [@{$captures}] do not match the type constraints in actionchain ending with '$action'"; return; } } @@ -1583,8 +1589,10 @@ sub uri_for { } @keys); } - #warn $base; - #warn $args; + $base = encode_utf8 $base; + $base =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; + $args = encode_utf8 $args; + $args =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; my $res = bless(\"${base}${args}${query}", $class); $res; diff --git a/t/arg_constraints.t b/t/arg_constraints.t index e948dee..8bfa085 100644 --- a/t/arg_constraints.t +++ b/t/arg_constraints.t @@ -1,6 +1,7 @@ use warnings; use strict; use HTTP::Request::Common; +use utf8; BEGIN { use Test::More; @@ -20,7 +21,7 @@ BEGIN { use Types::Standard -types; use Type::Library -base, - -declare => qw( UserId User ContextLike ); + -declare => qw( UserId Heart User ContextLike ); extends "Types::Standard"; @@ -31,6 +32,10 @@ BEGIN { as Int, where { $_ < 5 }; + declare Heart, + as Str, + where { $_ eq '♥' }; + # Tests using this are skipped pending deeper thought coerce User, from ContextLike, @@ -61,7 +66,7 @@ BEGIN { use Moose; use MooseX::MethodAttributes; - use MyApp::Types qw/Tuple Int Str StrMatch ArrayRef UserId User/; + use MyApp::Types qw/Tuple Int Str StrMatch ArrayRef UserId User Heart/; extends 'Catalyst::Controller'; @@ -151,6 +156,11 @@ BEGIN { sub chained_zero3 : Chained(chain_base2) PathPart('') Args(1) { $_[1]->res->body('chained_zero3') } + sub heart :Local Args(Heart) { } + + sub utf8_base :Chained(/) CaptureArgs(Heart) { } + sub utf8_end :Chained(utf8_base) PathPart('') Args(Heart) { } + sub default :Default { my ($self, $c, $int) = @_; $c->res->body('default'); @@ -409,12 +419,24 @@ SKIP: { ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a','a',3,4,4,'6']) }; } -} - -done_testing; + { + ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('heart'), ['♥']) }; + is $url, 'http://localhost/heart/%E2%99%A5'; + } + { + ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('heart'), ['1']) }; + } -__END__ + { + ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('utf8_end'), ['♥','♥']) }; + is $url, 'http://localhost/utf8_base/%E2%99%A5/%E2%99%A5'; + } + { + ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('utf8_end'), ['2','1']) }; + } +} +done_testing;