Ovid has asked for the wisdom of the Perl Monks concerning the following question:

I'm probably just having a brain cramp, but I'm having problems subclassing WWW::Mechanize. According to the docs:

$a->request( $request [, $arg [, $size]])

Overloaded version of request() in the LWP::UserAgent manpage. Performs the actual request. Normally, if you're using WWW::Mechanize, it'd because you don't want to deal with this level of stuff anyway.

Note that $request will be modified.

Returns an the HTTP::Response manpage object.

_make_request()

Convenience method to make it easier for subclasses like WWW::Mechanize::Cached to intercept the request.

So we can intercept the _make_request() method if we want to sublass Mechanize and it appears to return an HTTP::Response object (you have to read the code to really see that). I am subclassing to be able to use Mechanize to test Mason code, but the following minimal test script fails:

package WWW::Mechanize::Mason; use strict; use HTTP::Status qw/RC_OK RC_NOT_FOUND/; use base 'WWW::Mechanize'; # we can make it work by also inheriting fr +om Clone sub _make_request { my ($self,$request,@rest) = @_; my $uri = $request->uri->as_string; my $response_content = "foobar\n"; # we'll probably have to build in support for redirects at some po +int my $response = HTTP::Response->new( defined $response_content ? RC_OK : RC_NOT_FOUND, ); $response->request($request); $response->push_header('Content-Type', 'text/html'); $response->content($response_content); return $response; } package main; my $browser = WWW::Mechanize::Mason->new; $browser->get('/TEST/mason.txt'); print $browser->content; $browser->get('/TEST/mason.txt'); print $browser->content;

After the second call to get(), the program dies with this message:

Can't use an undefined value as a HASH reference at /dp/usr/cxp/perl/lib/LWP/UserAgent.pm line 1036

Digging into this, I find that the program dies after the call to to _make_request() and I see that the problem lies with LWP::UserAgent::clone expecting its object to have a 'proxy' key, but the value is undef and the code can't dereference it. The quick workaround was to have my stuff also inherit from Clone, but that was causing some problems with a different, much larger script that I've had trouble reducing down.

The troublesome method in LWP::UserAgent:

sub clone { my $self = shift; my $copy = bless { %$self }, ref $self; # copy most fields # elements that are references must be handled in a special way $copy->{'proxy'} = { %{$self->{'proxy'}} }; # here's where we die! $copy->{'no_proxy'} = [ @{$self->{'no_proxy'}} ]; # copy array # remove reference to objects for now delete $copy->{cookie_jar}; delete $copy->{conn_cache}; $copy; }

Suggestions for the best way to fix this are welcome. I can make Clone work, but it doesn't seem like a clean fix.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Subclassing WWW::Mechanize
by petdance (Parson) on Nov 14, 2003 at 19:46 UTC
    Sorry I haven't had time to check into your problems, but please don't turn to Clone. I spent a fair amount of time extracting Mech from Clone after Clone was causing segfaults.

    xoxo,
    Andy

Re: Subclassing WWW::Mechanize
by LTjake (Prior) on Nov 14, 2003 at 20:25 UTC

    Here's my quick fix:

    sub _make_request { my ($self,$request,@rest) = @_; # fake a proxy $self->proxy( [ undef ] ); my $uri = $request->uri->as_string; my $response_content = "foobar\n"; # we'll probably have to build in support for redirects at some po +int my $response = HTTP::Response->new( defined $response_content ? RC_OK : RC_NOT_FOUND, ); $response->request($request); $response->push_header('Content-Type', 'text/html'); $response->content($response_content); return $response; }

    It's a hack i know, but it gives me this output (with some added debug code (LWP::Debug))

    LWP::UserAgent::new: () LWP::UserAgent::proxy: ARRAY(0x1ccb53c) LWP::UserAgent::proxy: undef LWP::UserAgent::proxy: foobar LWP::UserAgent::proxy: ARRAY(0x1da22b4) LWP::UserAgent::proxy: undef LWP::UserAgent::proxy: foobar

    --
    "To err is human, but to really foul things up you need a computer." --Paul Ehrlich