[an error occurred while processing this directive]
[APACHE DOCUMENTATION]

Apache HTTP Server Version 1.3

Apache API notes

これはApache APIと扱わなければならないデータ構成等についての注釈です。まだ完成には程遠いものですが、概要を得る助けにはなるでしょう。APIは、まだ経験を重ねるに従って変化するものであることを忘れないでください(mightがどんなものであるかはTODOファイルを参照してください)。しかしながら、変化にモジュールを対応させるのは簡単でしょう(より対応するモジュールがあります)。

少々ここで一般的なpedagogicalなスタイルに触れています。簡潔にするために、ここでは全ての構成通知は不完全です --- 実際には触れていないより多くのスロットがあります。これらはほとんどの部分についてサーバの中心部と他の部分に用意されており、使用する上で注意が必要なモジュールによって変更されるでしょう。しかしながらいくつかの場合には、まだ本当に手付かずのものがあります。最前線へようこそ。

最後になりますがここにあるのは概要であり、何が起こって何を指図するかということについての基本的な概念を提供するものです:

基本的なコンセプト

まずAPI基本的なコンセプトの概要と、コードにどのように書かれたかについて始めます。

Handlers, Modules, and Requests

Apacheは要求のハンドリングをNetscapeサーバのAPIが行なう、多いか、または少ない同じ方法の一連の段階に分類します(このAPIはNetSiteが行なうよりも2、3段階が多くなっていますが、スタッフのフックのように将来は使いやすくなるでしょう)。これは: この段階はそれぞれの連続するmodulesを見て、もしそれぞれがその段階のハンドラーを持っていれば調べ、もしそうなら利用しようとすることによってハンドルされます。ハンドラーは通常3つことのうち1つを行なうことができます: ほとんどの段階はハンドルする最初のモジュールによって終わります;しかしながらログ、`fixups'そしてアクセス以外の認証チェックの間、全てのハンドラーは動いています(エラーがなければ)。要求された物のMIMEタイプで鍵をかけられたテーブルの転送によって、モジュールが多様なハンドラーを明示するかもしれないという点で反応の段階はユニークです。モジュールは鍵*/*(すなわちワイルドカードのMIMEタイプ特定化)を与えることによって、なんらかの要求をハンドルすることができる反応段階のハンドラーを明示しているのかもしれません。しかしながら、もしサーバがすでにより多くの要求された物(なくなったか、減少したかのどちらか)のMIMEタイプについての特定の反応ハンドラーを捜そうとして失敗すれば、ワイルドカードハンドラーが利用されます。

ハンドラー自身は、上記のようにintegerを転送する一つの引数(a request_rec structure. vide infra)の関数です。

モジュールの概要

この点で、モジュールの構造を説明する必要があります。Our candidate will be one of the messier ones, the CGI module --- これはCGIスクリプトと ScriptAliasコンフィグファイルコマンドの両方をハンドルしています。実際、ほとんどのモジュールよりも非常に複雑になっていますが、しかしもし一つの例だけを取り上げれば、それはあらゆる場所でのそのフィンガーに関する一つかもしれません。

ハンドラーについて始めましょう。CGIスクリプトをハンドルする代わりに、モジュールはそれらの反応ハンドラーを明示します。ScriptAliasのせいで、それは名前の翻訳段階(ScriptAliased URIsの認識)、タイプチェック段階(なんらかのScriptAliased要求がCGIスクリプトとしてタイプされています)を持っています。

モジュールはいくつかの(仮想)サーバ情報、すなわち実際にはScriptAliasesを維持する必要があります;それ故、モジュール構造はこれらの構造を構成している関数と、その二つを組み合わせているべつの物に対するポインタを含んでいます(メインサーバと仮想サーバの両方が明示されたScriptAliasesを持っている場合)。

最後に、このモジュールはScriptAliasコマンド自身をハンドルするコードを含んでいます。この特定のモジュールは一つのコマンドだけを明示しますが、更にそのようなモジュールは、どんなコマンドを明示したコマンドテーブル、それらがどこで許可され、どのように利用されるかについての記述を含んでいます。

最終的ないくつかのこれらのコマンドの明示された引数タイプについての注釈: poolresource pool構造に対するポインタです;これらは割り当てられたメモリートラック、開かれたファイル等を維持して、特定の要求を修理するか、コンフィギュアする処理自身をハンドルするサーバによって使われます。そのやり方は、要求が終了(またはコンフィグレーションプールについて、サーバが再起動する時)する時、それらを全てつきとめる明白なコードを書き、それらを処分することなしでメモリーがfreedされ、ファイルが閉じるen masseがその方法です。また、cmd_parms構造は読まれるコンフィグファイルについての多様な情報と、コンフィグファイルコマンド(ScriptAliasのようなもの)を処理する関数を時々使う他のステータス情報を含んでいます。 モジュール自身に問題ありません:

/* Declarations of handlers. */

int translate_scriptalias (request_rec *);
int type_scriptalias (request_rec *);
int cgi_handler (request_rec *);

/* Subsidiary dispatch table for response-phase handlers, by MIME type */

handler_rec cgi_handlers[] = {
{ "application/x-httpd-cgi", cgi_handler },
{ NULL }
};

/* Declarations of routines to manipulate the module's configuration
 * info.  Note that these are returned, and passed in, as void *'s;
 * the server core keeps track of them, but it doesn't, and can't,
 * know their internal structure.
 */

void *make_cgi_server_config (pool *);
void *merge_cgi_server_config (pool *, void *, void *);

/* Declarations of routines to handle config-file commands */

extern char *script_alias(cmd_parms *, void *per_dir_config, char *fake,
                          char *real);

command_rec cgi_cmds[] = {
{ "ScriptAlias", script_alias, NULL, RSRC_CONF, TAKE2,
    "a fakename and a realname"},
{ NULL }
};

module cgi_module = {
   STANDARD_MODULE_STUFF,
   NULL,                     /* initializer */
   NULL,                     /* dir config creator */
   NULL,                     /* dir merger --- default is to override */
   make_cgi_server_config,   /* server config */
   merge_cgi_server_config,  /* merge server config */
   cgi_cmds,                 /* command table */
   cgi_handlers,             /* handlers */
   translate_scriptalias,    /* filename translation */
   NULL,                     /* check_user_id */
   NULL,                     /* check auth */
   NULL,                     /* check access */
   type_scriptalias,         /* type_checker */
   NULL,                     /* fixups */
   NULL,                     /* logger */
   NULL                      /* header parser */
};

どのようにハンドラーが働くか

ハンドラーに対する唯一の引数はrequest_rec構造です。この構造はクライアント代わってサーバに作られた特定の要求を記述しています。ほとんどの場合、それぞれのクライアントに対する接続は唯一request_rec構造だけを生じます。

request_recの概要

request_recはサーバが要求のハンドリングを終了した時に消去されるリソースプールへのポインタを含んでいます; サーバ毎と、接続毎の情報、そして最も重要な要求自体の情報を含んでいる構造に対して。

最も重要なそのような情報は、そのURI、ファイル名、コンテントタイプとコンテントエンコーディング(これらはそれぞれ要求をハンドルするタイプチェックハンドラーと翻訳によって最新の情報を与えられる)を含んで要求された物の属性を記述しているキャラクタストリングの小さなセットです。

他に一般的に使われるデータ項目は、クライアント自身の要求のMIMEヘッダと、レスポンス(意のままにモジュールを追加できる)と共に返送されるMIMEヘッダ、要求をサービスする間に生じるなんらかの二次処理についての環境変数を与えているテーブルです。これらのテーブルはtable_gettable_setルーチンを使うことによって扱われています。

Note that the Content-type header value cannot be set by module content-handlers using the table_*() routines. Rather, it is set by pointing the content_type field in the request_rec structure to an appropriate string. E.g.,
  r->content_type = "text/html";
 
最後にモジュールごとのコンフィグレーション構成に対して順番にポイントする二つのデータ構成に対するポインターがあります。特に、これらは要求を受け取っている間に構築されるプライベートデータについて、(一つの段階についてのそのようなモジュールハンドラーは、他の段階についてのハンドラーに対して`notes'をパスすることができます)モジュールが与えられたディレクトリ(.htaccessファイルや<Directory>セクションによって)で作動するためにコンフィギュアする方法を記述するために作るデータ構成に対するポインターを維持します。(仮想)サーバコンフィギュレーションのデータごとに含まれるrequest_recによってポイントされるserver_recデータ構成には別のそのようなコンフィギュレーションベクトルがあります。

ここにあるのは簡易記述で、最も頻繁に使われる領域に与えられています:

struct request_rec {

  pool *pool;
  conn_rec *connection;
  server_rec *server;

  /* どんな物が要求されているか */

  char *uri;
  char *filename;
  char *path_info;
  char *args;           /* QUERY_ARGS, if any */
  struct stat finfo;    /* Set by server core;
                         * st_mode set to zero if no such file */

  char *content_type;
  char *content_encoding;

  /* MIMEヘッダー環境は出たり入ったりしています。また、配列はサブプロ
   * セスにパスされる環境変数を含んでいるので、その環境に追加するため
   * にモジュールを書くことができます。headers_outとerr_headers_outと
   * の違いは、後者がエラーでさえプリントし、内部リダイレクトの横断を
   * 続けることです(それで、ErrorDocumentのヘッダーにプリントされたヘ
   * ッダーはそれらを持っています)。
   */

  table *headers_in;
  table *headers_out;
  table *err_headers_out;
  table *subprocess_env;

  /* 要求自身についての情報 ... */

  int header_only;     /* HEAD request, as opposed to GET */
  char *protocol;      /* Protocol, as given to us, or HTTP/0.9 */
  char *method;        /* GET, HEAD, POST, etc. */
  int method_number;   /* M_GET, M_POST, etc. */

  /* ロギングについての情報 */

  char *the_request;
  int bytes_sent;

  /* 返送されたデータが変わりやすいことを示すためにモジュールがセット
   * できるフラッグとクライアントは、それをキャッシュしないことを言う
   * べきである。
   */

  int no_cache;

  /* .htaccessファイルと共に変わるかもしれない多様な他のコンフィグ情
   * 報これらはそれぞれのモジュールにとって一つのvoid*ポインタが付い
   * たコンフィグベクトルです(モジュールの仕事にするためにポイントさ
   * れたもの)。
   */

  void *per_dir_config;   /* Options set in config files, etc. */
  void *request_config;   /* Notes on *this* request */

};

request_rec 構造はどこに由来するのか

ほとんどの request_rec 構造はクライアントからの HTTP リクエストを読み込んで、フィールドを満たすことによって構築されます。しかし、いくつか例外があります:

リクエストのハンドリング、終了、エラーコードの返信

上にあるように、特定のrequest_recをハンドルするために利用された時、それぞれのハンドラーは何が起こったのかを指し示すintをリターンしなければなりません。以下のいずれかが可能です。 もし返送されたエラーコードがREDIRECTであれば、モジュールはクライアントがどこに向けてリダイレクトすべきなのかを指し示す、要求のheaders_outの中にあるLocationを付けるべきであることに注意してください。

レスポンスハンドラーのための特別な配慮

ほとんどの段階についてのハンドラーは、request_rec構造(または、アクセスチェッカーの場合には単に正確なエラーコードをリターンすることによります)にある2、3の領域を単にセッティングすることによって仕事をします。しかしながら、反応ハンドラーは実際にクライアントに要求を返送しなければなりません。

それらはHTTP反応ヘッダを送信し、send_http_header機能を使うことによって始まらなければなりません(HTTP/0.9要求について、ヘッダの送信をスキップするために特別なことをしてはいけません; その機能は何もすべきではないそれ自身を見分けます)。もし要求がマークされたheader_onlyであるなら、それが行なうべき全てです; それらは更なるアウトプットを試みることなしに、その後にリターンすべきです。

そうでなければ、それらは適切にクライアントに反応する要求本体を生じるべきです。この初期は内部的に生じるrputcrprintf、いくつかのFILE *の内容をまっすぐにクライアントにコピーするためのsend_fdです。

この点で、特定のハンドラーを持たないGET要求をハンドルするハンドラーの以下のコード片を多少は理解すべきです; それはまたどのように条件付きのGETがハンドルされたかを示しており、もし特定の反応ハンドラーの中でそうすることが望ましいなら --- set_last_modifiedはクライアントによって供給されたIf-modified-sinceの値をチェックして適切なコードをリターンします(もしゼロでなければUSE_LOCAL_COPYです)。類似の理由がset_content_lengthに適用されることはありませんが、それは釣り合いのエラーコードをリターンします。

int default_handler (request_rec *r)
{
    int errstatus;
    FILE *f;

    if (r->method_number != M_GET) return DECLINED;
    if (r->finfo.st_mode == 0) return NOT_FOUND;

    if ((errstatus = set_content_length (r, r->finfo.st_size))
        || (errstatus = set_last_modified (r, r->finfo.st_mtime)))
        return errstatus;

    f = fopen (r->filename, "r");

    if (f == NULL) {
        log_reason("file permissions deny server access",
                   r->filename, r);
        return FORBIDDEN;
    }

    register_timeout ("send", r);
    send_http_header (r);

    if (!r->header_only) send_fd (f, r);
    pfclose (r->pool, f);
    return OK;
}
最後に、この全てが手に負えない試みであるなら、2、3の解決法があります。まず上に示したように、まだなんらかのアウトプットを生じていない反応ハンドラーは、サーバが自動的にエラー反応を生じた場合に単にエラーコードをリターンすることができます。二番目に、上記の内部リダイレクト機構がどのように利用されているのかというinternal_redirectを利用することによっていくつかの他のハンドラーをパントすることができます。内部的にリダイレクトした反応ハンドラーはいつもOKをリターンすべきです。

(反応ハンドラーではないハンドラーからinternal_redirect を利用することは、深刻な混乱を招くでしょう)

認証ハンドラーのための特別な配慮

ここで詳細が記述される内容:

ロギングハンドラーのための特別な配慮

要求が内部的にリダイレクトされる時、なにをログするのかという疑問があります。Apacheは r->prevr->nextポインタを通じてスレッドするrequest_rec構造のリストにリダイレクトの完全なチェーンをバンドルすることによってこれをハンドルします。そのような場合にハンドラーのロギングをパスするrequest_recは、クライアントからのイニシャル要求を独自に構築するものの一つです; bytes_sentフィールドはチェーンの最後の要求の中でのみ正確になることに注意して下さい(反応が実際に送信されたうちの一つ).

リソースの割り当てとプール

サーバプールサーバに書き込んで、デザインする問題の一つはリークを避けることであり、それは引き続いて起こるそれらの放出をすることなしにリソース(メモリ、オープンファイル等)を割り当てることです。リソースプール機構はサーバでそれが成された時に自動的に放出されるような方法で割り当てられたリソースを許可することによって、ハプニングからこれを避けやすくするようにデザインされます。

これが作動する方法は以下の通りです: 特定の要求を扱うための開かれたファイル等に割り当てられたメモリは、要求に割り当てられたresource poolに制限されます。プールは問題のリソースをトラックするデータ構造です。

要求が処理されると、プールは消去されます。その点、それに関連付けられた全てのメモリはreuseに開放され、全ての関連付けられたファイルは閉じられます。そしてプールと関連付けられたなんらかの消去機能が作動します。これが終了すると、プールに制限されていた全てのリソースが開放され、リークされたものはないことがわかります。

サーバは再起動して、メモリの割り当てと、サーバ毎のコンフィギュレーションのリソースが同じようにしてハンドルされます。サーバのコンフィギュレーションファイルを読み込んで、その中にコマンドをハンドルしている間に、割り当てられたリソースのトラックを維持するconfiguration poolがあります (例として、開かれた、外部へのサーバ毎のモジュールコンフィギュレーションとログファイル、その他のファイルに割り当てられたメモリ等)。サーバが再起動してコンフィギュレーションファイルを再び読み込むと、コンフィギュレーションプールは消去され、それらを最後に読み込むことにより始められるメモリとファイルの書き込みはreuseの役に立つようになります。

プール機構の使用は普通、義務的なものではありません。ただし、サーバが再起動する時にログファイルが閉じることを確認するために、本当にcleanupsを記録する必要のあるハンドラーのロギングのような場合や、(これはCGIスクリプトのような、なんらかの子プロセスが実行される前に閉じられる内在するファイルの書き込みをアレンジするpfopen機能を使うことによって最も簡単に行われます)タイムアウト機構を使っている場合を除きます(ここではまだ記述されていません)。 しかし、それを使うことには二つ利点があります: 決してリークしないプールに割り当てられたリソース (スクラッチストリングを割り当てて、それについて忘れてしまう時でさえも); また、メモリの割り当てにとってpallocは普通mallocよりも速いです。

ここではプールにどのくらいメモリが割り当てられているのかの記述から始め、それからリソースプール機構によって他のリソースがどのくらいトラックされるのかを論じます。

プールにあるメモリの割り当て

メモリはpallocと呼ばれる機能によってプールに割り当てられます。pallocはリソースプール構造へのポインターであり、割り当てるメモリと等しくなっています(in chars)。要求をハンドリングするハンドラーの内部で、リソースプール構造を得る最も一般的な方法はrequest_rec関連のpoolスロットを見ることです; それ故、モジュールコードの以下の慣用法が繰り替えされます:
int my_handler(request_rec *r)
{
    struct my_structure *foo;
    ...

    foo = (foo *)palloc (r->pool, sizeof(my_structure));
}
pfreeがないことに注意してください --- pallocされたメモリは、関連したリソースプールが消去されると開放されます。これはpallocmalloc()と同じようにアカウントしてはいけないことを意味しています; 典型的な場合に行われることは、サイズを統一してポインタをバンプし、レンジをチェックすることです。

(pallocの頻繁な使用はまた、過度に大きくなるサーバプロセスを引き起こす可能性があります。以下にあるこれの扱いには二つの方法があります; 要するに、mallocを使って全てのメモリがはっきりと開放されていることを確認しようとするか、あるいはメインプールのサブプールを割り当てて、サブプールにメモリを割り当て、定期的にそれを消去することができます。後者の方法はサブプール以下のセクションで説明されており、数千のファイルのあるディレクトリをリストに書き込む時、過度の記憶装置の割り当てを避けるためにディレクトリインデックスコードで使われます)。

初期化されたメモリの割り当て

初期化されたメモリを割り当てる機能は頻繁に使われるものです。pcalloc機能はpallocと同じインターフェースを持っていますが、それをリターンする前に割り当てているメモリを消去します。pstrdup機能はリソースプールと引数としてchar *を取り、ポインタがポイントするストリングのコピーのために、コピーに対するポインタをリターンするメモリを割り当てます。最後にpstrcatはリソースプールに対するポインタを取るvarargs-styleの機能で、少なくとも二つのchar *引数を取り、最後にNULLにならなければなりません。ユニットとして、それぞれのストリングのコピーに合致するのに十分なメモリを割り当てます; 例えば:
     pstrcat (r->pool, "foo", "/", "bar", NULL);
"foo/bar"に初期化された、メモリの8バイトに相当するポインタをリターンします。

Tracking open files, etc.

上に示したように、リソースプールはまたメモリ以外のリソースの他の分類をトラックするために使われます。最も一般的なのはオープンファイルです。これに典型的に使われるルーチンはリソースプールと引数として二つのストリングを取るpfopenです; ストリングはfopenに対する典型的な引数と同じで、例えば、
     ...
     FILE *f = pfopen (r->pool, r->filename, "r");

     if (f == NULL) { ... } else { ... }
システムが呼び出す低レベルのopenと平行するpopenfルーチンもあります。問題のリソースプールがはっきりすると、両方のこれらのルーチンは閉じられたファイルをアレンジします。

メモリの異なる場合、pfopenpopenfで割り当てられたファイルを閉じるpfclosepclosefという機能があります。(これは多くのシステムで、一つのプロセスが開くことのできるファイルの数が完全に限られているせいです)。pfopenpopenfで割り当てられたファイルを閉じる機能を使うことが重要なのは、別のやり方では同じFILE*が一度以上閉じられると不都合な反応を示すLinuxのようなシステムで、致命的なエラーを引き起こすことがあるからです。

(close機能を使うことが強制でないのは、ファイルが結局不注意に閉じられるからですが、モジュールがたくさんのファイルを開いているか、開くことのできる場合には考慮すべきです)

リソースの他のソート --- クリーンアップ機能

ここにより多くのテキストがあります。ファイルスタッフが完成していることを前提にcleanup primitivesを記述しています; spawn_processについても同様です。

微細な制御 --- サブプールとサブリクエストのノートについての作成と扱い

めったにないことですが、palloc()と、関連したprimitivesの過度の使用は望ましくないリソースの割り当てをもたらすかもしれません。sub-poolを作成してメインプールよりもむしろサブプールの内部に割り当てて、それに関連するリソースを放出するサブプールを消去するか壊すことによってそのようなケースを扱うことができます。(これは本当にめったにないことです; 標準モジュールセットに発生する唯一のケースは、リスティングしているディレクトリに非常に大きなディレクトリがある場合だけです。 ここで書かれたprimitivesの無益な使用は、ほとんど得るものもなく相当コードをヘアアップすることになります).

サブプールを作成するためのprimitiveは、引数として他のプール(親プール)を取るmake_sub_poolです。メインプールが消去されると、サブプールは壊されます。サブプールはまた、clear_pooldestroy_poolの機能それぞれに呼ぶことによって、時々消去されたり壊されたりするかもしれません。(相違点はclear_poolがプールに関連したリソースを開放することですが、 destroy_poolもまたプール自身の割り当てをなくします。前者の場合にはプールに新しいリソースを割り当てて、それを再び消去すること等ができます; 後者の場合では単になくなってしまいます)

最終的な注意点 --- サブ要求はメインの要求にとってのリソースプールであるサブプールを自身のリソースプールとして持っています。割り当てていた(sub_req_lookup_...機能を使って)サブ要求に関連したリソースを改善する正確な方法は、リソースプールを開放するdestroy_sub_requestです。この機能を呼び出す前に、ほとんど変わらないでどこかにある、サブリクエストのリソースに割り当てられているかもしれないことが気になるものをコピーしていることを確認してください。(例えばそのrequest_rec構造にあるファイル名)

(また一方で、ほとんどの環境下ではこの機能を仕方なく呼んでいると感じるべきではありません; たった2K程度のメモリが典型的なサブ要求に割り当てられていて、メイン要求のプールが消去されると開放されるでしょう。それは、深刻にdestroy...機能を考慮すべき単一のメイン要求にたくさんのサブ要求を割り当てている時だけです)

コンフィギュレーション、コマンド等

このサーバの設計目的に一つは、NCSA 1.3 サーバと外部の互換性を維持することでした --- それは、同じコンフィギュレーションファイルを読み込んで、そこで正確に全ての命令を処理して、一般にはNCSAに置き換えることです。一方、他の設計目的は融通のきかないサーバコアではほとんど動かないモジュールにサーバの機能性と同じくらい動かすことでした。これらの目的を達成する唯一の方法は、中心サーバからモジュールにほとんどのコマンドのハンドリングを移動させることです。

しかし、ただモジュールコマンドテーブルを与えることは、サーバコアから完全に引き離すには不十分です。サーバは後にそれを作動させるために、コマンドを記憶しています。それはサーバ毎かディレクトリ毎かのどちらかになるモジュールに対する秘密のデータを維持することを意味しています。ほとんどはディレクトリ毎であり、特定のアクセスコントロールと認証情報に含まれていますが、AddTypeDefaultType命令等によって修正される拡張子からどのようにファイルタイプを決定するかについての情報です。一般には統制する原理は、ディレクトリであるべきことによってコンフィギュアが可能にされるものです; サーバ毎の情報は普通、要求が内在するファイルシステムにある特定の場所に制限される前に作動するようになるAliasesとRedirectsのような情報を基に標準セットのモジュールで使われます。

NCSAサーバをエミュレートするための他の要求は、一般的に.htaccessファイルと呼ばれるディレクトリ毎のコンフィギュレーションファイルをハンドルすることを可能にしますが、NCSAサーバの中でさえ、アクセスコントロールを全く行なわない命令を含んでいます。それ故、URI -> ファイル名翻訳の後、他の段階を実行する前に 提示されたかもしれないなんらかの.htaccessファイルを読み込むために、次の翻訳されたパス名の内在するファイルシステムのディレクトリ階層構造をサーバが降りていきます。その時読み込まれている情報は、サーバ自身からのコンフィグファイルからの適用できる情報でマージされなければなりません。(実際に<Directory />のようにほぼ正確にほとんどの目的について作動するaccess.confにある<Directory>セクションか、srm.confにあるデフォルトからかのどちらか).

最後に、.htaccessファイルの読み込みを必要とする要求を受け取った後、それらをハンドリングするために割り当てられた記憶装置を放棄する必要があります。トランザクション毎のリソースプールに対してそれらの構造を制限することにより、どこで類似する問題が起こっても同じ方法で解決されます。

ディレクトリ毎のコンフィギュレーション構造

拡張子からファイルタイプを決定するNCSAサーバの動きをエミュレートしてファイル分類ハンドラーを定義するmod_mime.cで、これの全てがどのように動くか気を付けてください。ここで見るであろうものは、AddTypeAddEncodingコマンドを実行するコードです。これらのコマンドは.htaccessファイルに現れるので、実際にMIMEタイプとエンコーディング情報についての二つに分かれたtablesを構成している、モジュールの秘密のディレクトリ毎のデータにハンドルされなければならず、以下のように示されます:
typedef struct {
    table *forced_types;      /* Additional AddTyped stuff */
    table *encoding_types;    /* Added with AddEncoding... */
} mime_dir_config;
サーバがMIMEモジュールコマンドの一つを含むコンフィギュレーションファイルや<Directory>セクションを読み込んでいる時、mime_dir_config構造を作成する必要があるのは、それらのコマンドが作動するためのものを持っているからです。二つの引数のあるモジュールが作成するディレクトリ毎のコンフィグスロットに見られる機能を利用することによってこれを行ないます: このコンフィギュレーション情報が適用する(あるいは srm.conf についてのNULL)ディレクトリ名と割り当てが起こるべきリソースプールに対するポインタ

(もし.htaccessファイルを読み込むと、リソースプールは要求についての要求毎のリソースプールになります; 一方、コンフィギュレーションデータに使われるのはリソースデータで、再起動をクリアします。どちらかの方法で、もし必要ならプールのクリーンアップを記録することによって、プールがクリアされる時消去することが構築された構造にとって重要です。)

MIMEモジュールにとって、ディレクトリ毎のコンフィグ作成はちょうど上記のようなpallocs構造を構築し、それを満たす2、3のテーブルを作成します。それはこのように見えます:

void *create_mime_dir_config (pool *p, char *dummy)
{
    mime_dir_config *new =
      (mime_dir_config *) palloc (p, sizeof(mime_dir_config));

    new->forced_types = make_table (p, 4);
    new->encoding_types = make_table (p, 4);

    return new;
}
今、.htaccessファイルの中でちょうど読み込んでいるとします。すでに階層構造の一つ上にあるディレクトリ毎のコンフィギュレーション構造を持っています。ちょうど読み込んでいる.htaccessファイルはAddTypeAddEncodingコマンドを持っておらず、MIMEモジュールのディレクトリ毎のコンフィグ構造はまだ有効で、それを使うことが出来るだけです。一方、なんらかの方法で二つの構造をマージする必要があります。

それを行なうためには、もし一つ存在するならサーバはモジュールのディレクトリ毎のコンフィグマージ機能を利用します。その機能は三つの項から成ります:マージされた二つの構造と結果を割り当てるリソースプール。MIMEモジュールにとって行われるべきことは、新しいディレクトリ毎のコンフィグ構造からのテーブルに、親からのテーブルをオーバーレイすることだけです:

void *merge_mime_dir_configs (pool *p, void *parent_dirv, void *subdirv)
{
    mime_dir_config *parent_dir = (mime_dir_config *)parent_dirv;
    mime_dir_config *subdir = (mime_dir_config *)subdirv;
    mime_dir_config *new =
      (mime_dir_config *)palloc (p, sizeof(mime_dir_config));

    new->forced_types = overlay_tables (p, subdir->forced_types,
                                        parent_dir->forced_types);
    new->encoding_types = overlay_tables (p, subdir->encoding_types,
                                          parent_dir->encoding_types);

    return new;
}
As a note --- もしディレクトリ毎のマージ機能が存在しなくても、サーバはサブディレクトリのコンフィギュレーション情報を使い、親のものを無視します。いくつかのモジュールについて、それがうまく作動して(例えばディレクトリ毎のコンフィギュレーション情報がXBITHACKの状態を単に構成している含んでいるモジュールについて)そしてそれらのモジュールについてちょうど一つを断言することはできず、モジュール自身のNULLの中に対応する構造スロットを残します。

コマンドハンドリング

今これらの構造を持っていて、どのようにそれらを満たすのかを考え出す必要があります。それは実際にAddTypeAddEncodingコマンドを処理する必要があります。コマンドを捜すために、サーバはモジュールのコマンドテーブルの中を見ます。そのテーブルはコマンドがどのくらいたくさんの引数を取るのか、フォーマットは何か、どこで許可されているのか等の情報を含んでいます。その情報は先に解析された引数についてのほとんどのコマンドハンドリング機能を利用するサーバを許可するのに十分です。更なる苦労なしで、このようなAddTypeコマンドハンドラーを見ましょう(AddEncodingコマンドは基本的に同じように見え、ここには示されていません):
char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
{
    if (*ext == '.') ++ext;
    table_set (m->forced_types, ext, ct);
    return NULL;
}
このコマンドハンドラーは非常にシンプルです。見ればわかるように、4つの引数を取り、2つは先に解析された引数で、3つ目は問題のモジュールについてのディレクトリ毎のコンフィギュレーション構造で、4つ目はcmd_parms構造に対するポインタとなっています。その構造はリソースプール(メモリが割り当てられることができることから、クリーンアップが制限されるべきです)とモジュールのサーバ毎のコンフィギュレーションデータがもし必要なら得られることからコンフィギュアされる(仮想)サーバを含んでいる頻繁に使われるいくつかのコマンドの引数の束を含んでいます。

この特定のコマンドハンドラーが非常に単純であることの他の点は、遭遇するエラーコンディションがないことです。もしあるなら、NULLの代わりにエラーメッセージを返送できます; もしメインのコンフィグファイルの中にそれがあると、これはquick exitに続くサーバのstderrのプリントアウトに対するエラーを引き起こします; .htaccessファイルについて、シンタックスエラーはサーバエラーログにログされ(それが何処から来るのかの表示に従って)、要求はサーバエラーレスポンスに跳ね返されます(HTTP error status, code 500)。

MIMEモジュールのコマンドテーブルは、このようなこれらのコマンドのエントリーを持っています:

command_rec mime_cmds[] = {
{ "AddType", add_type, NULL, OR_FILEINFO, TAKE2,
    "a mime type followed by a file extension" },
{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2,
    "an encoding (e.g., gzip), followed by a file extension" },
{ NULL }
};
これらのテーブルにあるエントリーは: 最後に、これを全てセットするとそれを使わなければなりません。これは最終的にモジュールのハンドラーの中で、特に大体このようなファイルタイピングハンドラーについて行われます; ディレクトリ毎のコンフィギュレーション構造は、get_module_config機能を使うことによってrequest_recのディレクトリ毎のコンフィギュレーションベクトルから引き出されます。
int find_ct(request_rec *r)
{
    int i;
    char *fn = pstrdup (r->pool, r->filename);
    mime_dir_config *conf = (mime_dir_config *)
             get_module_config(r->per_dir_config, &mime_module);
    char *type;

    if (S_ISDIR(r->finfo.st_mode)) {
        r->content_type = DIR_MAGIC_TYPE;
        return OK;
    }

    if((i=rind(fn,'.')) < 0) return DECLINED;
    ++i;

    if ((type = table_get (conf->encoding_types, &fn[i])))
    {
        r->content_encoding = type;

        /* go back to previous extension to try to use it as a type */

        fn[i-1] = '\0';
        if((i=rind(fn,'.')) < 0) return OK;
        ++i;
    }

    if ((type = table_get (conf->forced_types, &fn[i])))
    {
        r->content_type = type;
    }

    return OK;
}

追記 --- ディレクトリ毎のコンフィギュレーション、バーチャルサーバ、その他

サーバ毎のモジュールコンフィギュレーションにある基本的な考えは、基本的にディレクトリ毎のコンフィギュレーションのものと同じです; クリエーション機能とマージ機能があり、後者は仮想サーバが部分的に基のサーバコンフィギュレーションを無効にしている場所を利用されて、複合の構造が計算されなければなりません(ディレクトリ毎のコンフィギュレーションについて、もしマージのない機能が特定されて、モジュールがいくつかの仮想サーバの中でコンフィギュアされると、デフォルトは単に無視されている基のコンフィギュレーションです)。

ただ実質的な違いは、コマンドがサーバ毎のプライベートなモジュールデータをコンフィギュアするために必要とする時、それを入手するためにcmd_parmsデータへ行く必要があることです。シンタックスエラーの返送がどのようにして可能になるのかを示しているアライアスモジュールからの例がここにあります (コマンドハンドラーに対するディレクトリ毎のコンフィギュレーション引数がダミーとして申告されるのは、モジュールが実際にはディレクトリ毎のコンフィグデータを持っていないからです):

char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)
{
    server_rec *s = cmd->server;
    alias_server_conf *conf = (alias_server_conf *)
            get_module_config(s->module_config,&alias_module);
    alias_entry *new = push_array (conf->redirects);

    if (!is_url (url)) return "Redirect to non-URL";

    new->fake = f; new->real = url;
    return NULL;
}

Apache HTTP Server Version 1.3

検索文字
このJAPACHE!ニュースグループへ ( japache.API ) | JAPACHE!ニュースについて | JAPACHE!ホームページへ

Index Home The English original manual is here.


このページの情報に関わる、ご質問、お問い合わせは、 japache@infoscience.co.jpまで。

JAPACHE ホームページ