LWP::UserAgent::env_proxy

proxy 通さなきゃいけない環境でも LWP::UA を使うのは結構簡単.適切な環境変数を定義しておき,env_proxy を呼ぶ.すると,あとは LWP::UA がよしなにしてくれる.例えばこんな感じ.

use LWP::UserAgent;

$ENV{HTTP_PROXY} = $ENV{FTP_PROXY} = 'http://user:pass@proxy.example.com:8080';
$ENV{NO_PROXY} = '127.0.0.1, localhost';

my $ua = LWP::UserAgent->new;
$ua->env_proxy;
# or 
my $ua = LWP::UserAgent->new(env_proxy => 1);

user:pass@ の部分は必要に応じて記述すればよい.user/pass 付きだと,リクエストヘッダに Proxy-Authorization を自動的に付けてくれるのでありがたい.

ちゃんと no_proxy にも対応していて,localhost など proxy を通さなくてもよいホストを $ENV{NO_PROXY} に split /\s*,\s*/ で区切れるように設定しておくと,それらホストへのリクエストの場合は proxy 関連のヘッダを含めないようになる.

ほげほげ_PROXY っていう環境変数が特に無い場合,env_proxy は別に何もしないだけなので,あえて env_proxy を呼んでもたいした損は無い.LWP::UA 使ってモジュール作る場合なんかは,むしろ幸せになれる人のほうが多いかも?

ただ,残念なことに,LWP::UA は 192.168.0.0/24 といった形式の no_proxy には対応していない.Firefox の proxy 設定なんかだと受け付けてくれるのにね.サブネット全般に渡ってアドレスを1個1個設定していくのは萎えてしまう.ということで,サブネット形式でも指定できるパッチを書いた.どうやらパッチ期に入ったらしい.

--- lib/LWP/UserAgent.pm.orig	Fri Nov 12 03:12:04 2004
+++ lib/LWP/UserAgent.pm	Thu Apr 13 12:37:56 2006
@@ -28,8 +28,8 @@
     };
 }
 
+use constant HAS_NET_SUBNETS => eval { require Net::Subnets; 1 } || 0;
 
-
 sub new
 {
     my($class, %cnf) = @_;
@@ -782,6 +782,20 @@
 		    if ($host =~ /\Q$domain\E$/) {
 			LWP::Debug::trace("no_proxy configured");
 			return;
+		    }
+
+		    # check $host is in $domain subnets,
+		    #   e.g., $ENV{NO_PROXY} includes '192.168.0.0/24';
+		    #         $domain is '192.168.0.0/24' and $host is '192.168.0.10'
+		    next unless HAS_NET_SUBNETS;
+		    my $re = join '\.', ('(?:2(?:[0-4][0-9]|5[0-5])|1[0-9]{2}|[1-9]?[0-9])') x 4;
+		    if ($host =~ /^$re$/ and $domain =~ m!^$re/(?:3[0-2]|[12][0-9]|[1-9])$!) {
+			my $sn = Net::Subnets->new;
+			$sn->subnets([$domain]);
+			if (my $subnetref = $sn->check(\$host)) {
+			    LWP::Debug::trace("no_proxy configured");
+			    return;
+			}
 		    }
 		}
 	    }

さしあたって,Net::Subnets があるときだけチェックするようにした.このパッチは Gisle に投げてみようかな.