フック関数の一覧の続きだ。
フックポイントには多くの種類があって、どういったタイミングで呼ばれるのか、私にはよく分からないものも多い。
ハンドラフック関数は、ハンドラ処理のフック関数だ。フックポイントには多くの種類があって、どういったタイミングで呼ばれるのか、私にはよく分からないものも多い。
ハンドラは、ドキュメントには「ファイルが呼ばれたときに実行される動作の Apache における内部表現」とある。
参考: http://httpd.apache.org/docs/2.4/ja/handler.html
default_handler
ふつうApacheはHTMLファイルをリクエストされれば、ファイルシステム上のそのHTMLファイルを読み込んでレスポンスとして返す。その処理を行うのが、default_handler ハンドラだ。
(1)フック関数の登録
フック関数 default_handler を登録する処理は次のようになっている
(httpd-2.4.9/server/core.c) 4885 ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
APR_HOOK_REALLY_LASTは、実行順序の最後を意味する。
(apr-util-1.5.3/include/apr_hooks.h より)
マクロ | 値 | 備考 |
APR_HOOK_REALLY_FIRST | -10 | どれよりも先に実行したい |
APR_HOOK_FIRST | 0 | 先頭グループ |
APR_HOOK_MIDDLE | 10 | 中間グループ |
APR_HOOK_LAST | 20 | 最終グループ |
APR_HOOK_REALLY_LAST | 30 | どれよりも後に実行したい |
別のハンドラがハンドラフックポイントに登録されている場合、そのハンドラを先に実行してから、default_handlerは実行される。
ハンドラフック関数は、RUN_FIRSTタイプなので、フック関数の戻り値がDECLINE以外の場合に処理を終了する。
つまり、OKや、エラーステータスが返されると処理は終了する。
終了するということは、登録された次のフック関数は処理されないということだ。
要するに、default_handlerは他のハンドラで処理されなかったリクエストを処理するハンドラ、ということになる。
(2)ハンドラフック関数の処理
実行される処理は次の通り。(httpd-2.4.9/server/core.c) 4248 static int default_handler(request_rec *r) 4249 { 4250 conn_rec *c = r->connection; 4251 apr_bucket_brigade *bb; 4252 apr_bucket *e; : 4277 if ((errstatus = ap_discard_request_body(r)) != OK) {KeepAliveな接続の場合は、入力フィルタからbucket brigadeを吸い上げ、 Content-Length分のボディ部分を読み捨てるなどの処理を実行している
4278 return errstatus; 4279 } : 4281 if (r->method_number == M_GET || r->method_number == M_POST) { : 4330 if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY 4331 #if APR_HAS_SENDFILE 4332 | AP_SENDFILE_ENABLED(d->enable_sendfile) 4333 #endif 4334 , 0, r->pool)) != APR_SUCCESS) {r->filenameがリクエストされたファイルを指している オープンできない場合には、403 Forbiddenを返す
4335 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00132) 4336 "file permissions deny server access: %s", r->filename); 4337 return HTTP_FORBIDDEN; 4338 } 4339 4340 ap_update_mtime(r, r->finfo.mtime);リソースの最終更新日時の情報(r->mtime)を更新している
4341 ap_set_last_modified(r);Last-Modifiedヘッダをレスポンス情報にセットしている。 値は、ap_update_mtime()で更新された値
4342 ap_set_etag(r);ETagヘッダをレスポンス情報にセットしている。
4343 ap_set_accept_ranges(r);Accept-Rangesヘッダをレスポンス情報にセットしている。 MaxRangesディレクティブの指定が"none"の場合は、"none"。それ以外は、"bytes"
4344 ap_set_content_length(r, r->finfo.size);Content-Lengthヘッダをレスポンス情報にセットしている。 値は、r->finfo.size。
4345 if (bld_content_md5) { 4346 apr_table_setn(r->headers_out, "Content-MD5", 4347 ap_md5digest(r->pool, fd));ContentDigestディレクティブに指定に応じて、 Content-MD5ヘッダをレスポンス情報にセットしている
4348 } 4349 4350 bb = apr_brigade_create(r->pool, c->bucket_alloc);ここでbucket brigade bbを作成している
4351 4352 if ((errstatus = ap_meets_conditions(r)) != OK) { 4353 apr_file_close(fd); 4354 r->status = errstatus; 4355 } 4356 else { 4357 e = apr_brigade_insert_file(bb, fd, 0, r->finfo.size, r->pool);ここで、ターゲットのファイルのファイルbucket を作成し bucket brigade bbに挿入している
4358 4359 #if APR_HAS_MMAP 4360 if (d->enable_mmap == ENABLE_MMAP_OFF) { 4361 (void)apr_bucket_file_enable_mmap(e, 0); 4362 } 4363 #endif 4364 } 4365 4366 e = apr_bucket_eos_create(c->bucket_alloc); 4367 APR_BRIGADE_INSERT_TAIL(bb, e);EOSメタデータbucketを作成し、 bucket brigade bb に追加した。 ここまでで、bb には ファイルbucketとEOSバケットが格納されている
4368 4369 status = ap_pass_brigade(r->output_filters, bb);ここで、bucket brigade bb を出力フィルタに引き渡す。
4370 if (status == APR_SUCCESS 4371 || r->status != HTTP_OK 4372 || c->aborted) { 4373 return OK; 4374 } 4375 else { 4376 /* no way to know what type of error occurred */ 4377 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00133) 4378 "default_handler: ap_pass_brigade returned %i", 4379 status); 4380 return HTTP_INTERNAL_SERVER_ERROR; 4381 } : 4406 }
ひとまず、もう一つくらい、handlerの例を書く。