Skip to content

#221 uri encoding fixes #276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f5ae7c5
Initial S3 stabilisation tests - URI encoding
castaway Jun 13, 2018
b74df33
Initial S3 stabilisation tests - URI encoding
castaway Jun 13, 2018
461f289
Add "uri other chars" test
castaway Jun 14, 2018
76a3c9a
Merge branch 'tests/stabilisation' of https://github.com/shadow-dot-c…
castaway Jun 14, 2018
89ab3c2
Bump to 0.39
pplu Jun 18, 2018
b5e184e
Verify contentmd5 headers are sent for S3 methods that require them
castaway Jun 19, 2018
ff61959
Fix submodule version
piratefinn Jun 19, 2018
31e9522
Add mock caller which does not generate a response (we are only testi…
castaway Jun 20, 2018
8db823b
Merge branch 'tests/responseless_mock' into tests/stabilisation
castaway Jun 20, 2018
ac1db95
Merge remote-tracking branch 'refs/remotes/shadow-dot-cat/tests/respo…
piratefinn Jun 20, 2018
26a4684
initial non-functional header test
piratefinn Jun 20, 2018
0c0ce2a
fixed service name
piratefinn Jun 20, 2018
2eade6d
Amend Request s3 tests to use TestRequestCaller
castaway Jun 21, 2018
ec86cc8
Use official test bucketname
castaway Jun 21, 2018
4951696
Merge remote-tracking branch 'shadow-dot-cat/tests/stabilisation' int…
piratefinn Jun 21, 2018
b47d8b2
added rest of tests
piratefinn Jun 21, 2018
dd26694
fixed typo
piratefinn Jun 21, 2018
4028918
fixed wrong syntax
piratefinn Jun 21, 2018
18c4d84
moved some tested subs so they error again
piratefinn Jun 21, 2018
eeb82e8
Added TODO for code that is breaking test
piratefinn Jun 26, 2018
b32ddf3
Add Route53 XML generation tests
castaway Jun 26, 2018
f484e4c
TODOify the stabilisation tests
castaway Jun 26, 2018
4d9c3c0
Initial working URI test
piratefinn Jun 26, 2018
0b25331
Added test for uri that does not use locationName override
piratefinn Jun 26, 2018
15eed02
Removed Dwarn
piratefinn Jun 26, 2018
69cf465
TODOify s3 header tests
castaway Jun 26, 2018
d83d880
Test all things, even the subdirs
castaway Jun 26, 2018
3609b95
Revert "Added TODO for code that is breaking test"
piratefinn Jun 26, 2018
e263be7
added some TODO and eval to allow the test to finish
piratefinn Jun 27, 2018
c73dcf1
cleaned test to fail nicer
piratefinn Jun 27, 2018
0897bfe
More test tidying (diag not warn)
castaway Jun 27, 2018
fc83643
added extra test case
piratefinn Jun 27, 2018
f30952d
switched out tested URL with one not using XML
piratefinn Jun 27, 2018
93eb446
re-added breaking test ChangeTagsForResource
piratefinn Jun 27, 2018
6fa947e
Added breaking test case to xml_creation test
piratefinn Jun 27, 2018
f2a681e
Made RestXmlCaller more sane, partially fixing issue
piratefinn Jun 27, 2018
0048de0
minor test changes, POINTS OUT AUTO-LIB GENERATION CHANGE
piratefinn Jun 27, 2018
07b8b79
Merge branch 'test/stabilisation-glacier' into tests/stabilisation
piratefinn Jun 28, 2018
af9fb3c
Merge branch 'test/route53-url' into tests/stabilisation
piratefinn Jun 28, 2018
9da7bfd
reverted change due to being generated code
piratefinn Jun 28, 2018
d120dc2
reverting change to move to a new PR
piratefinn Jun 28, 2018
83a8033
Add tests to verify that InitiateMultipartUpload returns an UploadId …
castaway Jul 3, 2018
6752127
Test for S3 CreateMultipartUpload #92
castaway Jul 3, 2018
8480411
Add tests for the rest of S3 multipart upload #244
castaway Jul 4, 2018
6a77fe7
Prefix test for #171 #244
castaway Jul 4, 2018
a525999
Ensure that we don't encode "/" in S3 Key values
castaway Jul 4, 2018
6680634
No double-encoding of URI params in rest-xml; using new URI::Template
castaway Jul 11, 2018
902805b
Throw an exception if unusable characters are submitted in URI elements
castaway Jul 11, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
0.39
- API updates for any service up to the date of release

0.38 19 Jun 2018
- Fix test suite so that credentials_process tests don't need extra modules (#251, #248)
- API updates for any service up to the date of release
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test:
carton exec -- prove -v -I lib -I auto-lib t/
carton exec -- prove -r -v -I lib -I auto-lib t/

pod-test:
for i in `find auto-lib/Paws/ -name \*.pm`; do podchecker $$i; done;
Expand Down
2 changes: 1 addition & 1 deletion auto-lib/Paws.pm
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ __PACKAGE__->meta->make_immutable;

package Paws;

our $VERSION = '0.38';
our $VERSION = '0.39';

use Moose;
use MooseX::ClassAttribute;
Expand Down
3 changes: 1 addition & 2 deletions auto-lib/Paws/Route53/ChangeTagsForResource.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ package Paws::Route53::ChangeTagsForResource;
class_has _api_method => (isa => 'Str', is => 'ro', default => 'POST');
class_has _returns => (isa => 'Str', is => 'ro', default => 'Paws::Route53::ChangeTagsForResourceResponse');
class_has _result_key => (isa => 'Str', is => 'ro');

1;

### main pod documentation begin ###
Expand Down Expand Up @@ -110,4 +110,3 @@ The source code is located here: L<https://github.com/pplu/aws-sdk-perl>
Please report bugs to: L<https://github.com/pplu/aws-sdk-perl/issues>

=cut

2 changes: 1 addition & 1 deletion builder-lib/Paws/API/Builder/Paws.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package Paws::API::Builder::Paws {
use Moose;

sub version {
'0.38';
'0.39';
}

sub services {
Expand Down
2 changes: 1 addition & 1 deletion cpanfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ requires 'DateTime';
requires 'DateTime::Format::ISO8601';
requires 'URL::Encode';
requires 'URL::Encode::XS';
requires 'URI::Template';
requires 'URI::Template' => '0.23';
requires 'Config::INI';
requires 'Digest::SHA';
# For the paws CLI
Expand Down
7 changes: 4 additions & 3 deletions examples/s3-common-methods.pl
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
use Paws;

my $service = 'S3';
my $region = 'us-east-1';
my $bucketname = 'paws-test-bucket';
# my $region = 'us-east-1';
my $region = 'us-west-2';
my $bucketname = 'shadowcatjesstest';
my $test_dir = 'uploads/test_';


Expand Down Expand Up @@ -46,7 +47,7 @@
$response = $s3->CreateBucket(
Bucket => $bucketname,
CreateBucketConfiguration => {
LocationConstraint => 'eu-west-1',
LocationConstraint => 'us-west-2',
},
);
p $response;
Expand Down
2 changes: 2 additions & 0 deletions lib/Paws/Net/Caller.pm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package Paws::Net::Caller;
# HTTP::Tiny derives the Host header from the URL. It's an error to set it.
delete $headers->{Host};

# print STDERR Data::Dumper::Dumper($requestObj);
my $response = $self->ua->request(
$requestObj->method,
$requestObj->url,
Expand All @@ -30,6 +31,7 @@ package Paws::Net::Caller;
(defined $requestObj->content)?(content => $requestObj->content):(),
}
);
print STDERR Data::Dumper::Dumper($response);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a Data::Dumper print in

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this has been fixed long ago as 42 does not show the behaviour.

If you are in doupt try this branch all the S3 commands are working there

https://github.com/byterock/aws-sdk-perl/tree/s3ObjectTagging

Copy link
Contributor

@dheffx dheffx Jan 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I was mistaken by this pull request still being open if it is supposedly fixed in 0.42 release? I don't know.
I cloned both the pplu/aws-sdk-perl branch of release/0.42 and your fork's s3ObjectTagging branch and I still run into URI encoding issues, namely related to the = symbol in S3 object keys. I guess I should open a separate ticket/pull request for that.

i.e. Key = client=TEST/year=2020/month=01/day=02/test.txt'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be good

you would help me alot if you ran it against the s3ObjectTagging branch as well.
Though I do not think I have touched the 'Paws::Net::Caller' class in my branch.

Any of the S3 commands that run though the RestXml callers and responders have been fixed up.

Hopefully there will be a relase that will get things a little more stable.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so a doc or bucket key like this

TEST/year=2020/month=01/day=02/test.txt

well have a look and see what happens

not a very good name for a bucket ;) but that is not my call

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the recommended way to prefix object keys in order to get out of the box Hive-partitioning in S3.
https://docs.aws.amazon.com/glue/latest/dg/aws-glue-programming-etl-partitions.html

return Paws::Net::APIResponse->new(
status => $response->{status},
content => $response->{content},
Expand Down
10 changes: 9 additions & 1 deletion lib/Paws/Net/FileMockCaller.pm
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,19 @@ package Paws::Net::FileMockCaller;
default => sub { shift->file_contents->{ request }->{ params } }
);

has actual_request => (
is => 'rw',
isa => 'Object',
lazy => 1,
default => sub { '' },
);

has _encoder => (is => 'ro', default => sub { JSON::MaybeXS->new(canonical => 1) });

sub send_request {
my ($self, $service, $call_object) = @_;

$self->actual_request($service->prepare_request_for_call($call_object));
my $actual_call = $self->_encoder->encode($service->to_hash($call_object));
my $recorded_call = $self->_encoder->encode($self->params);

Expand All @@ -92,7 +100,7 @@ package Paws::Net::FileMockCaller;

sub caller_to_response {
my ($self, $service, $call_object, $response) = @_;

return $self->real_caller->caller_to_response($service, $call_object, $response);
};

Expand Down
108 changes: 64 additions & 44 deletions lib/Paws/Net/MockCaller.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package Paws::Net::MockCaller;
use Moose::Util::TypeConstraints;
use Path::Tiny;
use Paws::Net::FileMockCaller;
use Paws::Net::NoResponseMockCaller;

has real_caller => (
is => 'ro',
Expand All @@ -18,17 +19,25 @@ package Paws::Net::MockCaller;
}
);

has mock_type => (
is => 'ro',
isa => 'Str',
default => sub { 'FileMockCaller' },
);

has mock_mode => (
is => 'ro',
lazy => 1,
isa => enum([ 'REPLAY', 'RECORD' ]),
required => 1,
required => 0,
default => sub { $ENV{PAWS_MOCK_MODE} }
);

has mock_dir => (
is => 'ro',
isa => 'Str',
required => 1,
lazy => 1,
required => 0,
default => sub { $ENV{PAWS_MOCK_DIR} }
);

Expand All @@ -49,7 +58,8 @@ package Paws::Net::MockCaller;
lazy => 1,
default => sub {
my $self = shift;
Paws::Net::FileMockCaller->new(
my $mock_class = 'Paws::Net::' . $self->mock_type;
$mock_class->new(
real_caller => $self->real_caller,
);
}
Expand All @@ -60,60 +70,70 @@ package Paws::Net::MockCaller;
isa => 'CodeRef',
);

sub actual_request {
return $_[0]->caller->actual_request;
}

sub send_request {
my ($self, $service, $call_object) = @_;

$self->_test_file(sprintf("%s/%04d.response", $self->mock_dir, $self->_request_num));
$self->_next_request;

if ($self->mock_mode eq 'REPLAY') {
$self->caller->file($self->_test_file);
return $self->caller->send_request($service, $call_object);
} elsif ($self->mock_mode eq 'RECORD') {
return $self->real_caller->send_request($service, $call_object);
if ($self->mock_type eq 'FileMockCaller') {
$self->_test_file(sprintf("%s/%04d.response", $self->mock_dir, $self->_request_num));
$self->_next_request;

if ($self->mock_mode eq 'REPLAY') {
$self->caller->file($self->_test_file);
return $self->caller->send_request($service, $call_object);
} elsif ($self->mock_mode eq 'RECORD') {
return $self->real_caller->send_request($service, $call_object);
} else {
die "Unsupported record mode " . $self->mock_mode;
}
} else {
die "Unsupported record mode " . $self->mock_mode;
return $self->caller->send_request($service, $call_object);
}
};

sub caller_to_response {
my ($self, $service, $call_object, $response) = @_;
my $content = $response->content;
my $headers = $response->headers;

$content =~ s/<(RequestId)>.*<\/(RequestId)>/<$1>000000000000000000000000000000000000<\/$2>/ if (defined $content);
$content =~ s/<(RequestID)>.*<\/(RequestID)>/<$1>000000000000000000000000000000000000<\/$2>/ if (defined $content);

if ($headers->{ "x-amzn-requestid" }) {
$headers->{ "x-amzn-requestid" } = '000000000000000000000000000000000000'
}

if ($headers->{ "x-amz-request-id" }) {
$headers->{ "x-amz-request-id" } = '000000000000000000000000000000000000'
}

if ($self->mock_mode eq 'RECORD') {
my $file = path $self->_test_file;
$file->parent->mkpath;

write_text($self->_test_file, encode_json({
request => {
params => $service->to_hash($call_object),
service => $service->service,
call => $call_object->_api_call,
},
response => {
content => $response->content,
headers => $response->headers,
status => $response->status,
}
}));

my $result = $self->real_caller->caller_to_response($service, $call_object, $response);
if ($self->mock_type eq 'FileMockCaller') {
my $content = $response->content;
my $headers = $response->headers;

$content =~ s/<(RequestId)>.*<\/(RequestId)>/<$1>000000000000000000000000000000000000<\/$2>/ if (defined $content);
$content =~ s/<(RequestID)>.*<\/(RequestID)>/<$1>000000000000000000000000000000000000<\/$2>/ if (defined $content);

if ($headers->{ "x-amzn-requestid" }) {
$headers->{ "x-amzn-requestid" } = '000000000000000000000000000000000000'
}

if ($headers->{ "x-amz-request-id" }) {
$headers->{ "x-amz-request-id" } = '000000000000000000000000000000000000'
}

if ($self->mock_mode eq 'RECORD') {
my $file = path $self->_test_file;
$file->parent->mkpath;

write_text($self->_test_file, encode_json({
request => {
params => $service->to_hash($call_object),
service => $service->service,
call => $call_object->_api_call,
},
response => {
content => $response->content,
headers => $response->headers,
status => $response->status,
}
}));
}
my $result = $self->caller->caller_to_response($service, $call_object, $response);
$self->result_hook->($self, $result) if (defined $self->result_hook);
return $result;
} else {
return $self->real_caller->caller_to_response($service, $call_object, $response);
return $self->caller->caller_to_response($service, $call_object, $response);
}
};

Expand Down
48 changes: 48 additions & 0 deletions lib/Paws/Net/NoResponseMockCaller.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package Paws::Net::NoResponseMockCaller;
use Moose;

with 'Paws::Net::RetryCallerRole', 'Paws::Net::CallerRole';

use Paws::Net::APIResponse;
use File::Slurper qw(read_text write_text);
use JSON::MaybeXS;
use Moose::Util::TypeConstraints;
use Path::Tiny;

has file => (is => 'rw', isa => 'Str', trigger => \&_set_file);

has real_caller => (
is => 'ro',
does => 'Paws::Net::CallerRole',
default => sub {
require Paws::Net::Caller;
Paws::Net::Caller->new;
}
);

has actual_request => (
is => 'rw',
isa => 'Object',
lazy => 1,
default => sub { '' },
);

has _encoder => (is => 'ro', default => sub { JSON::MaybeXS->new(canonical => 1) });

sub send_request {
my ($self, $service, $call_object) = @_;

$self->actual_request($service->prepare_request_for_call($call_object));
my $actual_call = $self->_encoder->encode($service->to_hash($call_object));

# we don't care about the response
return {};
};

sub caller_to_response {
my ($self, $service, $call_object, $response) = @_;

return $response;
};

1;
16 changes: 12 additions & 4 deletions lib/Paws/Net/RestXmlCaller.pm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ package Paws::Net::RestXmlCaller;

my %p;
foreach my $att (grep { $_ !~ m/^_/ } $params->meta->get_attribute_list) {

# e.g. S3 metadata objects, which are passed in the header
next if $params->meta->get_attribute($att)->does('Paws::API::Attribute::Trait::ParamInHeaders');

Expand Down Expand Up @@ -79,6 +79,14 @@ package Paws::Net::RestXmlCaller;
{
if ($attribute->does('Paws::API::Attribute::Trait::ParamInURI')) {
my $att_name = $attribute->name;
my $non_print = join('', map { chr($_) } (128..255) );
if ($call->$att_name =~ /[{^}`\[\]><#%'"~|\\$non_print]/) {
return Paws::Exception->throw(
message => "Found unacceptable content in $att_name parameter",
code => 'InvalidInput',
request_id => '',
);
}
if ($uri_attrib_is_greedy{$att_name}) {
$vars->{ $attribute->uri_name } = uri_escape_utf8($call->$att_name, q[^A-Za-z0-9\-\._~/]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the = character fixes a double encoding bug we are encountering. Would there be any perceived harm of including it in the regex, or making the regex configurable or overridable? Would a separate ticket be necessary since it is related to URI encoding?

I can probably find some time to work on this to send a fix and tests.

i.e. Key = client=TEST/year=2020/month=01/day=02/test.txt

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, sorry, I didn't see these comments - this change hasnt been merged yet, however we're working on it. The issue should be fixed in #265 , there's a test in t/s3/uri_encoding.t that checks = is encoded . Are you saying it shouldn't be? Its on the list here: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html

See "Characters that might require special handling" section. (Though the "might" makes for great documentation.. either we do or we don't.. !)

$uri_template =~ s{$att_name\+}{\+$att_name}g;
Expand Down Expand Up @@ -120,7 +128,7 @@ package Paws::Net::RestXmlCaller;
elsif ($attribute->does('Paws::API::Attribute::Trait::ParamInHeaders')) {
my $map = $attribute->get_value($call)->Map;
my $prefix = $attribute->header_prefix;
for my $header (keys %{$map}) {
for my $header (keys %{$map}) {
my $header_name = $prefix . $header;
$request->headers->header( $header_name => $map->{$header} );
}
Expand Down Expand Up @@ -179,11 +187,11 @@ package Paws::Net::RestXmlCaller;

my $xml = '';
foreach my $attribute ($call->meta->get_all_attributes) {
if ($attribute->has_value($call) and
if ($attribute->has_value($call) and
not $attribute->does('Paws::API::Attribute::Trait::ParamInHeader') and
not $attribute->does('Paws::API::Attribute::Trait::ParamInQuery') and
not $attribute->does('Paws::API::Attribute::Trait::ParamInURI') and
not $attribute->does('Paws::API::Attribute::Trait::ParamInBody') and
not $attribute->does('Paws::API::Attribute::Trait::ParamInBody') and
not $attribute->type_constraint eq 'Paws::S3::Metadata'
) {
my $attribute_value = $attribute->get_value($call);
Expand Down
Loading