概要
LWP::UserAgent(バージョン6.06未満)でプロキシ越しにHTTPS通信をやろうとすると、何も考えずに設定すると
GET https://example.com/index.html
のように、CONNECTメソッドを使わずhttpsスキームのリクエストURLをそのままプロキシに投げてしまう。
このようなリクエストはSquidなどのプロキシではサポートされておらず、エラーになってしまう。
(Apache mod_proxyならイケるっぽい?)
「LWP::UserAgentでHTTPSプロキシ越しに通信する」の投稿では、環境変数を設定することでCONNECTメソッドを有効にした。
今回は、LWP::Protocol::connectモジュールを使ってCONNECTメソッドを使う。
検証環境
- Ubuntu 12.04.2
- perl 5.14.2
- IO::Socket::INET6 2.71
- IO::Socket::IP 0.22
- IO::Socket::SSL 1.953
- LWP::UserAgent 6.05
- LWP::Protocol::connect 6.03
- LWP::Protocol::https 6.02
- Net::HTTPS 6.04
サンプルコード
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request;
my $ua = LWP::UserAgent->new;
$ua->proxy('https', 'connect://localhost:3128/');
## ** If you want to disable peer verification (NOT RECOMMENDED)
## $ua->ssl_opts(verify_hostname => 0);
## ** If you want to explicitly specify the directory containing CA certificates.
## $ua->ssl_opts(SSL_ca_path => '/etc/ssl/certs');
my $req = HTTP::Request->new('GET', 'https://metacpan.org/module/LWP::UserAgent');
my $res = $ua->request($req);
print $res->as_string, "\n";
ポイント
LWP::Protocol::connect
をインストールした状態で、
$ua->proxy('https', 'connect://PROXY_HOSTNAME:PORT');
を設定する。
LWP::Protocol::connect
はconnect://
という独自スキームを使うので、これだけだと一般的な環境変数の設定を解釈できないのが玉にキズではある。
ハマりどころ
上記のサンプルコードを実行すると、以下のようなエラーが出ることがある。
Bad arg length for Socket6::unpack_sockaddr_in6, length is 16, should be 28 at /usr/lib/perl5/Socket6.pm line 282.
これはIO::Socket::INET6
のバグ: https://rt.cpan.org/Public/Bug/Display.html?id=68282
(さらに元をたどるとIO::Socket
のバグらしい)
IO::Socket::IP
をインストールすると直る。これは、IO::Socket::SSL
がIO::Socket::IP
を優先して使うため。
参考: 各モジュールの使役関係
- 同じレベルの
->
は 「いずれかを選択して使う」 という意味 - 継承関係を表すわけではないので注意!
- 間違いがあったらご指摘お願いします
LWP::UserAgent
-> LWP::Protocol::connect
-> LWP::Protocol::https::connect
-> LWP::Protocol::https
-> Net::HTTPS
-> IO::Socket::SSL
-> IO::Socket::IP
-> IO::Socket::INET6
-> IO::Socket::INET
-> Net::SSL
-> IO::Socket::INET + Crypt::SSLeay