File Coverage

blib/lib/Paws/Net/RestXmlCaller.pm
Criterion Covered Total %
statement 131 143 91.6
branch 49 56 87.5
condition 14 15 93.3
subroutine 13 14 92.8
pod 0 2 0.0
total 207 230 90.0


line stmt bran cond sub pod time code
1             package Paws::Net::RestXmlCaller;
2 8     8   6404 use Moose::Role;
  8         23  
  8         64  
3 8     8   44521 use HTTP::Request::Common;
  8         14073  
  8         698  
4 8     8   63 use POSIX qw(strftime);
  8         21  
  8         95  
5 8     8   518 use URI::Template;
  8         19  
  8         206  
6 8     8   44 use URI::Escape;
  8         19  
  8         369  
7 8     8   51 use Moose::Util;
  8         18  
  8         70  
8              
9             sub array_flatten_string {
10 9     9 0 15 my $self = shift;
11 9 50       25 return ($self->flattened_arrays)?'%s.%d':'%s.member.%d';
12             }
13              
14             # converts the objects that represent the call into parameters that the API can understand
15             sub _to_querycaller_params {
16 13     13   39 my ($self, $params) = @_;
17              
18              
19 13         26 my %p;
20 13         66 foreach my $att (grep { $_ !~ m/^_/ } $params->meta->get_attribute_list) {
  71         549  
21            
22             # e.g. S3 metadata objects, which are passed in the header
23 71 100       660 next if $params->meta->get_attribute($att)->does('Paws::API::Attribute::Trait::ParamInHeaders');
24              
25 70 100       23882 my $key = $params->meta->get_attribute($att)->does('Paws::API::Attribute::Trait::ParamInQuery')?$params->meta->get_attribute($att)->query_name:$att;
26 70 100       18634 if (defined $params->$att) {
27 28         101 my $att_type = $params->meta->get_attribute($att)->type_constraint;
28              
29 28 100       1812 if ($self->_is_internal_type($att_type)) {
    100          
30 21         1191 $p{ $key } = $params->{$att};
31             } elsif ($att_type =~ m/^ArrayRef\[(.*)\]/) {
32 3 100       519 if ($self->_is_internal_type("$1")){
33 1         3 my $i = 1;
34 1         3 foreach my $value (@{ $params->$att }){
  1         24  
35 3         7 $p{ sprintf($self->array_flatten_string, $key, $i) } = $value;
36 3         7 $i++
37             }
38             } else {
39 2         5 my $i = 1;
40 2         3 foreach my $value (@{ $params->$att }){
  2         50  
41 2         9 my %complex_value = $self->_to_querycaller_params($value);
42 2         6 map { $p{ sprintf($self->array_flatten_string . ".%s", $key, $i, $_) } = $complex_value{$_} } keys %complex_value;
  6         16  
43 2         33 $i++
44             }
45             }
46             } else {
47 4         877 my %complex_value = $self->_to_querycaller_params($params->$att);
48 4         14 map { $p{ "$key.$_" } = $complex_value{$_} } keys %complex_value;
  18         69  
49             }
50             }
51             }
52 13         368 return %p;
53             }
54              
55             sub _call_uri {
56 7     7   25 my ($self, $call) = @_;
57 7         37 my $uri_template = $call->meta->name->_api_uri; # in auto-lib/<service>/<method>.pm
58              
59 7         58 my @uri_attribs = $uri_template =~ /{(.+?)}/g;
60 7         27 my $vars = {};
61              
62 7         15 my %uri_attrib_is_greedy;
63 7         23 foreach my $attrib ( @uri_attribs ) {
64 7         50 my ($att_name, $greedy) = $attrib =~ /(\w+)(\+?)/;
65 7         31 $uri_attrib_is_greedy{$att_name} = $greedy;
66             }
67              
68 7         33 foreach my $attribute ($call->meta->get_all_attributes)
69             {
70 49 100       16175 if ($attribute->does('Paws::API::Attribute::Trait::ParamInURI')) {
71 7         2167 my $att_name = $attribute->name;
72 7 100       33 if ($uri_attrib_is_greedy{$att_name}) {
73 1         31 $vars->{ $attribute->uri_name } = uri_escape_utf8($call->$att_name, q[^A-Za-z0-9\-\._~/]);
74 1         28 $uri_template =~ s{$att_name\+}{\+$att_name}g;
75             } else {
76 6         228 $vars->{ $attribute->uri_name } = $call->$att_name;
77             }
78             }
79             }
80              
81 7         1568 my $t = URI::Template->new( $uri_template );
82 7         1226 my $uri = $t->process($vars);
83 7         2190 return $uri;
84             }
85              
86             sub _to_header_params {
87 7     7   26 my ($self, $request, $call) = @_;
88 7         42 foreach my $attribute ($call->meta->get_all_attributes) {
89 49 100       11557 next unless $attribute->has_value($call);
90 17 50       606 if ($attribute->does('Paws::API::Attribute::Trait::ParamInHeader')) {
    100          
91 0         0 $request->headers->header( $attribute->header_name => $attribute->get_value($call) );
92             }
93             elsif ($attribute->does('Paws::API::Attribute::Trait::ParamInHeaders')) {
94 1         539 my $map = $attribute->get_value($call)->Map;
95 1         43 my $prefix = $attribute->header_prefix;
96 1         4 for my $header (keys %{$map}) {
  1         6  
97 2         147 my $header_name = $prefix . $header;
98 2         97 $request->headers->header( $header_name => $map->{$header} );
99             }
100             }
101             }
102             }
103              
104             # URI escaping adapted from URI::Escape
105             #c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
106             # perl 5.6 ready UTF-8 encoding adapted from JSON::PP
107             our %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
108             our $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
109              
110             sub _uri_escape {
111 0     0   0 my ($self, $str) = @_;
112 0         0 utf8::encode($str);
113 0         0 $str =~ s/($unsafe_char)/$escapes{$1}/ge;
  0         0  
114 0         0 $str =~ s/ /+/go;
115 0         0 return $str;
116             }
117              
118             sub _to_xml {
119 6     6   250 my ($self, $value) = @_;
120              
121 6         11 my $xml = '';
122 6         26 foreach my $attribute ($value->meta->get_all_attributes) {
123 22         1177 my $att_name = $attribute->name;
124 22 100       60 next if (not $attribute->has_value($value));
125 12 100       664 if (Moose::Util::find_meta($attribute->type_constraint->name)) {
    100          
    100          
126 2 50       88 if ($attribute->does('NameInRequest')) {
127 0         0 my $location = $attribute->request_name;
128 0         0 $xml .= sprintf '<%s>%s</%s>', $location, $self->_to_xml($attribute->get_value($value)), $location;
129             } else {
130 2         154 $xml .= sprintf '<%s>%s</%s>', $att_name, $self->_to_xml($attribute->get_value($value)), $att_name;
131             }
132             } elsif ($attribute->type_constraint eq 'ArrayRef[Str|Undef]') {
133 1         119 my $location = $attribute->request_name;
134 1         4 $xml .= "<${att_name}>" . ( join '', map { sprintf '<%s>%s</%s>', $location, $_, $location } @{ $attribute->get_value($value) } ) . "</${att_name}>";
  3         116  
  1         11  
135             } elsif ($attribute->type_constraint =~ m/^ArrayRef\[(.*?\:\:.*)\]/) { #assume it's an array of Paws API objects
136 2 50       370 my $location = $attribute->does('NameInRequest') ? $attribute->request_name : $att_name;
137 2         7 $xml .= ( join '', map { sprintf '<%s>%s</%s>', $location, $self->_to_xml($_), $location } @{ $attribute->get_value($value) } );
  2         229  
  2         10  
138             } else {
139 7 50       1112 if ($attribute->does('NameInRequest')) {
140 0         0 my $location = $attribute->request_name;
141 0         0 $xml .= sprintf '<%s>%s</%s>', $location, $attribute->get_value($value), $location;
142             } else {
143 7         589 $xml .= sprintf '<%s>%s</%s>', $att_name, $attribute->get_value($value), $att_name;
144             }
145             }
146             }
147 6         338 return $xml;
148             }
149              
150             sub _to_xml_body {
151 7     7   26 my ($self, $call) = @_;
152              
153 7         24 my $xml = '';
154 7         35 foreach my $attribute ($call->meta->get_all_attributes) {
155 49 100 66     15142 if ($attribute->has_value($call) and
      100        
      100        
      100        
      100        
156             not $attribute->does('Paws::API::Attribute::Trait::ParamInHeader') and
157             not $attribute->does('Paws::API::Attribute::Trait::ParamInQuery') and
158             not $attribute->does('Paws::API::Attribute::Trait::ParamInURI') and
159             not $attribute->does('Paws::API::Attribute::Trait::ParamInBody') and
160             not $attribute->type_constraint eq 'Paws::S3::Metadata'
161             ) {
162 2         834 my $attribute_value = $attribute->get_value($call);
163 2 50       259 if ( ref $attribute_value ) {
164 2 50       9 my $location = $attribute->does('NameInRequest') ? $attribute->request_name : $attribute->name;
165 2         166 $xml .= sprintf '<%s>%s</%s>', $location, $self->_to_xml($attribute_value), $location;
166             }
167             else {
168 0         0 $xml .= $attribute_value;
169             }
170             }
171             }
172              
173 7 100       3244 return undef if (not $xml);
174 2         10 return $xml;
175             }
176              
177             sub prepare_request_for_call {
178 7     7 0 85 my ($self, $call) = @_;
179              
180 7         18 my $request;
181 7 100       61 if ($self->isa('Paws::S3')){
182 4         21100 require Paws::Net::S3APIRequest;
183 4         55 $request = Paws::Net::S3APIRequest->new();
184             } else {
185 3         30 $request = Paws::Net::APIRequest->new();
186             }
187              
188 7         6110 my $uri = $self->_call_uri($call); #in RestXmlCaller
189              
190 7         73 my $qparams = { $uri->query_form };
191 7         353 foreach my $attribute ($call->meta->get_all_attributes) {
192 49         10988 my $att_name = $attribute->name;
193 49 100       162 if ($attribute->does('Paws::API::Attribute::Trait::ParamInQuery')) {
194 14 100       4654 $qparams->{ $attribute->query_name } = $call->$att_name if (defined $call->$att_name);
195             }
196             }
197 7         1575 $uri->query_form(%$qparams);
198              
199 7         602 $request->uri($uri->as_string);
200              
201 7         204 my $url = $self->_api_endpoint . $uri; #in Paws::API::EndPointResolver
202              
203             #TODO: I'm not sure if any of the REST style APIs want things as query parameters
204 7         91 $request->parameters({ $self->_to_querycaller_params($call) });
205              
206 7         220 $request->url($url);
207 7         228 $request->method($call->_api_method);
208              
209 7 100       50 if (my $xml_body = $self->_to_xml_body($call)){
210 2         54 $request->content($xml_body);
211             }
212              
213 7         44 $self->_to_header_params($request, $call);
214              
215 7 100       2268 if ($call->can('_stream_param')) {
216 1         33 my $param_name = $call->_stream_param;
217 1         27 $request->content($call->$param_name);
218 1         22 $request->headers->header( 'content-length' => $request->content_length );
219             #$request->headers->header( 'content-type' => $self->content_type );
220             }
221              
222 7         112 $self->sign($request);
223              
224 7         185 return $request;
225             }
226             1;