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   9602 use Moose::Role;
  20         51  
  20         146  
3 20     20   98005 use URI::Template;
  20         74864  
  20         544  
4 20     20   137 use URI;
  20         47  
  20         339  
5 20     20   2706 use Paws::Exception;
  20         55  
  20         674  
6 20     20   135 use Moose::Util::TypeConstraints;
  20         37  
  20         217  
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 666     666   1708 my ($self) = @_;
99              
100 666         1304 my $args = {};
101 666         2888 $args->{ service } = $self->service;
102 666         15694 $args->{ region } = $self->region;
103 666 50       17188 $args->{ scheme } = $self->default_scheme if (not defined $args->{scheme});
104              
105 666         15293 my $service_rules = $self->region_rules;
106 666         13537 my $endpoint_info = $self->_match_rules($self->region_rules, $args->{ region }, $args);
107 666 100       14000 if (not defined $self->region_rules) {
108 390         8032 $endpoint_info = $self->_match_rules($self->region_rules, $args->{ region }, $args);
109             }
110 666 100       1961 if (not defined $endpoint_info) {
111 455         10511 $endpoint_info = $self->_match_rules($self->_default_rules, $args->{ region }, $args);
112             }
113              
114 666 100       2030 if ( not defined $endpoint_info ) {
115 1 50       4 my $region_for_exception = (defined $args->{ region }) ? $args->{ region } : '';
116 1         24 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 665         5049 my $template = URI::Template->new($endpoint_info->{uri});
123 665         100560 my $url = $template->process($args);
124 665         307944 $endpoint_info->{ url } = $url;
125             }
126              
127 665         17722 return $endpoint_info;
128             }
129              
130             sub _match_rules {
131 1511     1511   3684 my ( $self, $service_rules, $region, $args ) = @_;
132              
133 1511 100       3942 return undef if (not defined $service_rules);
134 731 50       2518 return undef if scalar(@$service_rules) == 0;
135              
136 731         1923 for my $rule ( @$service_rules ) {
137 1549 100       3818 if ( $self->_matches_rule($rule, $region, $args) ) {
138 665 100       2939 return { uri => $rule->{ uri }, (defined $rule->{ properties }) ? %{ $rule->{ properties } } : () };
  123         676  
139             }
140             }
141 66         159 return undef;
142             }
143              
144             sub _matches_rule {
145 1549     1549   3146 my( $self, $rule, $region, $args ) = @_;
146              
147 1549 100       3498 return 1 if (not defined $rule->{ constraints });
148              
149 1495         2031 my @constraints = @{ $rule->{ constraints } };
  1495         3008  
150 1495         2676 for my $constraint (@constraints) {
151 1495 100       3322 return 1 if ( $self->_matches_constraint($region, $constraint, $args) );
152             }
153 884         2636 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 1495     1495   3071 my ($self, $region, $constraint, $args ) = @_;
203 1495         2552 my $property = $constraint->[0];
204 1495 50       3426 die "We only know how to apply constraints to region" if ($property ne 'region');
205 1495         2217 my $func = $constraint->[1];
206 1495         2334 my $value = $constraint->[2];
207 1495         34017 return $self->constraints->{$func}->($region,$value);
208             }
209             1;
210