Skip Menu |

This queue is for tickets about the Flickr-Upload CPAN distribution.

Report information
The Basics
Id: 50493
Status: resolved
Priority: 0/
Queue: Flickr-Upload

People
Owner: Nobody in particular
Requestors: avar [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 1.32
Fixed in: (no value)



Subject: Flickr::Upload doesn't check if HTTP requests were successful and gives invalid data to XML::Parser::Lite::Tree
In Flickr::Upload::upload_request the return value of $self->request( $req ) is only checked for definedness. Sometimes the flickr API will fail with some error or other and close the connection without sending any data back. With the attached debugging (see patch) this is what flickr_upload returns in this scenario: """ flickr_upload --public 0 --progress img_43??.jpg img_4373.jpg: 12% [============= ]ETA 15:04do { my $a = { "\$\@" => "junk '500 Server closed connection without sending any data back\n' before XML element\n", is_success => "", req => bless({ _content => sub { "???" }, _headers => bless({ "accept-encoding" => "gzip", "content-length" => 8168700, "content-type" => "multipart/form-data; boundary=MSZ3KssWaEg3L2BH1ZY982eiFcgSwQcbJtjAUxjZ", "user-agent" => "flickr_upload/1.32", }, "HTTP::Headers"), _method => "POST", _uri => bless(do{\(my $o = "http://api.flickr.com/services/upload/")}, "URI::http"), }, "HTTP::Request"), res => bless({ _content => "500 Server closed connection without sending any data back\n", _headers => bless({ "client-date" => "Wed, 14 Oct 2009 14:20:50 GMT", "client-warning" => "Internal response", "content-type" => "text/plain", }, "HTTP::Headers"), _msg => "Server closed connection without sending any data back", _rc => 500, _request => 'fix', }, "HTTP::Response"), tree => undef, }; $a->{res}{_request} = $a->{req}; $a; } """ It should instead: * Check if the request ->is_success * Wrap the call to the XML parser in eval * If either one of these fails try again say 3 times before giving up
Subject: flickr-upload-debugging-hack.patch
diff --git a/Upload.pm b/Upload.pm index 69e7e63..9608ef7 100644 --- a/Upload.pm +++ b/Upload.pm @@ -7,6 +7,7 @@ use LWP::UserAgent; use HTTP::Request::Common; use Flickr::API; use XML::Parser::Lite::Tree; +use Data::Dump 'dump'; our $VERSION = '1.32'; @@ -269,10 +270,39 @@ sub upload_request { die "expecting a HTTP::Request" unless $req->isa('HTTP::Request'); my $res = $self->request( $req ); - return () unless defined $res; - - my $tree = XML::Parser::Lite::Tree::instance()->parse($res->decoded_content()); - return () unless defined $tree; + if (not $res) { + warn "zomg request failed"; + print STDERR dump({ + is_success => $res->is_success, + req => $req, + res => $res, + }); + return () unless defined $res; + } + + ## Sometimes I'll get: + # junk '500 read failed: Connection reset by peer + # ' before XML element + ## From XML::Parser::LiteCopy which will die + my $tree; + { + local ($@, $!); + eval { + $tree = XML::Parser::Lite::Tree::instance()->parse($res->decoded_content()); + }; + + if ($@) { + print STDERR dump({ + is_success => $res->is_success, + tree => $tree, + req => $req, + res => $res, + '$@' => $@, + }); + } + + return () unless defined $tree; + } my $photoid = response_tag($tree, 'rsp', 'photoid'); my $ticketid = response_tag($tree, 'rsp', 'ticketid');
On Wed Oct 14 10:31:24 2009, AVAR wrote: This patch fixes the issue. It's better for you if you pull it from git://git.nix.is/avar/pm/Flickr- Upload-50493 You can view a diff at http://git.nix.is/?p=avar/pm/Flickr-Upload- 50493;a=commitdiff;h=6b2b1a87ccd4eabe66b28db56a2df7bf6e5f0f2b
diff --git a/Upload.pm b/Upload.pm index 69e7e63..048e0f5 100644 --- a/Upload.pm +++ b/Upload.pm @@ -268,11 +268,28 @@ sub upload_request { my $req = shift; die "expecting a HTTP::Request" unless $req->isa('HTTP::Request'); - my $res = $self->request( $req ); - return () unless defined $res; + # Try 3 times to upload data. Without this flickr_upload is bound + # to die on large uploads due to some miscellaneous network + # issues. Timeouts on flickr or something else. + my ($res, $tree); + my $tries = 3; + for my $try (1 .. $tries) { + # Try to upload + $res = $self->request( $req ); + return () unless defined $res; + + if ($res->is_success) { + $tree = XML::Parser::Lite::Tree::instance()->parse($res->decoded_content()); + return () unless defined $tree; + last; + } else { + my $what_next = ($try == $tries ? "giving up" : "trying again"); + my $status = $res->status_line; - my $tree = XML::Parser::Lite::Tree::instance()->parse($res->decoded_content()); - return () unless defined $tree; + print STDERR "Failed uploading attempt attempt $try/$tries, $what_next. Message from server was: '$status'\n"; + next; + } + } my $photoid = response_tag($tree, 'rsp', 'photoid'); my $ticketid = response_tag($tree, 'rsp', 'ticketid'); diff --git a/t/failupload_timeout.t b/t/failupload_timeout.t new file mode 100644 index 0000000..1cbcfd7 --- /dev/null +++ b/t/failupload_timeout.t @@ -0,0 +1,60 @@ +no strict 'refs'; +no warnings 'redefine'; +use Test::More qw(no_plan); +BEGIN { use_ok('Flickr::Upload') }; + +# Overwrite LWP::UserAgent::request to emulate the server closing the +# connection on us. Which can happen e.g. if the network sucks or if +# we C-z flickr_upload + +BEGIN { + our $old_request = *{"LWP::UserAgent::request"}{CODE}; + our $times = 0; +} + +sub LWP::UserAgent::request { + $times ++; + + # Return the real LWP::UserAgent::request + if ($times == 3) { + *LWP::UserAgent::request = $old_request; + goto &LWP::UserAgent::request; + } + + bless({ + _content => "500 Server closed connection without sending any data back\n", + _headers => bless({ + "client-date" => "Wed, 14 Oct 2009 14:44:46 GMT", + "client-warning" => "Internal response", + "content-type" => "text/plain", + }, "HTTP::Headers"), + _msg => "Server closed connection without sending any data back", + _rc => 500, + _request => 'fix', + }, "HTTP::Response"), +} + +my $api_key = '8dcf37880da64acfe8e30bb1091376b7'; +my $not_so_secret = '2f3695d0562cdac7'; + +# grab auth token. If none, fail nicely. +my $pw = '******'; +open( F, '<', 't/password' ) || (print STDERR "No password file\n" && exit 0); +$pw = <F>; +chomp $pw; +close F; + +my $ua = Flickr::Upload->new({'key'=>$api_key, 'secret'=>$not_so_secret}); +ok(defined $ua); + +my $rc = $ua->upload( + 'photo' => 't/testimage.jpg', + 'auth_token' => $pw, + 'tags' => "test kernel perl cat dog", + 'description' => "Flickr Upload test for $0", + 'is_public' => 0, + 'is_friend' => 0, + 'is_family' => 0, +); + +ok( defined $rc );
It appears that this patch is part of the 1.4 release, and 'make test' shows a pass for failupload.t, so I'm closing this issue.