CC: | alangrow+pause [...] gmail.com |
The FTP reply parsing code is broken for multi-line server replies which
might require more than one socket read. Here's a transcript of a PUT
succeeding, but subsequent operations failing, because response() didn't
drain the full mult-line reply from the server. I've attached a patch
against 0.4 that fixes the problem.
Show quoted text
<<< 200 PROT command OK. Using secure data connection.
Show quoted text
<<< xxx Entering Passive Mode (xxx,xxx,x,xx,xx,xx)
Show quoted text
<<< 150 Opening ASCII mode data connection. Ready to write file .
("/foo.txt.tmp") S T O R
<<< 226-Upload File Size:2845 bytes @ 2K/sec.
1
Show quoted text
> put foo.txt foo.txt.tmp
<<< 200 PBSZ command OK. Using buffer size set to 0.
Show quoted text >>> PBSZ 0
>>> PROT P
>>> PASV
>>> STOR foo.txt.tmp
> nlst
<<< 226 Transfer complete. CRC32=90434B1 ("/foo.txt.tmp") STOR
Show quoted text >>> PBSZ 0
>>> PROT P
<<< 200 PBSZ command OK. Using buffer size set to 0.
Show quoted text >>> PASV
<<< 200 PROT command OK. Using secure data connection.
Use of uninitialized value in split at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 143, <STDIN> line 1.
Use of uninitialized value in join or string at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 145, <STDIN> line 1.
Use of uninitialized value in join or string at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 145, <STDIN> line 1.
Use of uninitialized value in join or string at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 145, <STDIN> line 1.
Use of uninitialized value in join or string at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 145, <STDIN> line 1.
Use of uninitialized value in multiplication (*) at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 146, <STDIN> line 1.
Use of uninitialized value in addition (+) at
~/perl/bin/hsn/extlib/Net/FTPSSL.pm line 146, <STDIN> line 1.
Use of uninitialized value in subroutine entry at
/usr/lib/perl/5.8/Socket.pm line 201, <STDIN> line 1.
Bad arg length for Socket::pack_sockaddr_in, length is 0, should be 4
at /usr/lib/perl/5.8/Socket.pm line 201, <STDIN> line 1.
Subject: | multiline-reply.net-ftpssl.diff |
--- Net/FTPSSL.pm.orig 2005-10-23 10:37:12.000000000 -0400
+++ Net/FTPSSL.pm 2008-12-12 15:15:54.000000000 -0500
@@ -655,31 +655,33 @@
sub response {
my $self = shift;
- my ( $data, $code );
+ my $data = '';
+ my $code;
+ my $lastline = 0;
- my $read = sysread( $self, $data, 4096);
- unless( defined $read ) {
- croak "Can't read on socket: $!";
- }
-
- my @lines = split( "\015\012", $data );
-
- foreach my $line ( @lines ) {
-
-# $data = $self->getline();
-# $data =~ m/^(\d+)(\-?)(.*)$/s;
- $line =~ m/^(\d+)(\-?)(.*)$/s;
-
- $code = $1;
- print STDERR "<<< " . $line ."\n"
- if ref($self) eq "Net::FTPSSL" && ${*$self}{'debug'};
+ while (!$lastline) {
+ my $read = sysread( $self, $data, 4096, length $data);
- if ( ref($self) eq "Net::FTPSSL" ) {
- ${*$self}{'last_ftp_msg'} = $line;
+ unless( defined $read ) {
+ croak "Can't read on socket: $!";
}
- last if $2 ne '-';
+ if (length $data > 1048576) {
+ die "Server's command response is too large (> 1Mbyte).";
+ }
+ while ($data =~ s/^(\d+)(\-| )(.*?)\015\012//) {
+ my $line = $3;
+ $code = $1;
+ $lastline = $2 ne '-';
+
+ print STDERR "<<< " . $line ."\n"
+ if ref($self) eq "Net::FTPSSL" && ${*$self}{'debug'};
+
+ if ( ref($self) eq "Net::FTPSSL" ) {
+ ${*$self}{'last_ftp_msg'} = $line;
+ }
+ }
}
return substr( $code, 0, 1 );