LoginSignup
1
0

More than 5 years have passed since last update.

Apacheのmod_proxyのコードを読んでみる(3)

Last updated at Posted at 2018-05-08

はじめに

前回の記事:Apacheのmod_proxyのコードを読んでみる(2)

前回はmod_proxyの概要についての記事を書きました。

今回はmod_proxyの実装の詳細として、各handler関数(register_hooksで登録される各hook関数の第一引数)の理解内容を記事にします。

呼び出されるフェーズ順に説明を記載します。

これまでと同様に、我流で読み進めているので、理解内容に間違いなどありましたらご指摘ください。

リクエスト実行の前処理のhandler

child_init

ap_hook_child_initのhandlerです。
構造体メンバの初期化ぐらいしかしていません。

proxy_detect

ap_hook_post_read_requestのhandlerです。

URIを見てproxy対象かを判断します。

  • virtual hostへのアクセス
  • HTTPメソッドがCONNECTの場合

上記の場合にrequest_rec構造体に値を設定します。

            r->proxyreq = PROXYREQ_PROXY;
            r->uri = r->unparsed_uri;
            r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
            r->handler = "proxy-server";

handlerやfilenameの値は、handler呼び出し時に処理対象か判定するためにも使われます。

proxy_pre_config

ap_hook_pre_configのhandlerです。
ここでmod_proxy_balancerで使われるworkerのカウントをリセットしています。

proxy_post_config

ap_hook_post_configのhandlerです。
SSLなどの設定内容を変数に格納しています。

    proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
    proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
    proxy_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
    proxy_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
    ap_proxy_strmatch_path = apr_strmatch_precompile(pconf, "path=", 0);
    ap_proxy_strmatch_domain = apr_strmatch_precompile(pconf, "domain=", 0);

proxy_trans

ap_hook_translage_nameのhandlerです。
条件を満たした場合にfilenameに”proxy:”というprefixを付けたURLを設定します。

    if (r->proxyreq) {
        /* someone has already set up the proxy, it was possibly ourselves
         * in proxy_detect
         */
        return OK;
    }

コメントの通りですが、すでに別のhandlerなどでproxyreqにNONE以外が設定されていたら、proxy対象として検知できているため、処理正常終了(OK)します。

ここでreturnしている場合はおそらくforward proxyと判定されていると思います。

次の条件文はDECLINEDを返すので説明を省略し、その次の条件文ではreverse proxyの判定を行っています。

    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);

    /* short way - this location is reverse proxied? */
    if (dconf->alias) {
        int rv = ap_proxy_trans_match(r, dconf->alias, dconf);
        if (DONE != rv) {
            return rv;
        }
    }

    conf = (proxy_server_conf *) ap_get_module_config(r->server->module_config,
                                                      &proxy_module);

    /* long way - walk the list of aliases, find a match */
    if (conf->aliases->nelts) {
        ent = (struct proxy_alias *) conf->aliases->elts;
        for (i = 0; i < conf->aliases->nelts; i++) {
            int rv = ap_proxy_trans_match(r, &ent[i], dconf);
            if (DONE != rv) {
                return rv;
            }
        }
    }

ディレクトリごとの設定(dconf変数)やサーバごとの設定(conf変数)の値を基にap_proxy_trans_match関数を呼び出し、エラーリターンもしくはreverse proxyと判定された時、DONE以外が返ってきて、returnします。

proxy_map_location(あまり読めていないです)

ap_hook_map_to_storageのhandlerです。

私のコードリーディングの目的にはあまり関係ないと思い、あまりよく読めていないので説明を省略します。

proxy_fixup

ap_hook_fixupsのhandlerです。

リクエストの最終準備フェーズに該当し、リクエスト構造体の最終調整を行っています。

mod_proxyで処理すべきリクエストであった場合、mod_proxyの後段モジュール(mod_proxy_wstunnelなど)のcanonicalize用関数(proxy_hook_canon_handler)をフックし処理を委譲します。

    /* canonicalise each specific scheme */
    if ((access_status = proxy_run_canon_handler(r, url))) {
        return access_status;
    }

リクエスト実行のhandler

proxy_handler

ap_hook_handlerのhandlerです。

do-while文よりも前

次のような処理を行っていますが、詳細な説明は省略します。

  • 処理対象の判別
  • Proxyのリクエストの有無チェック
  • NoProxyのホストのチェック
  • エラーチェック

do-while文の処理内容

        /* Try to obtain the most suitable worker */
        access_status = ap_proxy_pre_request(&worker, &balancer, r, conf, &url);

do-while文の序盤でmod_proxyの後段モジュール(mod_proxy_balancerなど)のrequest前処理用関数(proxy_hook_pre_request)をフックし適切なworkerを取得しています。

balancerが登録してある場合には初期化など必要な処理をし、
NoProxyが指定されていない場合はproxyであると仮定して処理を進めます。

                    /* handle the scheme */
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142)
                                  "Trying to run scheme_handler against proxy");
                    access_status = proxy_run_scheme_handler(r, worker,
                                                             conf, url,
                                                             ents[i].hostname,
                                                             ents[i].port);

proxy_hook_scheme_handlerをフックしschemeに応じた処理を後段へ委譲します。

後段からDECLINED以外のリターンが返って来た場合は、cleanupなどで後処理をして終了です。

NoProxyの場合でもproxy_hook_scheme_handlerをフックしschemeに応じた処理を後段へ委譲するのは同様です。

        /* Try again if the worker is unusable and the service is
         * unavailable.
         */
    } while (!PROXY_WORKER_IS_USABLE(worker) &&
             max_attempts > attempts++);

whileループの条件文です。
workerがusableでない、かつ試行回数の設定値(max attempts)を超えたか
を判定しています。

statusがDECLINEDだった場合はHTTP_INTERNAL_SERVER_ERRORを設定してcleanupで後処理をして終了です。

cleanup

エラーの場合や正常終了で後処理をする場合の処理を実施するためのgoto分のラベルです。

リクエスト構造体のstatusの設定や後段で実装されているproxy_hook_post_requestやproxy_hook_request_statusをフックし、最終的なstatusをreturnします。

おわりに

不要なところを飛ばしながら読んだため、理解できていないところもあります。
また、理解内容に間違いがあるかもしれませんが、mod_proxyの主要な関数を一通り読んでみました。

備忘録も兼ねていますが、参考になる方がいれば幸いです。

本記事でmod_proxy本体の内容は終わりです。
時間があったら、mod_proxy_balanacerやmod_proxy_wstunnelの実装についても記事を書いてみようと思っています。

1
0
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
1
0