LWP::UserAgentのtimeoutエラー判定法 (Can't connect to (connect: timeout)を出力してる場所のメモ)

LWP::UserAgentでtimeoutをセットしたときに、
「timeout」と「それ以外のエラー」を判別したい。


以下のようなコードを見つけたのだが、

use LWP::UserAgent;
use XML::TreePP;

my $ua = LWP::UserAgent->new();
   $ua->timeout(3);
my $tpp = XML::TreePP->new();
   $tpp->set(lwp_useragent => $ua);
my ($tree, $xml, $code) = $tpp->parsehttp(GET => 'http://d.hatena.ne.jp/favril/rss');  # 本当はAPIのリクエストURLとか
if ( $code == 200 ) {
    print "取得成功\n";
} elsif ( ($code == 500) && ($xml =~ /\(connect: timeout\)/) ) {
    print "タイムアウト\n";
} else {
    print "タイムアウト以外のエラー";
}

タイムアウトを判定している "(connect: timeout)" なる文字列が、
一体どこで出力されているのか簡単には辿り着けず(orz)、
この判定法が一般的に使えるのかどうか迷ったのでメモ*1


XML::TreePPを探しても、LWP::UserAgentを探しても、
そんな文字列は見当たらなかったので困ったが、
結論から言うと、以下にあった。


LWP::Protocol::http.pm

my $sock = $self->socket_class->new(PeerAddr => $host,
                                    PeerPort => $port,
                                    Proto    => 'tcp',
                                    Timeout  => $timeout,
                                    KeepAlive => !!$conn_cache,
                                    SendTE    => 1,
                                    $self->_extra_sock_opts($host, $port),
                                   );

unless ($sock) {
    # IO::Socket::INET leaves additional error messages in $@
    $@ =~ s/^.*?: //;
    die "Can't connect to $host:$port ($@)";
}


LWP::UserAgentの中で見るとたぶんここ。
LWP::UserAgent.pm

if (!$response && $self->{use_eval}) {
    # we eval, and turn dies into responses below
    eval {
        $response = $protocol->request($request, $proxy,
                                       $arg, $size, $self->{timeout});
    };
    if ($@) {
        $@ =~ s/ at .* line \d+.*//s;  # remove file/line number
        $response = _new_response($request,
                                  &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
                                  $@);
    }
}


ということで、LWP::UserAgentを使ってる分には、
上に書いた判定方法でたぶん問題ない。

      • -

ちなみに、上記のタイムアウトは、接続時点のタイムアウトで、
接続はできたけど、データを受信し切れなかったとかだと、「500 read timeout」になるのかな?
エラーメッセージ作ってるのは以下。
LWP::Protocol::http.pm

if (my $timeout = ${*$self}{io_socket_timeout}) {
    die "read timeout" unless $self->can_read($timeout);
}

*1:そもそも、XML::TreePPが出してるのか、LWP::UserAgentが出してるのかすら最初はわからなかった