Forum Discussion
John_Gruber_432
Apr 28, 2011Historic F5 Account
perl SOAP::Lite and file encoding
I'm having problems using System::ConfigSync::upload_file with SOAP Lite in perl.
In perl everything is working fine when I read in binary files with binmode set. When I read in text files, no matter what type encoding type I put in binmod (utf8 or byte) or if I try and read them in as text without binmode, the XML serialized data for the content has "\n" for every line and the file on the BIG-IP comes shows up as a binary file..all jacked up.
I know the API says char[], but how it is being serialized in SOAP::Lite and then written to the disk on the BIG-IP is not working for me. I jumped over to java and read in the files as byte arrays and, after trimming them up BTW..thanks for that,got everything working with binary and text files. So I'm sure this is a encoding/serialization issue in perl SOAP::Lite.
Anyone have this working in perl with some syntax?
Here is what does not work for text files... It's got a bunch of my module sub in it, but you will get the point.
sub copyFile
{
my ($self,$srcfile,$destfile) = @_;
writelog($self,"debug","Copy source file $srcfile to $destfile");
if( -e $srcfile ) {
my $request = getSoapRequestObject($self, "urn:iControl:System/ConfigSync");
my $buffer;
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($srcfile);
open INF, $srcfile or writelog($self,"err","Source file $srcfile can not be opened. $!"); This does work for text files. Tried :byte, :utf8. Tried checking file with if (-B ) and not encoding..doesn't matter
binmode INF, ":bytes";my $blocksize = 65535;
if($size < $blocksize) {
$blocksize = $size;
}
my $bytes_read = 0;
while ( read (INF, $buffer, $blocksize))
{
my $chain_type = "FILE_MIDDLE";
if($bytes_read < 1) {
$chain_type = "FILE_FIRST";
}
elsif (($bytes_read + length($buffer)) eq $size) {
$chain_type = "FILE_LAST";
}
writelog($self,"debug","Writing $destfile ($bytes_read/".length($buffer)."/$size) $chain_type");
my $FileTransferContext = {file_data => $buffer,
chain_type => $chain_type
};
my $response = $request->upload_file(
SOAP::Data->name(file_name => $destfile),
SOAP::Data->name(file_context => $FileTransferContext)
);
if(checkResponse($self,$response)){
$bytes_read = $bytes_read+length($buffer);
} else {
close INF;
return 0;
}
}
close INF;
return 1;
} else {
writelog($self,"err","Source file for copy, $srcfile, does not exist");
return 0;
}
}
- Here's how I did it in the PerlConfigSync CodeShare entry (also as included in the SDK).
sub uploadFile() { my ($localFile, $configName, $quiet) = (@_); $success = 0; if ( "" eq $configName ) { $configName = $localFile; } if ( "" eq $localFile ) { &usage("upload"); } $bContinue = 1; $chain_type = $FILE_FIRST; $preferred_chunk_size = $defaultChunkSize; $chunk_size = $defaultChunkSize; $total_bytes = 0; open(LOCAL_FILE, "<$localFile") or die("Can't open $localFile for input: $!"); binmode(LOCAL_FILE); while (1 == $bContinue ) { $file_data = ""; $bytes_read = read(LOCAL_FILE, $file_data, $chunk_size); if ( $preferred_chunk_size != $bytes_read ) { if ( $total_bytes == 0 ) { $chain_type = $FILE_FIRST_AND_LAST; } else { $chain_type = $FILE_LAST; } $bContinue = 0; } $total_bytes += $bytes_read; $FileTransferContext = { file_data => SOAP::Data->type(base64 => $file_data), chain_type => $chain_type }; $soap_response = $ConfigSync->upload_file ( SOAP::Data->name(file_name => $configName), SOAP::Data->name(file_context => $FileTransferContext) ); if ( $soap_response->fault ) { if ( 1 != $quiet ) { print $soap_response->faultcode, " ", $soap_response->faultstring, "\n"; } $success = 0; $bContinue = 0; } else { if ( 1 != $quiet ) { print "Uploaded $total_bytes bytes\n"; } $success = 1; } $chain_type = $FILE_MIDDLE; } print "\n"; close(LOCAL_FILE); return $success; }
-Joe - John_Gruber_432Historic F5 AccountTeach me not to look... Sorry Joe. I know you work hard for a reason! RTM...
- It's funny, this is the second time this exact issue came up this week and it's the only time I can remember in the 6 years or so since I wrote that first ConfigSync sample.
- John_Gruber_432Historic F5 AccountThat tells you where the zeitgeist for iControl is then...
- L4L7_53191
Nimbostratus
John: Really? That's extremely odd to me. I'd think that you'd need to explicitly decode the response - something must be going on there. Perl gets ASCII back - just like Python, which requires me to explicitly decode. So I'd expect it to duck type it as ASCII on the response side, which in terms of dynamic languages is the Right Thing to do. I'm extremely interested to see why this happens with SOAP::Lite. - Actually, the methods that use parameters with char[] data types will result in a SOAP type of base64Binary. Looking at a soap trace on the download_file method, the resulting data looks something like this:
< E:Envelope xmlns:E="http://schemas.xmlsoap.org/soap/envelope/" xmlns:A="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.w3.org/2001/XMLSchema" xmlns:iControl="urn:iControl" E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" > < E:Body > < m:download_fileResponse xmlns:m="urn:iControl:System/ConfigSync" > < return s:type="iControl:System.ConfigSync.FileTransferContext" > < file_data s:type="y:base64Binary" >YXV0aCBwYXJ0aXRpb24gQ29tbW9uIHsKICAgIGRlc2N...."< /file_data > < chain_type s:type="iControl:Common.FileChainType" >FILE_FIRST_AND_LAST< /chain_type > < /return > < file_offset s:type="y:long" >7656< /file_offset > < /m:download_fileResponse > < /E:Body > < /E:Envelope >
- L4L7_53191
Nimbostratus
Ah. That explains it on the return side then.
Recent Discussions
Related Content
Â
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects