Why isn't agent() set when using LWP::Parallel::UserAgent?

158 views Asked by At

It appears to be undefined when looking at UserAgent.pm. At least, as far as I know, it is undefined when the routine gets to that part, even though I'm explicitly setting it with $pua->agent(). Is this a bug? There's also init_header(), but when I tried $pua->request->init_header(), it also failed to set.

#!/bin/perl

use LWP::Parallel::UserAgent;

my $ua_string =
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36";

my $url  = "http://www.example1.com";
my $url2 = "http://www.example2.com";

my $reqs = [
    HTTP::Request->new( 'GET', $url ),
    HTTP::Request->new( 'GET', $url2 )
];

my ( $req, $res );

my $pua = LWP::Parallel::UserAgent->new();

$pua->agent($ua_string);

foreach $req ( @$reqs ) {
    $pua->register( $req );
}

my $entries = $pua->wait();
foreach ( keys %$entries ) {
    $res = $entries->{$_}->response;
    my $r = $res;
    my @redirects;
    while ( $r ) {
        $res = $r;
        $r   = $r->previous;
        push( @redirects, $res ) if $r;
    }
}
1

There are 1 answers

20
Schwern On

Sorry about the confusion, $pua->agent is set, but LWP::Parallel::UserAgent isn't using it. This is a long standing bug in LWP::Parallel::UserAgent.

LWP::Parallel::UserAgent is a subclass of LWP::UserAgent but it's a poorly behaved subclass. Rather than using accessors it grabs at internal fields and assumes the agent will be stored in $self->{agent}. Maybe it once was, but it isn't anymore.

Your particular problem is in LWP::Parallel::UserAgent::init_request() starting at line 1506.

# Extract fields that will be used below
my ($agent, $from, $timeout, $cookie_jar,
    $use_eval, $parse_head, $max_size, $nonblock) =
  @{$self}{qw(agent from timeout cookie_jar
              use_eval parse_head max_size nonblock)};

This assumes the user-agent is stored in $self->{agent}. It isn't. It should instead do something like this to call each accessor in turn.

my %fields;
my @fields = qw(agent from timeout cookie_jar parse_head max_size);
for my $field (@fields) {
    $fields{$field} = $self->$field();
}

Or just use the accessors directly. This will use the documented interface for LWP.

nonblock and use_eval are special cases. These are not LWP::UserAgent fields, they were added by LWP::Parallel. There is no accessor method for use_eval. There is a LWP::Parallel::UserAgent::nonblock() but its only a setter. I don't think this is intentional.

Since it doesn't define an accessor for use_eval, and should add one. And you could fix nonblock to always return its value.

sub nonblock {
    my $self = shift;
    $self->{'nonblock'} = $_[0] if defined $_[0];
    return $self->{nonblock};
}

LWP::Parallel::UserAgent is being actively maintained, you should send a bug report and maybe a patch.