File::FetchモジュールのLWP部の$uriが微妙な気がする => はじめてのPerl Debugger

File::Fetchというモジュールがあります。
uriを与えるとその先頭文字列から、複数方法の取得をしてくれる便利な(?)モジュール。
version 5.9.5からcore入りのようです。


$ perldoc File::Fetch
...
File::Fetch is able to fetch a variety of uris, by using several
external programs and modules.

Below is a mapping of what utilities will be used in what order for
what schemes, if available:

file => LWP, file
http => LWP, wget, curl, lynx
ftp => LWP, Net::FTP, wget, curl, ncftp, ftp
rsync => rsync
...
$ corelist File::Fetch

File::Fetch was first released with perl 5.009005
$

cpanp の中でもこれを使ってcpanミラーサイトにアクセスしているようです。
で、Solaris環境では気づかなかったのですが、Strawberry Perl 環境で動かすとエラーになる?ということで調べてみました。

で、perldocの中から、ほぼ同じサンプルプログラムを書きます。(試したのはsakuraのサーバ上)


$ cat FileFetch.pl
#!/home/handler/local/bin/perl

use strict;
use warnings;

use File::Fetch;

my $ff = File::Fetch->new(uri=>'http://d.hatena.ne.jp/handler/rss');

my $where = $ff->fetch or die $ff->error;

__END__
$
$ ~/local/bin/perl FileFetch.pl
$ ls -al rss
-rw-r--r-- 1 handler users 5471 Dec 16 21:36 rss
$

まぁ、普通に動きます。
でも、、、


$ ~/local/bin/perl -d FileFetch.pl
Loading DB routines from perl5db.pl version 1.3
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.
...
DB<1> l File::Fetch::_lwp_fetch
Switching to file '/home/handler/local/lib/perl5/5.10.0/File/Fetch.pm'.
494 sub _lwp_fetch {
495: my $self = shift;
496: my %hash = @_;
497
498: my ($to);
499: my $tmpl = {
500 to => { required => 1, store => \$to }
501 };
502: check( $tmpl, \%hash ) or return;
503
DB<2>
DB<2> l 503+30
503
504 ### modules required to download with lwp ###
505: my $use_list = {
506 LWP => '0.0',
...
521 ### special rules apply for file:// uris ###
522: $uri->scheme( $self->scheme );
523: $uri->host( $self->scheme eq 'file' ? '' : $self->host );
524: $uri->userinfo("anonymous:$FROM_EMAIL") if $self->scheme ne 'file';
525
526 ### set up the useragent object
527: my $ua = LWP::UserAgent->new();
528: $ua->timeout( $TIMEOUT ) if $TIMEOUT;
529: $ua->agent( $USER_AGENT );
530: $ua->from( $FROM_EMAIL );
531: $ua->env_proxy;
532
533: my $res = $ua->mirror($uri, $to) or return;
DB<3>
DB<3> b 527
DB<4> L
/home/handler/local/lib/perl5/5.10.0/File/Fetch.pm:
527: my $ua = LWP::UserAgent->new();
break if (1)
DB<4>
DB<4> n
main::(FileFetch.pl:10): my $where = $ff->fetch or die $ff->error;
DB<4>
File::Fetch::_lwp_fetch(/home/handler/local/lib/perl5/5.10.0/File/Fetch.pm:527):
527: my $ua = LWP::UserAgent->new();
DB<4>

DB<4> print $uri
http://anonymous:File-Fetch%40example.com@d.hatena.ne.jp/handler/rss
DB<5>
DB<5> q

perlのデバッガスイッチ(-d)の使い方は、perldebugのドキュメントにくわしく載っています。
とりあえず、使ったのは、以下です。(事前にソース読んであたりをつけています)


DB<1> l File::Fetch::_lwp_fetch
DB<2> l 503+30
DB<3> b 527
DB<4> L
DB<4> n
DB<4> print $uri
DB<5> q

"l モジュール名::関数名" で、その関数の先頭ソースコードを表示。
"l min+incr" で、ソースコードの min行目からincr行分表示。
"b line" で、 line行目にブレークポイントの挿入。
"L" で、ブレークポイントとアクションの表示。
"n" で、next。
"print $uri" で、実際の変数を表示。
"q" で、quit

で、結論としては、File::Fetchを使って、httpを取得しようとするとuriホスト部前にゴミが付きます。
(File::Fetchのversionは0.14)


my $ff = File::Fetch->new(uri=>'http://d.hatena.ne.jp/handler/rss');
で、与えたuriが、関数内の$uriでは、、、

DB<4> print $uri
http://anonymous:File-Fetch%40example.com@d.hatena.ne.jp/handler/rss

RFC1738 Uniform Resource Locators (URL) に書式は定義されています。


3.1. Common Internet Scheme Syntax

While the syntax for the rest of the URL may vary depending on the
particular scheme selected, URL schemes that involve the direct use
of an IP-based protocol to a specified host on the Internet use a
common syntax for the scheme-specific data:

//:@:/

Some or all of the parts ":@", ":",
":", and "/" may be excluded. The scheme specific
data start with a double slash "//" to indicate that it complies with
the common Internet scheme syntax.

ブラウザからのFTP接続とかでは馴染みがありますが、File::Fetchに普通のhttp://〜のURIを指定しても上記のユーザ名とパスワードが挿入されてしまいます。
で、普通のサイトは認証がないので、そのままコンテンツを取得できているようなのですが、、、少なくとも会社のproxyを通すとコケマス。
(あんまり検証してません。)

Solaris(Linux)環境だと、このFile::FetchのLWP部分で失敗しても次のwget部分で成功します。(上記の挿入は、_lwp_fetchの中しかない)
で、Strawberry Perl 単体だと、以下のwget,curl,lynxWindows環境にないのでこけていたということのようです。(cygwinとか入れてりゃ動くかも)


http => LWP, wget, curl, lynx

なんで、あんな挿入が入るんだ。。。
まぁ、File/Fetch.pmのL.524($uri->userinfo...)をコメントアウトすれば、とりあえずは動くんですが。
個人的に、File::Fetch単体では使わないのですが、cpanpの中でコイツが動いているので意外とやっかいな気がする。。。