subversionを認証必須のプロキシ経由で使いたい

目的

id:taiyo:20080401#p1 を参照。

結果

リポジトリhttpsでアクセスする場合のみ可能(httpアクセスは、プロキシサーバがPROPFINDメソッドを許可していないため、不可能)。

~/.subversion/servers に、以下の設定を記述する:

[groups]
external = sssvn.jp, svn.ruby-lang.org

[external]
http-proxy-host = abcproxy.examlple.com
http-proxy-port = 8080
http-proxy-username = 4000000
http-proxy-password = PassWord
ssl-trust-default-ca = yes

ファイルのパーミッションも適切に。

※外部にあるリポジトリにしかアクセスしない場合は、"[global]"セクションに書いても良い。

subversionの仕様

Subversion Book(Chapter 7. Advanced Topics)に、以下のように書いてある。

  • /etc/subversion か ~/.subversion にある、config と servers という設定ファイルを読み込み
  • 設定の優先順位は コマンドラインオプション > ~/.subversionのファイル > /etc/subversionのファイル
  • プロキシ設定は、[global] か グループ([groups]で指定)セクションの中に、以下を書く
    • http-proxy-host : ホスト名
    • http-proxy-port : ポート番号
    • http-proxy-username : プロキシ認証のユーザ名
    • http-proxy-password : プロキシ認証のパスワード
    • ssl-trust-default-ca : OpenSSL同梱のCAを信頼するかどうか

http-proxy-host の説明に、"HTTP-based Subversion requests must pass" とあるから、https(http+ssl)もこの設定でいけるのかな?明示はされてないが。

状況の確認

社内プロキシではsvnアクセスができるのか?
~/.subversion/servers の設定をしてから、実際に試してみる。

http アクセス → 失敗
> % svn ls http://svn.ruby-lang.org
> svn: PROPFIND request failed on '/'
> svn: PROPFIND of '/': 500 Server Error (http://svn.ruby-lang.org)

proxyサーバが、PROPFINDをちゃんと処理してくれないようだ。

https アクセス → 成功

https ならば、メソッドも暗号化されるのでプロキシがはじくことはできないはず。試してみるとうまくいった。

% svn ls https://sssvn.jp/svn/spikelet/
Makefile
...

ただ、httpssvnを公開しているオープンソースプロジェクトって、あまり無いよな…。

subversionのソースを見てみる

subversion-1.4.4 を参照した(単に手元にソースがあったから)。

設定ファイルの処理

subversion/include/svn_config.h にて、設定ファイル中の設定名 ("http-proxy-host" など) のマクロを定義している:

#define SVN_CONFIG_OPTION_HTTP_PROXY_HOST           "http-proxy-host"
#define SVN_CONFIG_OPTION_HTTP_PROXY_PORT           "http-proxy-port"
#define SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME       "http-proxy-username"
#define SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD       "http-proxy-password"

このマクロを使って、server_groupやexceptionに応じたproxyなどの設定を取得する関数がある。
subversion/libsvn_ra_dav/session.c:get_server_settings():

      svn_config_get(cfg, proxy_host, SVN_CONFIG_SECTION_GLOBAL,
                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
      svn_config_get(cfg, &port_str, SVN_CONFIG_SECTION_GLOBAL,
                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
      svn_config_get(cfg, proxy_username, SVN_CONFIG_SECTION_GLOBAL,
                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
      svn_config_get(cfg, proxy_password, SVN_CONFIG_SECTION_GLOBAL,
                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);

ちなみにconfig設定は以下の関数を経て、リポジトリや設定ファイルから読んで構造体に格納される。

  • main() : subversion/svn/main.c のエントリ関数
    • svn_config_get_config()
      • get_category_config()
        • read_all()
          • svn_config_read()
            • svn_config__parse_file() : ここで実際のパース処理
読み込んだ設定情報の使用箇所

設定値を取り出しているget_server_settings()は、DAVアクセス(http or httpスキーム使用)時に使われるRAモジュール用の関数から呼び出されている:

  • svn_ra_dav__open() : 構造体 dav_vtable の open メンバー
    • get_server_settings() : 読み込んである server setting からプロキシなどの情報を取得
    • ne_session_proxy() : neon(別ライブラリ)の関数。取得時のproxy 使用を宣言する。
    • ne_set_proxy_auth() : neonの関数。プロキシ認証情報を宣言する。
    • ne_set_progress() : neonの関数。ネットワーク処理の進捗を通知するコールバック関数の設定。

RA は "Repository Access" の略。この辺を参照→Chapter 8. Developer Information

また、RAのopen関数は、以下のように呼ばれる:

  • main() : subversion/svn/main.c のエントリ関数
    • svn_cl__checkout() : "svn checkout" に対応する関数。main.c の svn_cl__cmd_table[] で設定されている。
      • svn_client_checkout2()
        • svn_client__checkout_internal()
          • svn_client__ra_session_from_path()
            • svn_client__open_ra_session_internal() :
              • svn_ra_open2()
                • vtable->open() : これが、DAVアクセス時の svn_ra_dav__open() に該当する
subversion内での環境変数取得

ちなみに、subversion内でのgetenv()は数ヶ所あるが、以下の用途でしか使われていない:

  • SVN_EDITOR, VISUAL, EDITOR : コミットメッセージ編集用エディタの起動
  • LC_ALL, LC_CTYPE, LANG : 表示/使用言語の選択
  • (任意) : トンネルスキーマ('ssh')のコマンドの設定
  • SVN_ASP_DOT_NET_HACK : Windows(含むcygwin)環境で設定することで、管理情報ディレクトリ(.svn)の名前を _svn に変更する

すなわち、環境変数から設定を変更することはできない、ということ。

neonのソースを見てみる

ここからは、neonの処理になるので、そちらのソースを見る。

neonの関数呼出しでは、一緒に引数で渡した ne_session 型構造体のメンバーを設定する。

  • ne_session_proxy(): セッションの use_proxy, proxy.hostanme, proxy.portメンバ
  • ne_set_proxy_auth(): セッションのプライベートデータ(idは"http://webdav.org/neon/hooks/proxy-auth")

この設定情報を、以下の箇所で使う。

  • ne_begin_request() : DAVでのrequest(接続から受信完了まで)を処理する
    • send_request() : HTTP接続要求開始
      • open_connection() : use_proxyが設定されていたら、proxyサーバに接続する
      • do_connect() : 接続先として proxy サーバを指定

subversionの仕様のまとめ

コマンドラインオプション、環境変数では設定はできない。

設定ファイル ~/.subversion/servers
プロキシのホスト名 http-proxy-host
プロキシのポート番号 http-proxy-port
プロキシのユーザ名 http-proxy-username
プロキシのパスワード http-proxy-password