Paws XXII (Plana est terra)

The next action I had a crack at was 'PutCORSConfiguration' and I was getting the usual;

<Error> <Code>MalformedXML</Code> <Message>The XML you provided was not well-formed or did not validate against our published schema </Message> </Error>

At this points in my Paws adventure I checked the API doc for URI Request Parameters of the PutCORSConfiguration;

PUT /?cors HTTP/1.1 Host: Bucket.s3.amazonaws.com Content-MD5: ContentMD5

and I see I don't have to deal with the 'id' in the 'URI' bug here as I get what I want in the request URI;


 'uri' => '/dev.cargotel.paws?cors'

So I looked a little doc again and it wants;

<CORSConfiguration> <CORSRule> <AllowedOrigin>http://www.example.com</AllowedOrigin>

and I was sending;

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRules><CORSRule><

hence the Malformed XML error.

I ran into this once some time before when dealing with another bug in Paws and I did a change to boto to fix it. This time out I did not want to make a change to boto as that in the long run is not a solution so I had a deeper look.

In boto I fould this;


 "CORSRules":{
      "type":"list",
      "member":{"shape":"CORSRule"},
      "flattened":true
    },

"flattened" have not seen that before and I had a look in all the Paws code and could not find it so maybe I can use that to drop the 'CORSRules' tag. That would be the best solution no change to boto;

First I need a new trait in Paws::API;


+package Paws::API::Attribute::Trait::Flatten;
+  use Moose::Role;
+  use Moose::Util;
++  Moose::Util::meta_attribute_alias('Flatten');

just a simple logic one like 'ParamInBody' that is already in use;

Next was a change to the templates so I can get this new trait added into the class.

The correct template was 'default/object.tt' and I just added in;


[%- IF (shape.members.$param_name.streaming == 1); traits.push('ParamInBody'); END %]
+  [%- IF (member.flattened == 1); traits.push('Flatten'); END %]
   [%- encoder = c.encoders_struct.$member_shape_name; IF (encoder); traits.push('JSONAttribute') %], decode_as => '[% encoder.encoding %]', method => '[% encoder.alias %]'[% END %]

The real problem was finding the correct template took about 45 minutes to find the correct place.

Next was just a quick change to 'Paws::Net::RestXmlCaller' to account for the above;


++  if ($attribute->does('Flatten')){
++      $xml .= $self->_to_xml($attribute_value);
++  }
++  elsif ($call->can('_namspace_uri')){
--  if ($call->can('_namspace_uri')){
...
 $xml .=  ( join '', map { sprintf '<%s>%s</%s>', $location, $self->_to_xml($_), $location } @{ $attribute->get_value($value) } );
          $xml ="<$att_name>$xml</$att_name>"
--          if( $attribute->does('NameInRequest');
++            if( $attribute->does('NameInRequest') and
++                not $attribute->does('Flatten'));

and this time I got

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedHeaders>
      <AllowedHeader>*</AllowedHeader>
    </AllowedHeaders>
    <AllowedMethods>
      <AllowedMethod>PUT

I still get an invlaid resuslt but I a close;

The boto for 'AllowedHeaders' is


 "AllowedHeaders":{
      "type":"list",
      "member":{"shape":"AllowedHeader"},
      "flattened":true
    },

so the 'flattened' is there so a little more change to my 'RestXmlCaller' code;

In 'sub_to_xml' I made this change;


-          my $location = $attribute->request_name;
-          $xml .= "<${att_name}>" . ( join '', map { sprintf '<%s>%s</%s>', $location, $_, $location } @{ $attribute->get_value($value) } ) . "</${att_name}>";
-      } elsif ($attribute->type_constraint =~ m/^ArrayRef\[(.*?\:\:.*)\]/) { #assume it's an array of Paws API objects
-                my $location = $attribute->does('NameInRequest') ? $attribute->request_name : $att_name;
+
+                 my $location = $attribute->request_name;
+
+                 $xml .= ( join '', map { sprintf '<%s>%s</%s>', $location, $_, $location } @{ $attribute->get_value($value) } );
+
+          $xml .= "<${att_name}>".$xml ."</${att_name}>"
+                   unless($attribute->does('Flatten'));
+
+         } elsif ($attribute->type_constraint =~ m/^ArrayRef\[(.*?\:\:.*)\]/) { #assume it's an array of Paws API objects
my $location = $attribute->does('NameInRequest') ? $attribute->request_name : $att_name;

and I get the correct XML;

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule><AllowedMethod>PUT</AllowedMethod><AllowedMethod>POST</AllowedMethod><AllowedMethod>DELETE</AllowedMethod><AllowedOrigin>http://www.example.com</AllowedOrigin><AllowedHeader>*</AllowedHeader></CORSRule><CORSRule><AllowedOrigin>http://www.aws.com</AllowedOrigin><AllowedHeader>*</AllowedHeader><AllowedMethod>PUT</AllowedMethod><AllowedMethod>POST</AllowedMethod></CORSRule></CORSConfiguration>

but Still a 400?? error

After pulling my hair for a while I relaized I was getting this on the URI;


'uri' => '/dev.cargotel.paws',

which should be


'uri' => '/dev.cargotel.paws?cors',

I had while debugging had takeing the above out of bot so I just reverted boto back and got '200' for my command.

However I was getting this warning all over the place!

Use of uninitialized value $name in concatenation (.) or string at /sdk-perl/lib/Paws/Net/RestXmlCaller.pm line 24.

Not 100% sure what this sub;


sub array_flatten_string {
    my $self = shift;
    my ($name) =  shift;
    return ($self->flattened_arrays)?'%s.'.$name.'%d':'%s.member.%d';
  }

was doing, but the fix was easy enough;


 sub array_flatten_string {
    my $self = shift;
    my ($name) =  shift;
    $name=""
      unless($name);
    return ($self->flattened_arrays)?'%s.'.$name.'%d':'%s.member.%d';
  }

and time to check it as all the other test are running 100% correct

boo-the-pomeranian-dies.jpg

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations