tachyon has asked for the wisdom of the Perl Monks concerning the following question:
Hi,
I have an interesting issue. The code that follows has been in testing for a while and uses DID use read() to read data from a socket connection to a web server. The URL noted led to an interesting problem with the read hanging at 97%. Changing to sysread solved the problem. This is the first URL to display this behaviour.
Questions?
Both CGI and CGI::Simple use read() to get POST data. There is a transient, difficult to prove with a reliable test case, issue with both Modules and some Browsers in certain circumstances - Namely with large POSTs (not multipart form) sometimes all the expected data fails to be got by the read call. read() is blocking and should get all the data you asked for (if sent). The threshold for large appears to be ~20K ? 16384. You can kill read with signals due to the non-reentrant behaviour of the old C libs but getting it to return with a short read any other way with a test case has proved problematic. Wisdom appreciated.
#!/usr/bin/perl -w use strict; use IO::Socket::INET; $|++; my $url = "http://ftp.blizzard.com/pub/war3/maps/(4)iceforge.zip"; my $DEBUG = 1; my $CRLF = "\015\012\015\012"; my ( $code, $type, $length, $sock, $data_buffer, $location ) = init_do +wnload( $url ); open my $fh, '>c:/tmp.zip' or die $!; binmode $fh; print $fh $data_buffer; download( $fh, $sock, $filename, length($data_buffer), $length ); sub download { my ( $fh, $sock, $filename, $got_so_far, $length ) = @_; my $buffer; print "Got: $got_so_far\n" if $DEBUG; # # This will hang on a read() works with sysread() # while ( ($got_so_far < $length) and sysread( $sock, $buffer, 8192 +) ){ print $fh $buffer; $got_so_far += length $buffer; print "Got: $got_so_far\n" if $DEBUG; #write_lockfile( $filename, $got_so_far ); } close $fh; $sock->close; print "Wanted: $length\nGot $got_so_far\n"; unless ( $length == $got_so_far ) { die "Expected $length bytes but only got $got_so_far" ; } } sub init_download { my ( $url ) = @_; ui_network_error( "Invalid URL $url\n" ) unless $url =~ m!^http:// +([^/:\@]+)(?::(\d+))?(/\S*)?$!; my $host = $1; my $port = $2 || 80; my $path = $3; $path = "/" unless defined $path; my $sock = IO::Socket::INET->new( PeerAddr => $host, Proto => 'tcp +', PeerPort => $port ) or ui_network_error( 'Could not connect socket', $url ); $sock->autoflush; print $sock "GET $url HTTP/1.0 Host: localhost Accept: */* Connection: Keep-Alive User-Agent: Mozilla/4.0 (compatible; MSIE 4.5; Windows 98; ) $CRLF"; my ($header, $content, $buffer); while (sysread( $sock, $buffer, 8192 )){ $content .= $buffer; if ( (my $index = (index $content, $CRLF)) > 0 ) { $header = substr $content, 0, $index; $content = substr $content, $index+ 4; last; } } $header =~ s/\015\012/\n/g; # unfold the header $header =~ s/\n\s+/ /g; my ($length) = $header =~ m/^Content-Length:\s*(\d+)/im; my ($type) = $header =~ m/^Content-Type:\s*([^\r\n]+)/im; my ($loc) = $header =~ m/^Location:\s*([^\r\n]+)/im; my ($code) = $header =~ m!^HTTP/\d\.\d[^\d]+(\d+)!i; print "$header\n----\nWant: $length\n"; return ( $code, $type, $length, $sock, $content, $loc ) } sub ui_network_error{ die shift }
cheers
tachyon
s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: read aka fread(3) broken, sysread aka read(2) works IIS socket
by dws (Chancellor) on Sep 11, 2003 at 07:13 UTC | |
by antirice (Priest) on Sep 11, 2003 at 08:03 UTC | |
|
Re: read aka fread(3) broken, sysread aka read(2) works IIS socket
by antirice (Priest) on Sep 11, 2003 at 04:36 UTC | |
|
Re: read aka fread(3) broken, sysread aka read(2) works IIS socket
by dws (Chancellor) on Sep 11, 2003 at 08:32 UTC | |
by iburrell (Chaplain) on Sep 11, 2003 at 19:50 UTC |