You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In Dancer::Route->match, if %+ has any keys in it, then we will consider the route a match:
submatch {
my ($self, $request) = @_;
my$method = lc($request->method);
my$path = $request->path_info;
Dancer::Logger::core(
sprintf"Trying to match '%s%s' against /%s/ (generated from '%s')",
$request->method, $path, $self->{_compiled_regexp}, $self->pattern
);
my@values = $path =~ $self->{_compiled_regexp};
Dancer::Logger::core(" --> got ".
map { defined$_ ? $_ : 'undef' } @values)
if@values;
# if some named captures found, return captures# no warnings is for perl < 5.10if (my%captures =
do { no warnings; %+ }
)
{
Dancer::Logger::core(
" --> captures are: " . join(", ", keys(%captures)))
ifkeys%captures;
return$self->save_match_data($request, {captures=> \%captures});
}
returnunless@values;
# save the route pattern that matched
Note that, if %+ had keys, then we'll call return $self->save_match_data($request, {captures => \%captures});before checking if the route actually matched.
But, %+ only gets cleared after a successful match, so it's not safe to rely on it without first checking that the regex did match.
It may be as simple as moving the return unless @values; up a little so it's checked before looking at %+.
We should also confirm whether this is present in Dancer2.
I've looked at Dancer2, and it won't have this problem, because in Dancer2::Core::Route->match we check for the match first:
submatch {
my ( $self, $request ) = @_;
if ( $self->has_options ) {
returnunless$self->validate_options($request);
}
my@values = $request->path =~ $self->regexp;
returnunless@values;
# if some named captures are found, return captures# no warnings is for perl < 5.10# - Note no @values implies no named capturesif (my%captures =
do { no warnings; %+ }
)
{
return$self->_match_data( { captures=> \%captures } );
}
...
So, that backs up the "just return unless @values before looking at %+" idea.
This is for Issue #1187.
It's not safe to look at `%+` without first having checked whether the regex
matched successfully or not. Otherwise, we might see keys from a previous regex
match, because `%+` is only cleared after a successful match.
(perldoc perlvar confirms, "Note: "%-" and "%+" are tied views into a common
internal hash associated with the last successful regular expression.")
Dancer2 doesn't have problems here, as it already returns immediately if the
regex didn't match, the same way this change does.
Note: I think this would only happen via certain deployment methods, and if
there was an earlier route which used named captures.
In particular, we never had any problems in our large API app's comprehensive
test suite when we used Dancer::Test. We've re-worked our testing framework to
use Plack::Test, partially in readyness to switch to Dancer2, and started
getting weird failures which were tracked down to incorrect route matching, and
this was the cause.
In
Dancer::Route->match
, if%+
has any keys in it, then we will consider the route a match:Note that, if
%+
had keys, then we'll callreturn $self->save_match_data($request, {captures => \%captures});
before checking if the route actually matched.But,
%+
only gets cleared after a successful match, so it's not safe to rely on it without first checking that the regex did match.It may be as simple as moving the
return unless @values;
up a little so it's checked before looking at%+
.We should also confirm whether this is present in Dancer2.
Found by a colleague, @skington.
The text was updated successfully, but these errors were encountered: