「あなくつ」のおもちゃばこ

Blog

Apacheモジュールで404エラーの出し方2種と違い

会社が休みに入ると仕事ができていいですね(え

Apacheモジュールで処理を行った結果、404(Not Found)のHTTPステータスコードを返したい場合があります。その場合、2種類の方法があります。

  • ap_hook_handler で登録したフック関数の戻り値で404を返す
  • ap_hook_handler で登録したフック関数の引数 request_rec 構造体の status の値を変更する(戻り値は0=OKを返す)

さて、2つの違いは何でしょう。答えは、レスポンスボディに何が出力されるか、ということろに違いがあります。

Apacheのフックの処理の流れから考えてみましょう。とりあえず、今回ポイントとなっているあたりを概略図にすると下記のようになります。

正常なとき
正常なとき

エラーの時(ファイルがない)
エラーの時

Apacheがいろいろなフックを呼びだし、誰かが処理を担当してくれたらそれを返す、誰も処理してくれなかったらエラー処理して返す、という感じでしょうか。

このとき、フック関数の戻り値で404を返すと下記のように処理が流れます。

エラーの時

エラー処理のほうに流れるわけですね。よって、エラー処理で生成されたレスポンスボディが返されます。Apacheの設定で ErrorDocument ディレクティブを設定している場合、指定されているコンテンツがレスポンスされます。

一方、request_rec 構造体の status の値を変更する場合、フック関数自体はOK(処理完了)を返すので、エラーレスポンスには処理が流れません。よって、 ap_rwrite などでレスポンスボディをセットしていれば、その内容がレスポンスされます。

エラーの時

この動きは、404エラーに限らず、500(Internal Server Error)などでも同様です。

これを理解できると、

  • 引数が不正で処理が続行できない場合など、モジュールでエラーを出力したい時、なんでエラーになったのかエラーメッセージを表示しつつ 400 のステータスコードを返す
  • 引数が不正だった場合でも、ファイルのダウンロードの処理(CSVの出力など)の場合は、 ErrorDocument ディレクティブで設定された 404 ページを表示させたい

など便利な使い方ができます。

Apacheモジュール開発している人なんてあまりいないと思いますが、ご参考までに!

タグ : apache,module,モジュール

2015/12/30 20:23:08 | Trackbacks (0) | Comments (0) | Technology

Apacheモジュールを404型ブートストラップで起動することを考える

オリジナルなApacheモジュールを呼びだそうとするとき、設定ファイルの記述方法としては2種類あります。

  1. Locationディレクティブで特定のリクエストURIに対してハンドラを指定する
  2. AddTypeディレクティブで独自のコンテンツタイプに対してハンドラを指定する

ところで、世の中のウェブアプリケーションフレームワークにはステータスコード404(Not Found)のときに起動するものがあります。これはつまり、サーバーのドキュメントルート配下にファイルが無かったときにアプリケーションを起動するというものです。(ほんとよく考えたなぁ)

そこで、この考え方をApacheモジュールでも利用することを考えます。まず、エラードキュメントはApacheの設定で指定できますので、適当なURIを指定します。そして、そのURIに対して、Locationディレクティブでハンドラを登録します。こうすると、エラードキュメントが呼び出されるときにモジュールを呼び出してくれるわけですね。httpd.confの記述例としては下記のようになるでしょう。

ErrorDocument 404 /bootstrap/

<Location "/bootstrap/">
    SetHandler handler_of_application
</Location>

これでばんばんざい、というわけにいきません。404で起動するということは、Apacheとしてはエラー状態なわけです。これがどういう問題を起こすかというと、

  • ステータスコードとして、404がクライアントに伝達されてしまう
  • ファイルサイズが小さいと、IEなどで「やさしい」エラーメッセージ(Apacheドキュメント風に(笑))が表示されてしまう
  • CookieやLocationなど、モジュールでheaders_outに設定したヘッダを出力してくれない

というようなことがあります。

これらの問題を解決するためには、Apacheの状態をエラー状態から通常の状態に戻してあげます。具体的には、request_rec構造体のstatus変数にHTTP_OK定数を設定してあげればいいようです。

これはまったくもって予想ですが、モジュールが最初呼び出されるとき、statusには404が入っていることから、Apacheがあちこちのモジュールを駆けまわる時に状態を伝達する変数となっているのでしょう。最終的にコアプロセスへもどってきたときに、statusにより出力処理を切り替えるのだと思います。

さぁこれでフレームワークっぽくモジュールができる!と思いきや、まだダメなんですね。フレームワークとして動作させるには、リクエストURIによって処理やレスポンスを切り替える、という動作が必要です。通常のリクエストによる呼び出しなら、request_rec構造体のuri変数やfilename変数などを使えばどこから呼び出されているかわかります。ところが、404駆動の場合、前出の変数は404に指定したの値(上記のhttpd.confの設定だと/bootstrap/がセットされてやってくる)になるのです。

そこで必要になってくるのが、request_rec構造体のprev変数です。Apacheには内部リダイレクトという機能(要は、ブラウザに表示されているURLは変わらないのだけれど、同じサーバー内の別の場所にあるコンテンツを読んでいる状態、たぶん。詳しくは、このあたりが参考になる。)があり、ErrorDocumentによって設定されているページはこの機能により呼び出されています。そして、内部リダイレクトを呼び出した元が、prev変数によって指し示されているのです。つまり、クライアントがリクエストしたURIを取得するためには、prev変数をたどって、呼び出し元のuri変数やfilename変数を取得してくればいいわけですね。

さて、これで404駆動でもモジュールが使えるようになりました。あとそこから先は、ディベロッパーの根性で開発してください!

タグ : 404,Apache,Bootstrap,Module,ブートストラップ,モジュール

2011/02/25 04:34:22 | Trackbacks (0) | Comments (0) | Technology

FreePascal での httpd の優先順位

FreePascalでApacheモジュールを開発するときに利用するユニットにhttpdがあります。このhttpdユニットはApacheのバージョンに合わせて、1.3用・2.0用・2.2用が用意されています。

普通にhttpdをusesするとファイル名の順番から1.3用が利用されてしまいます。いまどきは2.2以上なので、2.2用を使ってコンパイルしなければなりません。

今まではコンパイラオプションのユニット検索パスで、2.2用が入っている/units/$FPCTARGET/httpd22のディレクトリを指定することで回避していました。

が、先ほどfpc.cfgを見ていたらhttpdの振り分けが記述してありまして...。シンボルとして「FPCAPACHE_2_2」を設定してあげれば2.2用を読みに行ってくれるようです。Lazarusなら、プロジェクト>コンパイラオプション>その他タブ>カスタムオプションで「-dFPCAPACHE_2_2」を追記しておけばオッケーです。

まぁ自分でパスを追加しても問題はおこらないのですが、シンボル定義して勝手に切り替えてもらったほうがエレガントだとおもうので。ってゆーか、fpc.cfgとか読まないし、ドキュメント皆無みたいなもんだし、マイナーな言語は大変ですね(笑)

タグ : Apache,FreePascal,モジュール

2010/12/16 00:22:37 | Trackbacks (0) | Comments (0) | Technology

request_rec の content_type

前の記事でこれ書こうと思っていたんだよね。

Apacheのモジュール開発するとき、絶対というほど使う「request_rec」構造体。これの中にある「content_type」変数はHTTPリクエストヘッダの「Content-Type」じゃないので注意。これはApacheの設定(httpd.confなど)でAddTypeされている値です。たとえばPHPだと「AddType application/x-httpd-php」を設定するので、「content_type」変数には「application/x-httpd-php」が入ってきます。フォームの送信などではリクエストヘッダに「Content-Type: application/x-www-form-urlencoded」などを送ってくるはずですが、これの「Content-Type」を得る場合は、同じ構造体内の「headers_in」変数から拾ってくる必要があります。

逆に、「content_type」変数からフックするモジュールができます。独自の拡張子にAddTypeして、モジュール内で自分の「content_type」かどうか判別して処理してあげればいいわけです。ネットでApacheモジュールを開発する方法を見ると、SetHandlerでハンドラを登録する方法で解説されているものを多く見るけれど、こんな処理方法もあるということで。

タグ : Apache,モジュール

2010/08/14 07:40:10 | Trackbacks (0) | Comments (0) | Technology

  • Top
  • Software
  • Blog
  • Laboratory
  • Profile
Search
Feeds of Blog
Archives

Copyright © 2004-2024 Ana-Kutsu All Rights Reserved.