LoginSignup
12
8

More than 5 years have passed since last update.

LWP::UserAgentでHTTPSプロキシ越しに通信する

Last updated at Posted at 2013-03-07

概要

LWP::UserAgent(バージョン6.06未満)でプロキシ越しにHTTPS通信をやろうとすると、何も考えずに設定すると

GET https://example.com/index.html

のように、CONNECTメソッドを使わずhttpsスキームのリクエストURLをそのままプロキシに投げてしまう。
このようなリクエストはSquidなどのプロキシではサポートされておらず、エラーになってしまう。
(Apache mod_proxyならイケるっぽい?)

CONNECTメソッドによる通信をやらせるには、いろいろと環境変数を設定する必要がある。

参考

割と以前から認識されている問題なのになぜかドハマりしてしまったのでここに書き留めておきます。

LWP::Protocol::connectを使う解決策はこちら → LWP::UserAgentでHTTPSプロキシ越しに通信する (LWP::Protocol::connect編)

検証バージョン

  • Ubuntu 12.04.1
  • perl 5.14.2
  • LWP::UserAgent 6.04
  • Crypt::SSLeay 0.64
  • Net::SSL 2.85
  • Net::Twitter 4.00003

サンプルコード

lwp_https_proxy_sample.pl
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request;

## ** See https://metacpan.org/module/Net::HTTPS
## Force use of Net::SSL instead of IO::Socket::SSL
$ENV{PERL_NET_HTTPS_SSL_SOCKET_CLASS} = 'Net::SSL';

## ** See https://metacpan.org/module/Crypt::SSLeay#ENVIRONMENT-VARIABLES
$ENV{HTTPS_PROXY} = 'http://your-https-proxy:8080';
$ENV{HTTPS_CA_DIR} = '/etc/ssl/certs';
## $ENV{HTTPS_DEBUG} = 1; ## ** Uncomment this for debug output


## ** See https://metacpan.org/module/LWP#ENVIRONMENT
## ** Uncomment this to disable server verification.
## ** You usually shouldn't do this, though.
## $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;

my $ua = LWP::UserAgent->new;

## ** This lets LWP::UserAgent to handle HTTPS proxying, but that's wrong.
$ua->env_proxy;

## ** Explicitly disables HTTPS proxy by LWP::UserAgent.
## ** Just let Crypt::SSLeay do the job.
$ua->proxy(https => undef);

my $req = HTTP::Request->new('GET', 'https://metacpan.org/module/LWP::UserAgent');
my $res = $ua->request($req);

print $res->as_string, "\n";
  • CONNECTメソッドを使うためには、プロキシ処理をLWP::UserAgentではなくCrypt::SSLeayに任せる必要がある。
  • そのために、LWP::UserAgentではプロキシ設定を行わない
  • env_proxy()メソッドを呼んでもいいが、その後に必ず$ua->proxy(https => undef)としてプロキシ設定を消す。
  • Crypt::SSLeayにプロキシ設定を伝えるには環境変数を使う。
  • その際、環境変数HTTPS_CA_DIRで認証局証明書ディレクトリを指定しないとサーバ証明書の検証でエラーになる。
  • さらに、環境変数PERL_NET_HTTPS_SSL_SOCKET_CLASSNet::SSLに設定しないと、そもそもCrypt::SSLeayが使われないようだ。
    • LWP::Protocol::httpsNet::HTTPSを使っており、Net::HTTPSIO::Socket::SSLを優先的に使い、環境変数などで指定された場合にNet::SSLを使うから。

LWP::UserAgentを使う別のモジュールを使う場合

例えば、Net::TwitterなんかはLWP::UserAgentを内製して内部でenv_proxy()を呼んでしまう。

Net::Twitterの場合は幸い、使用するUserAgentクラスをカスタマイズできるので、以下のようにenv_proxy()を無力化するクラスを作って与えればいいと思う。

lwp_useragent_noenv.pl
package LWP::UserAgent::NoEnv;
use strict;
use warnings;
use base ('LWP::UserAgent');

sub env_proxy {
    print STDERR "Fake env_proxy called.\n";
}
1;

そういうカスタマイズのポイントがないモジュールの場合は・・・、LWP::UserAgent自体を外から上書きするのかなあ・・・。うーむ。

12
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
8