Loading ...
Sorry, an error occurred while loading the content.

Re: [soaplite] STRANGE: SOAP::Lite can't encode @_?

Expand Messages
  • Jörg Ziefle
    ... I guess it was too late yesterday when I wrote the mail. When I read it today, I don t quite get what I wanted to say. ;-) Anyway, the problem persists,
    Message 1 of 4 , Jul 11, 2001
    • 0 Attachment
      On Wed, Jul 11, 2001 at 07:40:19AM -0700, Paul Kulchenko wrote:

      > Hm, I don't get it. Is it client or server? Where is the problem?
      > What is $ftp definition? Looks like you skip part of the message
      > (there is no text after 'following:'). What is the value of @_ in
      > your case and what do you expect to see on wire? I don't see any
      > difference except assign to @ary, which shouldn't make any
      > difference.

      I guess it was too late yesterday when I wrote the mail. When I read it
      today, I don't quite get what I wanted to say. ;-)

      Anyway, the problem persists, and here is all the code I have. It's a
      (very lacking) SOAP 'FTP' application. But the problem doesn't have to
      do with the type of the application.

      The problem is that when I use the head function to show me the first
      few line on a server side text file, it doesn't work unless I pass a
      copy of the values.

      The head function takes two arguments, where the latter one is optional:

      head <file> [number of lines]

      Now, if my command line parser detects this command, it calls the
      (client side) head() function and passes it the two values, the second
      one being undef if it's not provided. Now, the client side head
      function simply calls the server side head_ method in the SOAPFTP class
      on the server side $ftp SOAPFTP object. Now the strange thing happens:
      Unless I make a copy of @_ (@ary = @_) and pass that array, of literally
      enter values ($ftp->head_(file.txt, 10)), SOAP::Lite doesn't encode the
      values properly and seems encode a two-element array consisting of
      ('SOAPFTP', 'SOAPFTP'), that is, the class name of the server side
      module.

      I am running the client side module on:

      socorro:~/sp> uname -a
      SunOS socorro.coon.gatech.edu 5.7 Generic_106541-15 sun4u sparc SUNW,Ultra-5_10

      and the server side module and daemon on a Win98 box.

      Here's the whole code, consisting of the client application
      (soapftp.pl), the server side module (SOAPFTP.pm) and the daemon on the
      server side (daemon.pl).

      Here's the client application:


      #!/usr/local/bin/perl -w

      use strict;
      use Data::Dumper;
      use File::Basename;
      use Term::ReadLine;
      use Term::ReadKey;
      use Getopt::Std;

      $SIG{INT} = 'IGNORE';

      our ($opt_p, $opt_o);

      getopts('p:o:');

      die 'No server given!' unless defined (my $server = shift);

      my $term = new Term::ReadLine 'soap ftp client';

      eval <<EOT;
      use SOAP::Lite
      +trace => ['fault'],
      +autodispatch =>
      uri => "http://$server/",
      proxy => "http://$server:$opt_o/",
      on_fault => sub { print \$_[1]->faultstring },
      # on_debug => sub { print \@_ },
      ;
      EOT

      my $password = defined $opt_p ? $opt_p : getpass();

      sub getpass {

      ReadMode 2;
      print 'Password: ';
      $_ = <STDIN>;
      chomp;
      ReadMode 0;
      return $_;

      };

      my $ftp = SOAPFTP->new($password);
      die "$!\n" if $ftp == 1;

      while (1) {

      my $cmd = $term->readline('SOAPFTP> ');

      SWITCH:
      for ($cmd) {

      $term->addhistory($_) if /\S/;
      /^\s*get\s+(\S+)(\s+(\S+))?/ && do {get($1, $3); next SWITCH;};
      /^\s*cd\s+(\S+)/ && do {cd($1); next SWITCH;};
      /^\s*ls\s+(\S+)?/ && do {ls($1); next SWITCH;};
      /^\s*head\s+(\S+)(\s+(\d+))?/ && do {head($1, $3); next SWITCH;};
      /^\s*quit/ && do {end(); next SWITCH;};
      /^\s*help/ && do {help(); next SWITCH;};
      /^\s*!\s*(\S+)/ && do {system($1); next SWITCH;};

      eval $cmd;

      };

      };

      sub get {

      my ($remote, $local) = @_;
      $local = basename($remote) unless defined $local;
      open FILE, '>'.$local;
      binmode FILE;
      print FILE $ftp->get($remote);
      close FILE;

      };

      sub cd {

      my $dir = shift;
      print $ftp->cd($dir) ? "New directory is $dir.\n" : "Couldn't change directory to $dir!\n";

      };

      sub ls {

      my $file = shift;
      print map{ s/</</ig; $_; } $ftp->ls($file);

      };

      sub end {

      exit 0;

      };

      sub help {

      print <<'EOT';

      SOAPFTP V0.1 by Jorg Ziefle <joerg.ziefle@...>
      Commands:
      cd»··· change directory
      ls»··· list directory contents
      get»·· get file
      head show top lines of file
      help»· see this help message
      quit»· quit the client
      !»···· executes following system command locally
      EOT

      };

      sub head {

      my @ary = @_;
      my @return = $ftp->head_(@ary);
      $return[-1] .= "\n" unless $return[-1] =~ /\n$/;
      print @return ? @return : 'Problem giving head.';

      };

      __END__


      That's the server module:


      package SOAPFTP;

      use strict;

      our $PASS = 'passwd';

      sub new {

      my $passwd = $_[1];
      die "Wrong password" unless $passwd eq $PASS;
      return bless {};

      };

      sub get {

      open FILE, $_[1] or die "$!\n";
      binmode FILE;
      my @ary = <FILE>;
      close FILE;
      return @ary;

      };

      sub cd {

      my $dir = $_[1];
      chdir $dir;

      };

      sub ls {

      my $file = $_[1];
      return defined $file ? `dir $file` : `dir`;

      };

      sub head_ {

      my ($file, $howmany) = @_[1, 2];

      if (-T $file) {

      open FILE, "<$file" or return ();

      my @lines;
      my $linesread = 0;
      while (defined ($_ = <FILE>) && (defined $howmany ? (++$linesread <= $howmany) : 1)) {
      push @lines, $_;
      };

      close FILE;
      return @lines;

      } else {

      return ();

      };

      };


      1;


      Finally, here's the autodispatching daemon on the server side:


      #!/usr/local/bin/perl -w

      use SOAP::Transport::HTTP;

      #$SIG{PIPE} = $SIG{INT} = 'IGNORE';

      $daemon = SOAP::Transport::HTTP::Daemon
      -> new(
      LocalPort => 5000,
      Reuse => 1,
      )
      -> dispatch_to('C:\\perl\\site\\lib', '[\w:]+');

      print "Contact to SOAP server at ", $daemon->url, "\n";

      $daemon->handle;
    Your message has been successfully submitted and would be delivered to recipients shortly.