cpp-httplib v0.46.0
DRAFT

C16. プロキシを経由してリクエストを送る

社内ネットワークや特定の経路を通したい場合、HTTPプロキシを経由してリクエストを送れます。set_proxy()でプロキシのホストとポートを指定するだけです。

基本の使い方

httplib::Client cli("https://api.example.com");
cli.set_proxy("proxy.internal", 8080);

auto res = cli.Get("/users");
httplib::Client cli("https://api.example.com");
cli.set_proxy("proxy.internal", 8080);

auto res = cli.Get("/users");

プロキシ経由でリクエストが送られます。HTTPSの場合はCONNECTメソッドでトンネルが張られるので、cpp-httplib側で特別な設定は要りません。

プロキシに認証を設定する

プロキシ自体が認証を要求する場合は、set_proxy_basic_auth()set_proxy_bearer_token_auth()を使います。

cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("user", "password");
cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("user", "password");
cli.set_proxy_bearer_token_auth("token");
cli.set_proxy_bearer_token_auth("token");

OpenSSL(または他のTLSバックエンド)付きでビルドしていれば、Digest認証も使えます。

cli.set_proxy_digest_auth("user", "password");
cli.set_proxy_digest_auth("user", "password");

エンドのサーバー認証と組み合わせる

プロキシ認証と、エンドサーバーへの認証(C05. Basic認証を使うC06. BearerトークンでAPIを呼ぶ)は別物です。両方が必要なら、両方設定します。

cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("proxy-user", "proxy-pass");

cli.set_bearer_token_auth("api-token"); // エンドサーバー向け
cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("proxy-user", "proxy-pass");

cli.set_bearer_token_auth("api-token"); // エンドサーバー向け

プロキシにはProxy-Authorization、エンドサーバーにはAuthorizationヘッダーが送られます。

特定のホストだけプロキシをバイパスする

社内エンドポイントなどはプロキシを経由させたくないことがあります。set_no_proxy()で除外リストを指定できます。

cli.set_proxy("proxy.internal", 8080);
cli.set_no_proxy({"internal.corp", "10.0.0.0/8", "*.dev.local"});
cli.set_proxy("proxy.internal", 8080);
cli.set_no_proxy({"internal.corp", "10.0.0.0/8", "*.dev.local"});

エントリは次のいずれかです。

  • * — すべてのホストでバイパス
  • ホスト名サフィックス(例: example.com)— example.com本体と任意のサブドメイン(foo.example.com)にマッチ。先頭にドットを付けても同じ意味です(.example.com)。
  • 単一のIPリテラル(例: 192.168.1.1::1
  • CIDRブロック(例: 10.0.0.0/8fe80::/10

ホスト名のマッチは大文字小文字を区別せず、ドット境界でしか一致しません。たとえばexample.comというエントリはevilexample.comにはマッチしません。IPの比較はinet_ptonで正規化されるので、127.0.0.1127.000.000.001のような別表記でバイパスすることはできません。マッチした場合、Proxy-Authorizationヘッダーも自動的に外れます。

不正な書式のエントリは黙って捨てられます。example.com:8080のようなポート指定エントリはサポート外です(cpp-httplibの他のホストキーAPIもホスト名のみを扱う設計のため)。

環境変数からプロキシ設定を読み込む

cpp-httplib本体はHTTP_PROXY / HTTPS_PROXY / NO_PROXYを読みません。set_ca_cert_path()と同じで、設定APIは常に明示的にしています。環境変数を反映させたい場合は、アプリ側で読んでset_proxy()set_no_proxy()に渡してください。

if (const char *v = std::getenv("no_proxy")) {
  std::vector<std::string> patterns;
  std::stringstream ss(v);
  for (std::string item; std::getline(ss, item, ',');) {
    if (!item.empty()) { patterns.push_back(item); }
  }
  cli.set_no_proxy(patterns);
}
if (const char *v = std::getenv("no_proxy")) {
  std::vector<std::string> patterns;
  std::stringstream ss(v);
  for (std::string item; std::getline(ss, item, ',');) {
    if (!item.empty()) { patterns.push_back(item); }
  }
  cli.set_no_proxy(patterns);
}

HTTP_PROXYも自分で読むなら、小文字のhttp_proxyだけを採用してください。大文字の方はCGI/FastCGI環境でProxy:リクエストヘッダーから汚染される可能性があります(CVE-2016-5385 / "httpoxy")。HTTPS_PROXYNO_PROXYは名前がHTTP_で始まらないので、どちらの大文字小文字でも安全です。

ESC