Tatsumaki::HTTPClient で Pixivにログインする

メモ的に書きます。ので、やっつけです。

AnyEvent::HTTP で pixivにログインしようとする際に recurse を指定しておかないと、/login.php にデータをポストした後、自動的に Loation ヘッダが示すURLに移動しようとします。
が、Content-Lenghtなど を保持したまま移動しようしているようで、そのままでは上手く移動できません。なので、recurse => 0 指定して、レスポンスが帰って来たら Locationが示すURLに移動するなどします。

が、Tatsumaki::HTTPClient では recurse 指定する方法がありません。なので Tatsumaki::HTTPClient を拡張して使えるようにしてみます。

package Tatsumaki::HTTPClient::Custom;
use Tatsumaki;
use AnyEvent::HTTP;
use Moo;
use MooX::late;
extends qw(Tatsumaki::HTTPClient);

has jar => (is => 'rw', isa => 'HashRef', default => sub { +{version => 1} });
has recurse => (is => 'rw', isa => 'Num', default => $AnyEvent::HTTP::MAX_RECURSE);
has agent => (is => 'rw', isa => 'Str', default => sub { join '/', __PACKAGE__, $Tatsumaki::VERSION });

sub request {
    my($self, $request, $cb) = @_;
    my $jar = $self->jar; # add
    my $headers = $request->headers;
    $headers->{'user-agent'} = $self->agent;
    ### delete $headers->{'content-length'}; ###

    my %options = (
        timeout => $self->timeout,
        headers => $headers,
        body    => $request->content,
        cookie_jar => $jar, # add
        recurse => $self->recurse, #add
    );

    AnyEvent::HTTP::http_request $request->method, $request->uri, %options, sub {
        my($body, $header) = @_;
        my $res = HTTP::Response->new($header->{Status}, $header->{Reason}, [ %$header ], $body);
        $self->jar($jar); # add
        $cb->($res);
    };
}

package main;
use strict;
use warnings;
use AE;

my $login_php = 'http://www.pixiv.net/login.php';
my %query = (mode => 'login', pixiv_id => 'foo', pass => 'bar');
my $client = Tatsumaki::HTTPClient::Custom->new(recurse => 0);
my $cv = AE::cv;

$client->post($login_php => \%query, sub {
    my $response = shift;

    ### Tatsumaki::HTTPClient::Custom::request で delete $headers->{'content-length'} しておくと
    ### 以降のリクエストは AnyEvent::HTTP がめんどうみてくれる
    $client->get($response->header('location'), sub {
        my $response = shift;
        # some work ...
        $cv->send;
    });
});

$cv->recv;

ただ、これだとたるいので、Tatsumaki::HTTPClient::Custom::request の $headers->{'user-agent'} = $self->agent; の後に delete $headers->{'content-length'} しておけば、recurse => 0 する必要も、再度 get リクエストする必要もないので、たるい時にはそれでいいかもしれないです。