Violating Perl Module Namespaces
Perl doesn't enforce access to modules' namespaces. This would usually be considered a bad thing, but sometimes it allows us to work around problems in modules without changing their code. Here's a perfect example:
I've been writing a script to talk to an XML-RPC endpoint, using Frontier::Client but for one of the requests, the script throws the following error:
wanted a data type, got `ex:i8'
Turning on debugging showed the response type was indeed ex:i8, which isn't one of the types that Frontier::Client supports.
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
<params>
<param>
<value>
<ex:i8>161</ex:i8>
</value>
</param>
</params>
</methodResponse>
Searching through the code shows Frontier::Client is a wrapper around Frontier::RPC2 and the error message happens at the following section:
} elsif ($scalars{$tag}) {
$expat->{'rpc_text'} = "";
push @{ $expat->{'rpc_state'} }, 'cdata';
} else {
Frontier::RPC2::die($expat, "wanted a data type, got \`$tag'\n");
}
So we can see that it's looking up the tag into a hash called %scalars to see if the type is a scalar type, otherwise throws the error we saw. Looking at the top, we can see this hash:
%scalars = (
'base64' => 1,
'boolean' => 1,
'dateTime.iso8601' => 1,
'double' => 1,
'int' => 1,
'i4' => 1,
'string' => 1,
);
So, if we could add ex:i8 to this scalar, we could fix the problem. We could fix the module, but that would require every user of the script to patch their copy of the module. The alternative is to inject something into that hash across module boundaries, which we can do by just refering to the hash by it's complete name including the package name. We can use:
$Frontier::RPC2::scalars{'ex:i8'} = 1;Now when we run the script, everything works. It's not nice and it's dependent on Frontier::RPC2 not changing. but it allows us to get on with our script.
Hardcore Java