我想访问资源标识符包含特殊字符的Restful API中的资源。我因此url_encoding标识符,但我在Mojolicious中为占位符获得了不一致的自动解码行为。
以下是测试一个简单资源标识符的测试脚本,一个包含空格,一个包含加号,另一个包含斜杠。在发送我的请求之前,我正在编写其中的每一个,但是第二个因为不同的原因而失败。
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10;
use Data::Dump qw(pp);
use Mojolicious::Lite;
use Mojo::UserAgent;
use Test::Exception;
use Test::More;
use URL::Encode qw(url_encode url_decode);
use WWW::Mechanize;
# Case 1: Access a resource using Standard Placeholders
get '/my/app/standard_placeholder/:id' => sub {
my $c = shift;
my $id_raw = $c->stash('id');
my $id_decoded = url_decode($id_raw);
$c->render( json => { raw => $id_raw, decoded => $id_decoded } );
};
# Shut the server down.
get '/my/api/shutdown' => sub {
exit 0;
};
# Fork for Client and Server
if ( my $pid = fork ) {
note "Waiting for the server to start";
sleep 2;
run_test();
# Clean up server process and we’re done
waitpid( $pid, 0 );
} else {
local @ARGV = qw(daemon);
app->log( Mojo::Log->new( path => "$0.log", level => 'debug' ) );
app->start;
}
exit 0;
### Client
sub run_test {
plan tests => 2;
my $ua = Mojo::UserAgent->new();
my $server_url = 'http://127.0.0.1:3000';
# Standard Placeholders: ([^/.]+)
# Relaxed Placeholders: ([^/]+)
# Wildcard Placeholders: (.+)
subtest 'Standard Placeholders testing url_encoding of route identifiers' => sub {
my @ids = (
"foobar", #
"a space",
"a+plus",
"a/slash",
);
plan tests => 3 * @ids;
for my $id (@ids) {
my $id_encoded = url_encode($id);
my $tx = $ua->get("$server_url/my/app/standard_placeholder/$id_encoded");
SKIP: {
is( $tx->res->code, 200, "Fetch Resource at " . pp($id) )
or skip "Error in response", 2;
is( $tx->res->json->{raw}, $id_encoded, "json->{raw} eq " . pp($id_encoded) );
is( $tx->res->json->{decoded}, $id, "json->{decoded} eq " . pp($id) );
}
}
};
subtest 'Shutdown the server' => sub {
plan tests => 2;
dies_ok {
my $mech = WWW::Mechanize->new( timeout => 3 );
$mech->get("$server_url/my/api/shutdown");
}
'shutdown occurred';
like $@, qr{Error GETing .*?shutdown: Server closed connection without sending any data back},
'detected closed connection';
};
}
1;
输出:
mhall@dev19:~$ ./mojo_placeholders.pl
# Waiting for the server to start
Server available at http://127.0.0.1:3000
1..2
# Subtest: Standard Placeholders testing url_encoding of route identifiers
1..12
ok 1 - Fetch Resource at "foobar"
ok 2 - json->{raw} eq "foobar"
ok 3 - json->{decoded} eq "foobar"
ok 4 - Fetch Resource at "a space"
ok 5 - json->{raw} eq "a+space"
ok 6 - json->{decoded} eq "a space"
ok 7 - Fetch Resource at "a+plus"
not ok 8 - json->{raw} eq "a%2Bplus"
# Failed test 'json->{raw} eq "a%2Bplus"'
# at ./mojo_placeholders.pl line 89.
# got: 'a+plus'
# expected: 'a%2Bplus'
not ok 9 - json->{decoded} eq "a+plus"
# Failed test 'json->{decoded} eq "a+plus"'
# at ./mojo_placeholders.pl line 90.
# got: 'a plus'
# expected: 'a+plus'
not ok 10 - Fetch Resource at "a/slash"
# Failed test 'Fetch Resource at "a/slash"'
# at ./mojo_placeholders.pl line 85.
# got: '404'
# expected: '200'
ok 11 # skip Error in response
ok 12 # skip Error in response
# Looks like you failed 3 tests of 12.
not ok 1 - Standard Placeholders testing url_encoding of route identifiers
# Failed test 'Standard Placeholders testing url_encoding of route identifiers'
# at ./mojo_placeholders.pl line 93.
# Subtest: Shutdown the server
1..2
ok 1 - shutdown occurred
ok 2 - detected closed connection
ok 2 - Shutdown the server
# Looks like you failed 1 test of 2.
有关如何处理此事的任何建议?
答案 0 :(得分:2)
所以这里有几件事情。首先,/
vs %2F
通常是一件非常令人担忧的事情。您可以在https://groups.google.com/forum/#!topic/python-web-sig/IAPhwezOJ7I阅读一个有趣的主题,并注意到Mojolicious本身就路径遍历的潜力https://www.cvedetails.com/cve/CVE-2011-1589/发出了CVE。也就是说,如果您使用通配符占位符,您仍然可以在占位符中恢复/
。最后你的测试(虽然我确定功能)不使用Mojolicious测试设备,这将避免你的大部分架构,为更多的测试留出空间。这是我的快速清理。
#!/usr/bin/env perl
use Mojo::Base -strict;
use Mojolicious::Lite;
use Mojo::Util qw(url_escape url_unescape);
use Test::More;
use Test::Mojo;
my $cb = sub {
my $c = shift;
my $id_raw = $c->stash('id');
my $id_decoded = url_unescape $id_raw;
$c->render( json => { raw => $id_raw, decoded => $id_decoded } );
};
get '/standard/:id' => $cb;
get '/relaxed/#id' => $cb;
get '/wildcard/*id' => $cb;
# Standard Placeholders: ([^/.]+)
# Relaxed Placeholders: ([^/]+)
# Wildcard Placeholders: (.+)
my $t = Test::Mojo->new;
my @ids = (
"foobar",
"a space",
"a+plus",
"a/slash",
);
plan tests => 3;
for my $type (qw/standard relaxed wildcard/) {
subtest "Type $type" => sub {
plan tests => 4 * @ids;
for my $id (@ids) {
my $id_encoded = url_escape $id;
$t->get_ok("/$type/$id_encoded")
->status_is(200)
->json_is('/raw', $id_encoded, "$type raw test for $id_encoded")
->json_is('/decoded', $id, "$type decoded test for $id");
}
};
}
我没有更正你的测试,只是将它们移植到书面上(并扩展了所有三种占位符类型)。