2014年8月5日火曜日

リクエスト処理の流れ: ap_process_request_internal

(4) ap_process_request_internal

多数のフック関数が実行されている、この関数の中を覗いてみる。
handlerフック関数の実行処理 に書いたap_process_async_request()で実行されている関数だ。

ちなみに2.4.9と2.4.10の間では、server/request.cに相違点はないようだった。
従って、ap_process_request_internal関数にも違いはない。

 (httpd-2.4.9/server/request.c)
    126 AP_DECLARE(int) ap_process_request_internal(request_rec *r)
    127 {
    128     int file_req = (r->main && r->filename);

request_recのmain変数は、リクエストのサブリクエストから見た親リクエストを指す。
mainに値があるということは処理中のrequest_recはサブリクエストということだ。
サブリクエストというのは、リクエスト処理中に副次的に発生した処理すべきパスに対してリクエスト処理と一定の例外を除いて同様の操作を行う仕掛けだ。
サブリクエストが直接レスポンスを返すことはないが、リソースのファイルシステム上のパスの判定や、あるいは、アクセスチェックなどは行われる必要があったりする。
そうした処理のために用いられる。
(見たところ、ap_sub_req_method_uri()や、ap_sub_req_lookup_dirent()、ap_sub_req_lookup_file()といった 関数から処理が行われている)

リソースのファイルシステム上のパスは、request_recのfilenameに収められる。
URLパスから生成されるサブリクエストの場合はfilenameはnulと考えられる。

    129     int access_status;
    130     core_dir_config *d;
    131
    132     /* Ignore embedded %2F's in path for proxy requests */

コメントによれば、proxyへのリクエストのパスに含まれている "%2F"(エンコードされたスラッシュ)は 無視するとある。
proxyへのリクエストでなければ、無視しないという意味なんだろう。

    133     if (!r->proxyreq && r->parsed_uri.path) {

request_recのproxyreq変数は、このリクエストがproxyサーバへのリクエストの場合に種別が記録される。
proxyの設定が行われていて、proxyモジュールが受け取ったリクエストを処理対象と判断した場合に値が入る。
このif文はその否定なので、proxyへのリクエストではないリクエストが処理対象となる。

かつ、parsed_uri.path にも値が入っている場合だ。

    134         d = ap_get_core_module_config(r->per_dir_config);

これはcoreモジュールの設定情報のアドレスを取得するマクロだ。
r->per_dir_configにモジュールの設定情報が入っている。
この中のcoreモジュールの設定情報の 場所を返してくれる。

    135         if (d->allow_encoded_slashes) {

これは、AllowEncodedSlashes ディレクティブの設定情報だ。
こちらのif文は Onか、NoDecodeの場合だ。

    136             access_status = ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes);

この場合、%2Fがパスに含まれていてもエラーとはしない。
Onの場合はデコードする。
NoDecodeの場合はそのまま残す。

    137         }
    138         else {

こちらのelseは Offの場合だ。

    139             access_status = ap_unescape_url(r->parsed_uri.path);

その場合、エンコードされているURLパスをデコードし、不正なエンコードがされていたり 禁止文字(通常は"/")がエンコードされていた場合にエラーとしている。
禁止文字がスラッシュ(%2F)だ。
禁止文字があったら 404(not found)を返している。

On/Offいずれであっても、エンコード自体が誤っていればデコードできないので、エラーとなる。
その場合は 400(bad request)が返ってくる。

    140         }
    141         if (access_status) {

ここは、AllowEncodedSlashes Offで%2Fが見つかるか、エンコードそのものが 誤りの場合。

    142             if (access_status == HTTP_NOT_FOUND) {
    143                 if (! d->allow_encoded_slashes) {
    144                     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026)
    145                                   "found %%2f (encoded '/') in URI "
    146                                   "(decoded='%s'), returning 404",
    147                                   r->parsed_uri.path);
    148                 }
    149             }
    150             return access_status;
    151         }
    152     }
    153
    154     ap_getparents(r->uri);     /* OK --- shrinking transformations... */

ap_getparent()は、urlから ... の相対パス指定を除去する。
. の場合は単に除去し、
.. の場合は前のパスセグメントごと除去する("xx/.."のまとまりで除去する)。

    155
    156     /* All file subrequests are a huge pain... they cannot bubble through the
    157      * next several steps.  Only file subrequests are allowed an empty uri,
    158      * otherwise let translate_name kill the request.
    159      */
    160     if (!file_req) {

ここはサブリクエストではないか、サブリクエストでもfilename(リソースのローカルパス)が未詳のリクエストが処理対象となる。

    161         if ((access_status = ap_location_walk(r))) {

ここでは、<Location><LocationMatch>節でこのリクエストの合致する条件をマージする処理が行われる。
マージの結果は request_rec.per_dir_configに格納される(マージされる)。


    162             return access_status;
    163         }
    164         if ((access_status = ap_if_walk(r))) {

ここでは、<If><IfElse><Else>節でこのリクエストの合致する条件をマージする処理が行われる。
マージの結果は、request_rec.per_dir_configに格納される(マージされる)。
<If>関連のセクションは2.2系には存在しなかった。


    165             return access_status;
    166         }
    167
    168         d = ap_get_core_module_config(r->per_dir_config);
    169         if (d->log) {
    170             r->log = d->log;
    171         }

マージされたディレクトリのログレベルの情報をrequest_recのlog変数(struct ap_logconfig *)にコピーする。

 
    172
    173         if ((access_status = ap_run_translate_name(r))) {

translate_nameフック関数を実行する。

 
    174             return decl_die(access_status, "translate", r);
    175         }
    176     }
    177
    178     /* Reset to the server default config prior to running map_to_storage
    179      */
    180     r->per_dir_config = r->server->lookup_defaults;

request_rec.per_dir_configをリセットする。

 
    181
    182     if ((access_status = ap_run_map_to_storage(r))) {

map_to_storageフック関数を実行する。

 
    183         /* This request wasn't in storage (e.g. TRACE) */
    184         return access_status;
    185     }
    186
    187     /* Rerun the location walk, which overrides any map_to_storage config.
    188      */
    189     if ((access_status = ap_location_walk(r))) {

再度、<Location><LocationMatch>節のマージ処理。
2度めはキャッシュが効くと思われる。


    190         return access_status;
    191     }
    192     if ((access_status = ap_if_walk(r))) {

再度、<If><IfElse><Else>節のマージ処理。
こちらも2度めはキャッシュが効くと思われる。


    193         return access_status;
    194     }
    195
    196     d = ap_get_core_module_config(r->per_dir_config);
    197     if (d->log) {
    198         r->log = d->log;
    199     }

同じく、ログレベルの情報をコピー


    200
    201     if ((access_status = ap_run_post_perdir_config(r))) {

post_perdir_configフック関数の実行 このフック関数は2.2系では存在していない。


    202         return access_status;
    203     }
    204
    205     /* Only on the main request! */
    206     if (r->main == NULL) {

サブリクエストでない場合の処理


    207         if ((access_status = ap_run_header_parser(r))) {

header_parserフック関数の実行


    208             return access_status;
    209         }
    210     }
    211
    212     /* Skip authn/authz if the parent or prior request passed the authn/authz,
    213      * and that configuration didn't change (this requires optimized _walk()
    214      * functions in map_to_storage that use the same merge results given
    215      * identical input.)  If the config changes, we must re-auth.
    216      */

内部リダイレクトされたリクエストやサブリクエストの処理中で、per_dir_configが元のリクエストのper_dir_configと同じだった場合、認証認可の処理を省略する(元のリクエストで設定されている認証の情報(userとap_auth_type)を引き継ぐ)。
設定が変わっていれば、再度認証認可処理を実行する必要がある。


    217     if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) {

こちらは内部リダイレクトの認証認可が省略される条件。


    218         r->user = r->prev->user;
    219         r->ap_auth_type = r->prev->ap_auth_type;
    220     }
    221     else if (r->main && (r->main->per_dir_config == r->per_dir_config)) {

こちらはサブリクエストの認証認可が省略される条件


    222         r->user = r->main->user;
    223         r->ap_auth_type = r->main->ap_auth_type;
    224     }
    225     else {

認証認可処理を行う。
mod_access_compatを使用している場合は、ap_satisfies()がSatisfyディレクティブの指定を返す。
そうでない場合は、SATISFY_NOSPECが返る。


    226         switch (ap_satisfies(r)) {
    227         case SATISFY_ALL:
    228         case SATISFY_NOSPEC:

SATISFY_NOSPECなので、ここが、2.4系での標準的な処理となる。


    229             if ((access_status = ap_run_access_checker(r)) != OK) {

access_checkerフック関数を実行する。
見たところ、AllowMethodsディレクティブのチェック処理が行われている。
その他、mod_access_compatモジュールによるOrder/Deny/Allow処理がここで行われている。


    230                 return decl_die(access_status,
    231                                 "check access (with Satisfy All)", r);
    232             }
    233
    234             access_status = ap_run_access_checker_ex(r);

access_cheker_exフック関数を実行する。
access_cheker_exフック関数は 2.2系には存在していない。
ap_hook_access_checker_ex()関数を呼び出しているのは、ap_hook_check_access_ex()だけで、 ap_hook_check_access_ex()を経由してフック関数を登録するようになっている。
見たところ、ここでは、Require ipなどのユーザに依存しない認可処理を行っている。


    235             if (access_status == OK) {
    236                 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
    237                               "request authorized without authentication by "
    238                               "access_checker_ex hook: %s", r->uri);
    239             }
    240             else if (access_status != DECLINED) {
    241                 return decl_die(access_status, "check access", r);
    242             }
    243             else {

ユーザ認証が必要な場合の処理が行われる。


    244                 if ((access_status = ap_run_check_user_id(r)) != OK) {

check_user_idフック関数を実行する。
このフック関数も直接ap_hook_check_user_id関数で登録している場合と、
ap_hook_check_authn()関数を経由して登録している場合とがある。
見たところ、ここではAuthTypeに応じたユーザ認証処理が行われているようだ。


    245                     return decl_die(access_status, "check user", r);
    246                 }
    247                 if (r->user == NULL) {
    248                     /* don't let buggy authn module crash us in authz */
    249                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00027)
    250                                   "No authentication done but request not "
    251                                   "allowed without authentication for %s. "
    252                                   "Authentication not configured?",
    253                                   r->uri);
    254                     access_status = HTTP_INTERNAL_SERVER_ERROR;
    255                     return decl_die(access_status, "check user", r);
    256                 }
    257                 if ((access_status = ap_run_auth_checker(r)) != OK) {

auth_checkerフック関数を実行する。
ap_hook_auth_checker()を直接利用している個所は見当たらない(mod_luaだけ)。 ap_hook_check_authz()経由で登録している。
見たところ、ここではRequireに応じた認可処理が行われている。


    258                     return decl_die(access_status, "check authorization", r);
    259                 }
    260             }
    261             break;
    262         case SATISFY_ANY:
    263             if ((access_status = ap_run_access_checker(r)) == OK) {
    264                 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
    265                               "request authorized without authentication by "
    266                               "access_checker hook and 'Satisfy any': %s",
    267                               r->uri);
    268                 break;
    269             }
    270
    271             access_status = ap_run_access_checker_ex(r);
    272             if (access_status == OK) {
    273                 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
    274                               "request authorized without authentication by "
    275                               "access_checker_ex hook: %s", r->uri);
    276             }
    277             else if (access_status != DECLINED) {
    278                 return decl_die(access_status, "check access", r);
    279             }
    280             else {
    281                 if ((access_status = ap_run_check_user_id(r)) != OK) {
    282                     return decl_die(access_status, "check user", r);
    283                 }
    284                 if (r->user == NULL) {
    285                     /* don't let buggy authn module crash us in authz */
    286                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00028)
    287                                   "No authentication done but request not "
    288                                   "allowed without authentication for %s. "
    289                                   "Authentication not configured?",
    290                                   r->uri);
    291                     access_status = HTTP_INTERNAL_SERVER_ERROR;
    292                     return decl_die(access_status, "check user", r);
    293                 }
    294                 if ((access_status = ap_run_auth_checker(r)) != OK) {
    295                     return decl_die(access_status, "check authorization", r);
    296                 }
    297             }
    298             break;
    299         }
    300     }
    301     /* XXX Must make certain the ap_run_type_checker short circuits mime
    302      * in mod-proxy for r->proxyreq && r->parsed_uri.scheme
    303      *                              && !strcmp(r->parsed_uri.scheme, "http")
    304      */
    305     if ((access_status = ap_run_type_checker(r)) != OK) {

type_chekerフック関数を実行する。


    306         return decl_die(access_status, "find types", r);
    307     }
    308
    309     if ((access_status = ap_run_fixups(r)) != OK) {

fixupsフック関数を実行する。


    310         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "fixups hook gave %d: %s",
    311                       access_status, r->uri);
    312         return access_status;
    313     }
    314
    315     return OK;
    316 }

これで、ap_process_request_internalは終わる。

0 件のコメント:

コメントを投稿