Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Calling LWP/Mech from AnyEvent

by Anonymous Monk
on Oct 29, 2012 at 18:09 UTC ( #1001399=perlquestion: print w/replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have a program that uses AnyEvent and I want to call Finance::MtGox, but do so without blocking the event loop. I tried both LWP::Protocol::AnyEvent::http and calling an internal method in Finance::MtGox to just construct the HTTP::Request and use AnyEvent::HTTP to make the request, but both of these result in a 400 Bad Request. I'm including the code so hopefully somebody can figure out where I'm going wrong. Thanks!

Need to subclass Finance::MtGox so the POST goes to a test server.

use Data::Dump; BEGIN { package Local::Finance::MtGox; use base 'Finance::MtGox'; sub _build_api_method_uri { return URI->new(""); } }
This works as expected, but it's blocking.
my $mtgox = Local::Finance::MtGox->new({ key => 'key', secret => 'secr +et' }); $mtgox->{mech}->ssl_opts(verify_hostname => 0); dd $mtgox->call_auth('getFunds');
This works and is non-blocking, but it is not very efficient if it is called many times or the parent process is large.
use AnyEvent; use AnyEvent::Util 'fork_call'; my $mtgox = Local::Finance::MtGox->new({ key => 'key', secret => 'secr +et' }); $mtgox->{mech}->ssl_opts(verify_hostname => 0); my $cv = AE::cv; fork_call { $mtgox->call_auth('getFunds') } sub { dd @_; $cv->send }; $cv->wait;
This doesn't work, it returns a 400 Bad Request.
use Coro; use LWP::Protocol::AnyEvent::http; my $mtgox = Local::Finance::MtGox->new({ key => 'key', secret => 'secr +et' }); my $coro = async { say "before"; $mtgox->call_auth('getFunds'); }; dd $coro->join;
This also doesn't work and returns a 400 Bad Request.
use AnyEvent; use AnyEvent::HTTP::Request; use AnyEvent::HTTP::Response; my $mtgox = Local::Finance::MtGox->new({ key => 'key', secret => 'secr +et' }); my $cv = AE::cv; my $req = AnyEvent::HTTP::Request->new( # Returns an HTTP::Request $mtgox->_build_api_method_request(POST => 'getFunds'), { cb => sub { my $res = AnyEvent::HTTP::Response->new(@_)->to_http_messa +ge; dd $res; $cv->send; } } ); $req->send; $cv->wait;

Replies are listed 'Best First'.
Re: Calling LWP/Mech from AnyEvent
by Anonymous Monk on Oct 30, 2012 at 19:11 UTC
    After ruling out the obvious, I used Charles proxy to see the decrypted request each method was making and it looks like AnyEvent::HTTP is probably mangling the request.

    This is what the working request looks like:

    POST /post HTTP/1.1 TE: deflate,gzip;q=0.3 Connection: TE, close Accept-Encoding: gzip Host: User-Agent: WWW-Mechanize/1.72 Content-Type: application/x-www-form-urlencoded Rest-Key: key Rest-Sign: eZsAHbbDBmD3/vHe7zg8IDdPJlV8WHBgHiAdd+ZDb8cD9TPHza4liDAYiLM +52nHLaGF2Jb9hlpoF 72SfxUg1Uw== Content-Length: 34 pass=&nonce=1351623186546267&name=
    And this is the mangled request from AnyEvent::HTTP:
    POST /post HTTP/1.1 User-agent: Mozilla/5.0 (compatible; U; AnyEvent-HTTP/2.14; +http://so Connection: close Te Rest-sign: GvzSzGg5WHPpL4O2bw48Q8lX6O5prasaiysH98FVS9oWYNfcs7pdUtWNpm7 +xGYG8zT3e0/BcPgHP LZWzMTdubg==
    I see the same behavior when changing from https to http.
Re: Calling LWP/Mech from AnyEvent
by Anonymous Monk on Nov 04, 2012 at 21:04 UTC
    This is now solved. It turns out LWP::Protocol::http replaces newlines in headers with spaces, and neither AnyEvent::HTTP, nor LWP::Protocol::AnyEvent::http did similar. Though the latter now does so with the latest CPAN update.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1001399]
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (7)
As of 2018-03-20 08:29 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (248 votes). Check out past polls.