File Coverage

blib/lib/Paws/API/EndpointResolver.pm
Criterion Covered Total %
statement 54 54 100.0
branch 20 24 83.3
condition n/a
subroutine 9 9 100.0
pod n/a
total 83 87 95.4


line stmt bran cond sub pod time code
1             package Paws::API::EndpointResolver;
2 20     20   13832 use Moose::Role;
  20         57  
  20         250  
3 20     20   127747 use URI::Template;
  20         87054  
  20         649  
4 20     20   176 use URI;
  20         54  
  20         358  
5 20     20   4143 use Paws::Exception;
  20         60  
  20         750  
6 20     20   152 use Moose::Util::TypeConstraints;
  20         81  
  20         235  
7              
8             has region => (is => 'rw', isa => 'Str|Undef');
9             requires 'service';
10              
11             has _endpoint_info => (
12             is => 'ro',
13             init_arg => undef,
14             lazy => 1,
15             builder => '_construct_endpoint',
16             );
17              
18             has _region_for_signature => (
19             is => 'rw',
20             isa => 'Str',
21             lazy => 1,
22             init_arg => undef,
23             default => sub {
24             my $self = shift;
25             my $sig_region;
26            
27             # For global services: don't specify region: we sign with the region in the credentialScope
28             # specify the region: we override the credentialScope (use the region specified)
29             # For regional services: use the region specified for signing
30             # If endpoint is specified: use the region specified (no _endpoint_info)
31             if (defined $self->_endpoint_info->{ credentialScope } and not defined $self->region) {
32             $sig_region = $self->_endpoint_info->{ credentialScope }->{ region }
33             }
34             $sig_region = $self->region if (not defined $sig_region);
35              
36             Paws::Exception->throw(
37             message => "Can't find a region for signing. region is required",
38             code => 'NoRegionError',
39             request_id => ''
40             ) if (not defined $sig_region);
41              
42             return $sig_region;
43             },
44             );
45              
46             subtype 'Paws::EndpointURL',
47             as 'URI';
48              
49             coerce 'Paws::EndpointURL',
50             from 'Str',
51             via { URI->new($_); };
52              
53             has endpoint => (
54             is => 'ro',
55             isa => 'Paws::EndpointURL',
56             lazy => 1,
57             coerce => 1,
58             default => sub {
59             shift->_endpoint_info->{ url };
60             }
61             );
62              
63             has endpoint_host => (
64             is => 'ro',
65             isa => 'Str',
66             lazy => 1,
67             default => sub {
68             shift->endpoint->host;
69             }
70             );
71              
72             has _api_endpoint => (
73             is => 'ro',
74             isa => 'Str',
75             lazy => 1,
76             default => sub {
77             shift->endpoint->as_string;
78             }
79             );
80              
81             has region_rules => (is => 'ro', isa => 'ArrayRef');
82              
83             has _default_rules => (is => 'ro', isa => 'ArrayRef', default => sub {
84             [ { constraints => [ [ 'region', 'startsWith', 'cn-' ] ],
85             properties => { signatureVersion => 'v4' },
86             uri => '{scheme}://{service}.{region}.amazonaws.com.cn'
87             },
88             { constraints => [ [ 'region', 'notEquals', undef ] ],
89             uri => '{scheme}://{service}.{region}.amazonaws.com'
90             },
91             ]
92             },
93             );
94              
95             has default_scheme => ( is => 'ro', isa => 'Str', default => 'https' );
96              
97             sub _construct_endpoint {
98 665     665   2265 my ($self) = @_;
99              
100 665         2013 my $args = {};
101 665         3890 $args->{ service } = $self->service;
102 665         18551 $args->{ region } = $self->region;
103 665 50       19182 $args->{ scheme } = $self->default_scheme if (not defined $args->{scheme});
104              
105 665         17623 my $service_rules = $self->region_rules;
106 665         16143 my $endpoint_info = $self->_match_rules($self->region_rules, $args->{ region }, $args);
107 665 100       16522 if (not defined $self->region_rules) {
108 389         9384 $endpoint_info = $self->_match_rules($self->region_rules, $args->{ region }, $args);
109             }
110 665 100       2768 if (not defined $endpoint_info) {
111 454         12572 $endpoint_info = $self->_match_rules($self->_default_rules, $args->{ region }, $args);
112             }
113              
114 665 100       2584 if ( not defined $endpoint_info ) {
115 1 50       3 my $region_for_exception = (defined $args->{ region }) ? $args->{ region } : '';
116 1         17 Paws::Exception->throw(
117             message => "No endpoint for service $args->{ service } in region '$region_for_exception'",
118             code => 'NoRegionError',
119             request_id => ''
120             );
121             } else {
122 664         6836 my $template = URI::Template->new($endpoint_info->{uri});
123 664         134837 my $url = $template->process($args);
124 664         382882 $endpoint_info->{ url } = $url;
125             }
126              
127 664         20634 return $endpoint_info;
128             }
129              
130             sub _match_rules {
131 1508     1508   4318 my ( $self, $service_rules, $region, $args ) = @_;
132              
133 1508 100       5059 return undef if (not defined $service_rules);
134 730 50       2634 return undef if scalar(@$service_rules) == 0;
135              
136 730         2388 for my $rule ( @$service_rules ) {
137 1547 100       4917 if ( $self->_matches_rule($rule, $region, $args) ) {
138 664 100       3956 return { uri => $rule->{ uri }, (defined $rule->{ properties }) ? %{ $rule->{ properties } } : () };
  123         785  
139             }
140             }
141 66         183 return undef;
142             }
143              
144             sub _matches_rule {
145 1547     1547   4027 my( $self, $rule, $region, $args ) = @_;
146              
147 1547 100       5020 return 1 if (not defined $rule->{ constraints });
148              
149 1493         3124 my @constraints = @{ $rule->{ constraints } };
  1493         4429  
150 1493         4672 for my $constraint (@constraints) {
151 1493 100       4678 return 1 if ( $self->_matches_constraint($region, $constraint, $args) );
152             }
153 883         3468 return 0;
154             }
155              
156             has constraints => (
157             is => 'ro',
158             init_arg => undef,
159             default => sub {
160             {
161             startsWith => sub {
162             my ( $a, $v ) = @_;
163             return 0 if (not defined $a and defined $v);
164             return 0 if (defined $a and not defined $v);
165             return $a =~ /^$v.*/i;
166             },
167             notStartsWith => sub {
168             my ( $a, $v ) = @_;
169             return 1 if (not defined $a);
170             return $a !~ /^$v.*/i;
171             },
172             equals => sub {
173             my ( $a, $v ) = @_;
174             return 0 if (not defined $a and defined $v);
175             return 0 if (defined $a and not defined $v);
176             return 1 if (not defined $a and not defined $v);
177             return $a eq $v;
178             },
179             notEquals => sub {
180             # in the sample json, notEqual region's is always null
181             # this needs review
182             my ( $a, $v ) = @_;
183             return 1 if (defined $a and not defined $v);
184             return 1 if (not defined $a and defined $v);
185             return 0 if (not defined $a and not defined $v);
186             return $a ne $v;
187             },
188             oneOf => sub {
189             my ( $a, $v ) = @_;
190             for my $b (@$v) {
191             return not defined($a) if (not defined($b));
192             return not defined($b) if (not defined($a));
193             return 1 if $a eq $b;
194             }
195             return 0;
196             }
197             };
198             }
199             );
200              
201             sub _matches_constraint {
202 1493     1493   3971 my ($self, $region, $constraint, $args ) = @_;
203 1493         3535 my $property = $constraint->[0];
204 1493 50       5056 die "We only know how to apply constraints to region" if ($property ne 'region');
205 1493         3131 my $func = $constraint->[1];
206 1493         2797 my $value = $constraint->[2];
207 1493         39737 return $self->constraints->{$func}->($region,$value);
208             }
209             1;
210