銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Linux の dotnet restore は大文字HTTP_PROXYを認識しない、あるいは curlコマンドは大文字HTTP_PROXYを認識しない件

微妙にハマったので、書いておきます。.NET Core CLI のdotnet restoreコマンドをプロキシ環境下のLinux*1で使う場合、環境変数http_proxyは小文字で設定する必要があります。ちなみにこれはcurlコマンドでも同じです。ちなみにhttps_proxyもしくはHTTPS_PROXYはどちらでも動くのですが、少し挙動が異なるので最後に補足します。

man curl からの抜粋

The environment variables can be specified in lower case or upper case. The lower case version has precedence. http_proxy is an exception as it is only available in lower case.

せっかくなのでコードを追ってみましょう。dotnet restoreはNuGet.Coreを参照してつかっています。環境変数http_proxyのキーはここで定義されています。

NuGet.Client/ConfigurationContants.cs at 3.4.5 · NuGet/NuGet.Client · GitHub

そして、ここで環境変数を取得していますが、この時大文字小文字は区別していません。

NuGet.Client/ProxyCache.cs at 3.4.5 · NuGet/NuGet.Client · GitHub

つまり、大文字でHTTP_PROXYをセットしてもLinux*2では無視されてしまうのです。また、この後のコードを見るとわかるようにURLのチェックをしているので、不正なURLを指定すると警告なしで無視され、プロキシなしでアクセスを試みます。ちなみに認証付きプロキシの場合は、http://user:passowrd@host/http://<username>:<password>@proxy.comの形式で指定すれば動くらしいのですが、手元に認証つきプロキシの環境をすぐに用意できていないので、検証していないです。 また、NuGetのAPIエンドポイントはhttps なのにhttp_proxyなのか?というのもありますが、これもコードを見ると、http_proxyが指定してあればNuGet.Clientがその値を読み取ってそのプロキシサーバーをNuGetの通信ではhttpsでも使うように設定しています。

さて、https_proxy でNuGetのリポジトリを検索してもなにもヒットしません。この環境変数を読み取ることはしていないようです。しかし、https_proxyもしくはHTTPS_PROXYに値をセットするとdotnet restoreのときに使われます。しかもhttp_proxyとは違って不正なURLの場合も使われて、その結果URLにアクセスできない場合はエラーになります。これはなぜ起きるかというと、NuGet.Core がHTTP通信に使っている System.Net.HttpがUnixプラットフォームではcurlライブラリに処理を委譲しているからのようです。

corefx/src/System.Net.Http/src/System/Net/Http/Unix at master · dotnet/corefx · GitHub

さきほどの curl のmanの続きにhttps_proxyもあって、これは大文字小文字を区別しないので、どちらを設定しても使われる挙動になっていました。

なんというかわかりづらい挙動で、はまると抜け出すのが面倒な気がするのでどこかに書いてあると便利な気がするんですが、どこがいいんだろうと悩んでいるところです。

追記: よく見たら、NuGet.configのドキュメントに大文字環境変数で動くと書いていたのでPRを出しました。

*1:確認できないけど多分Macも

*2:正確には環境変数で大文字小文字を区別しないプラットフォーム