Oracle HTTP Server FAQ(パート2)

全般 PL/SQL DMS
OHSエラー 構成に関する質問 SOAP
CGIおよびSSI 認証 Perl
URLリライト ASPの使用 Java Cache
SSL JServ高可用性インフラ FastCGI

このFAQは、サイズを小さくするために3つのファイルに分割されています。
ページ: (1/3) (2/3) (3/3)


動的コンテンツ(CGIおよびSSI)

ScriptAlias以外のディレクトリでCGIを実行できるようにするには、どうすればよいですか?
Oracle HTTP Server Powered by Apacheは、ScriptAliasという名前のディレクトリにあるすべてのファイルを、通常のドキュメントとして処理対象ではなく実行対象として認識します。これはファイル名に関係なくあてはまるので、ScriptAliasディレクトリにあるスクリプトには「*.cgi」や「*.pl」などの拡張子を付ける必要はありません。つまり、Oracle HTTP Server Powered by Apacheにとっては、ScriptAliasディレクトリ内のファイルはすべてスクリプトです。

他の場所(たとえば、通常のドキュメントも含まれているディレクトリ)にあるスクリプトをOracle HTTP Server Powered by Apacheに実行させるには、スクリプトの認識方法を指定し、さらにスクリプトを実行してもよいことも指示する必要があります。これには、AddHandlerディレクティブなどを使用する必要があります。

サーバー構成ファイルの該当するセクションに、次のような行を追加します。

AddHandler cgi-script .cgi

これでサーバーは、指定した場所(および論理的にその下位の場所)にある「.cgi」で終わるすべてのファイルが、ドキュメントではなくスクリプト・ファイルであることを認識します。

このディレクトリの場所が、ExecCGIオプションを含むOptions宣言に指定されていることを確認します。

CGIが失敗して「Premature end of script headers」というメッセージが表示されますが、これはどういう意味ですか?
サーバーは完全なHTTPヘッダー・セット(1つ以上のヘッダーとそれに続くブランク行)を想定していましたが、受け取りませんでした。

この問題の原因としては、完全なヘッダー・セットまたはその一部でもサーバーに送信する前にスクリプトが停止していることが最も一般的です。これが原因かどうかを調べるには、サーバーの下のスクリプトとして実行するのではなく、インタラクティブ・セッションからスタンドアロンで実行してみてください。これでエラー・メッセージが返された場合、これがほぼ確実に「premature end of script headers」の原因です。CGIがコマンドラインから正しく実行された場合でも、Webサーバーで実行するときは環境とアクセス権が異なる可能性があることを覚えておいてください。CGIでアクセスできるリソースは、Oracle HTTP Server Powered by Apache構成に指定されているUserおよびGroupが使用できるリソースのみです。さらに、コマンドラインで指定された環境とは異なる環境になりますが、mod_envで提供されているディレクティブを使用して調整できます。

(必要なヘッダーをユーザーがまったく送信していないという原因は別として)この問題の第二の原因は、Perlの出力バッファとの対話によるものです。各出力文の後でPerlがバッファをフラッシュするようにするには、HTTPヘッダーを送信するprint文またはwrite文の近辺に次の文を挿入します。

{
 local ($oldbar) = $|;
 $cfh = select (STDOUT);
 $| = 1;
 #
 # print your HTTP headers here
 #
 $| = $oldbar;
 select ($cfh);
}

これが必要になるのは、一般に、出力をstdoutに送信する外部プログラムをスクリプトから呼び出すときか、ヘッダーを送信してから実際のコンテンツの送信が開始されるまでの間にかなりの時間がある場合のみです。パフォーマンスを最大にするには、前述のように、ヘッダーを送信する文の後で($| = 0または同等の指定を使用して)バッファのフラッシュをオフに戻す必要があります。

スクリプトがPerlで作成されていない場合は、使用する言語で同じことを行います(たとえば、C言語の場合は、ヘッダーの作成後にfflush()を呼び出します)。

「premature end of script headers」メッセージのもう1つの原因は、RLimitCPUおよびRLimitMEMディレクティブです。リソース制限のためにCGIスクリプトが停止されると、このメッセージが出力されます。

さらに、suEXEC、mod_perlまたは別のサード・パーティ製モジュールに構成上の問題がある場合も、CGIの実行が妨害され、「premature end of script headers」メッセージの原因になります。

フォームのPOST要求に対して常に「使用できないメソッドです」を受け取りますが、どうしてですか?
これは、ほとんどの場合、CGIスクリプトとしてPOSTしようとしているファイルを処理できるようにOracle HTTP Server Powered by Apacheが構成されていないことが原因です。通常のHTMLファイルにPOSTすることはできません。この操作は意味がありません。問題のファイルをCGIとして扱えるようにOracle HTTP Server Powered by Apacheを構成する方法の詳細は、ScriptAlias以外のディレクトリにあるCGIに関するFAQを参照してください。

Oracle HTTP Server Powered by Apacheによるバッファリングなしでスクリプトの出力を得るには、どうすればよいですか? なぜサーバー・プッシュが機能しないのでしょうか?
Oracle HTTP Server Powered by Apache 1.3から、CGIスクリプトは基本的にバッファリングされません。スクリプトが出力データをフラッシュするたびに、そのデータがクライアントに送信されます。スクリプト言語の中には、Perlなどのように出力用に独自のバッファリングを行うものがあります。これは、特殊な変数$|を1に設定して使用禁止にできます。もちろん、これにより送信パケット数が全体として増加しするため、エンド・ユーザーが遅く感じることがあります。

解析されたファイルがキャッシュされないのは、どうしてですか?
サーバーはSSIディレクティブのランタイム処理を実行しており、クライアントに送信されるコンテンツが変更されることがあるため、解析の開始時に結果の最終サイズがどうなるかや解析結果が常に同じになるかどうかをサーバーは知ることはできません。つまり、サーバーではContent-LengthまたはLast-Modifiedヘッダーを生成できないということです。キャッシュは、通常、キャッシュ内の項目のLast-Modifiedとサーバーにより配信されるこのヘッダーを比較することで機能します。サーバーは解析されたドキュメントに対してこのヘッダーを送信していないため、キャッシュではそのドキュメントが変更されているかどうかを認識できず、安全のためにもう1度そのドキュメントをフェッチします。

場合によっては、Expiresヘッダーを生成して、これを回避できます。(詳細は、mod_expiresのドキュメントを参照してください。) もう1つの回避方法はXbitHack Fullメカニズムの使用です。このメカニズムは、Oracle HTTP Server Powered by Apacheに対して、(XbitHackディレクティブの説明に詳しく述べられている特定の条件の場合に)解析対象ファイルの最終変更日時を基にしたLast-Modifiedヘッダーを送信するように指示します。これは、解析済みファイルに変更がなくSSIにより挿入されたコンテンツに変更がある場合は、クライアントに対して嘘をつくことになるので注意してください。含まれているコンテンツが頻繁に変更される場合は、古いコピーがキャッシュされることになります。

スクリプト出力を解析するには、どうすればよいですか?
CGIスクリプトの出力にSSIディレクティブを含めたいが、方法がわからないということですね? 簡単に答えると「それはできません」。これはセキュリティ上の障害になる可能性があり、さらに重要なことは、現時点でのサーバーAPIではこれをきれいな形で実装できないということです。最善の回避策は、SSIで行うことをスクリプト自身で実行することです。結局、スクリプトがコンテンツの残りをすべて生成するわけですから。

仮想ホストまたはユーザー・ホーム・ディレクトリ(あるいはその両方)に対してSSIが機能しません。
ほとんどの場合、構成ファイルの中で「Options Includes」やその他の設定値をDocumentRootに対して設定しており、他のディレクトリに設定していないことがこの原因です。Directoryセクションの中で設定してある場合、その設定はそのディレクトリに対してのみ適用されます。

環境変数REMOTE_USERが設定されていないのはどうしてですか?
この変数が設定され、SSIまたはCGIスクリプトで使用できるようになるのは、要求されたドキュメントがアクセス認証により保護されている場合のみです。

ヒント: CGIスクリプトを使用してHTML FORMのデータを受信するとき、FORMを含むドキュメントを保護するだけでは、CGIスクリプトでREMOTE_USERを使用できるようにはなりません。CGIスクリプトも保護する必要があります。または、CGIスクリプトのみを保護します(そうすると、フォームが記入された後でのみ認証が発生します)。

ユーザー・ディレクトリのそれぞれにcgi-binディレクトリが含まれるようにするには、どうすればよいですか?
CGIの実行は、cgi-binディレクトリのみに制限する必要はありません。ファイル・システム内の任意の部分でCGIスクリプトの実行を可能にすることができます。ユーザー・ディレクトリのそれぞれに対して、http://example.com/~user/cgi-bin/programとして要求されたものがすべてCGIスクリプトとして実行されるようなcgi-binディレクトリを指定する方法は多数あります。次に2つの方法を示します。

cgi-binディレクトリをpublic_htmlディレクトリの隣に指定します。

ScriptAliasMatch ^/~([^/]*)/cgi-bin/(.*) /home/$1/cgi-bin/$2

cgi-binディレクトリをpublic_htmlディレクトリの下位に指定します。

<Directory /home/*/public_html/cgi-bin>
    Options ExecCGI
    SetHandler cgi-script
</Directory>


認証とアクセス制限

ホスト名またはドメイン名によるアクセス制限が正しく機能しないのは、どうしてですか?
この問題の最も一般的な原因を2つ示します。

●DNS登録でのエラー、非一貫性または予期しないマッピング
これはよく起こることで、構成はHost.FooBar.Comへのアクセスを制限していますが、そのホストからはアクセスできません。通常この原因は、Host.FooBar.Comが別の名前のエイリアスであり、Oracle HTTP Server Powered by Apacheがアドレス/名前参照を実行するときに、Host.FooBar.Comではなくて本当の名前を取得しているということです。逆引参照をチェックしてみると、これを確認できます。最も簡単な回避策は、構成内で正しいホスト名を指定することです。

●Oracle HTTP Server Powered by Apacheの構成のチェックおよび確認が不十分
クライアントのホスト名またはドメイン名に基づいてアクセスのチェックおよび制限を行う場合は、指定された情報を二重にチェックできるようにOracle HTTP Server Powered by Apacheを構成する必要があります。これを行うには、ConfigurationファイルのEXTRA_CFLAGS定義に-DMAXIMUM_DNS句を追加します。次に例を示します。

EXTRA_CFLAGS=-DMAXIMUM_DNS

これにより、Oracle HTTP Server Powered by Apacheは、特定のホスト・アドレスが確かにその名前に割り当てられているということを厳密に検査します。ただし、名前解決要求がすべてネーム・サーバーに送信されることになるため、パフォーマンスが著しく低下する可能性があるので注意してください。

サイトがローカル・サイトの場合、またはユーザーがパスワードとユーザー名を指定した場合にのみ、特定ドキュメントへのアクセスを許可するには、Oracle HTTP Server Powered by Apacheをどのように設定すればよいですか?
アクセス制限の1つのみが満たされるように要求するには、Satisfyディレクティブ、特にSatisfy Anyディレクティブを使用します。たとえば、.htaccessまたはサーバー構成ファイルに次の構成を追加すると、domain.com内のホストからサイトにアクセスしているユーザー、または正しいユーザー名とパスワードを指定するユーザーのみにアクセスが制限されます。

Deny from all
Allow from .domain.com
AuthType Basic
AuthUserFile /usr/local/Oracle HTTP Server Powered by Apache/conf/htpasswd.users
AuthName "special directory"
Require valid-user
Satisfy any

これらのディレクティブの詳細は、ユーザー認証に関する質問およびmod_accessモジュールを参照してください。

Webページ認証に/etc/passwdファイルを使用できますか?
はい、使用できます。しかし、この方法はお薦めしません。理由は次のとおりです。

  • Webテクノロジでは、パスワードの再試行(認証の失敗)の頻度および間隔を制御するものは提供されていません。これは、Webを使用しているシステムのrootパスワードに対してディクショナリまたは同様の大量攻撃を使用して、回線およびサーバーの要求処理速度の限界まで、反復攻撃できることを意味します。今日、ほとんどのオペレーティング・システムが攻撃検出機能(同一アカウントに対するパスワード再試行はm秒以内にn回など)および回避機能(接続の切断、攻撃されているアカウントの使用禁止、そのソースからのすべてのログインの禁止など)を備えていますが、Webにはこのような機能が装備されていません。
  • 攻撃されているアカウントには(サーバーが大幅に変更されないかぎり)通知されません。正当な所有者がログインしたときに、「ログインに19483回失敗しました」というようなメッセージが表示されることもありません。
  • エラーがないかどうかサーバー・ログを徹底的に調べないかぎり、アカウントが不正に使用されたかどうかはわかりません。ただし、攻撃があったことまたは発生中であることは、ログを調べれば比較的簡単に検出できます。
  • Web認証パスワードは、通常、(少なくとも基本認証の場合は)プレーン・テキスト形式で回線上を転送され、中間のプロキシ・システムを通過します。(ジングル・ベルの替え歌調に言うと)「ネットを越えて/キャッシュしていくよ/サーフィンは楽し/ついでにパスワードをばらまきながら!」となります。
  • HTTPはステートレスであるため、認証に関する情報はサーバーに対して要求が行われるたびに必ず送信されます。基本的に、クライアントは初回の正常なアクセス後にその情報をキャッシュしておき、その後同じサーバーに対する要求では、求められなくてもその情報を送信します。
  • システム上のだれかが、クライアントのキャッシュ内のパスワードをクライアントに知られずに盗み出すページを作成するのは比較的簡単です。「パスワードのひったくり」とでも言うのでしょうか。

Oracle HTTP Server Powered by Apacheがファイルを表示する前にパスワードの入力を2度求めるのはどうしてですか?
サーバーにアクセスしているホスト名が、ServerNameディレクティブに指定されているホスト名と異なる場合、UseCanonicalNameディレクティブの設定によっては、Oracle HTTP Server Powered by Apacheは自己参照URLを作成するときにユーザーを新しいホスト名にリダイレクトすることがあります。これは、たとえば、末尾にスラッシュを指定しないでディレクトリを要求した場合などに発生します。

末尾に「/」を指定しないでディレクトリにアクセスすると、Oracle HTTP Server Powered by Apacheは、元のホスト名で認証を1度要求し、リダイレクトを実行し、次に新規ホスト名で認証を再要求します。セキュリティ上の理由から、ブラウザはホスト名が変更されたときにパスワードの入力を再要求する必要があります。この問題を回避する方法は、次のとおりです。

  • ディレクトリを要求する場合は、常に末尾にスラッシュを使用します。
  • URLで使用する名前と一致するようにServerNameを変更します。および/あるいは、
  • UseCanonicalName offを設定します。

JServ

JservにおけるServletクラスのロードのロギングをオンにするには、どうすればよいですか?
JServを自動モードで実行している場合は、jserv.propertiesファイルに次の行を追加します。
wrapper.bin.parameters=-verbose

Apacheサーバーを再起動します。Javaによりどのクラスがロードされたかを示す出力は、Apacheログ・ディレクトリ内のerror_logに入れられます。

手動モードで実行している場合は、JServを起動するときに、javaコマンドに-verboseを追加します。出力は、JServを起動したウィンドウに表示されます。または、出力をファイルにパイプする場合は、そのファイルに入れられます。

「Servlet Error: NoClassDefFoundError: oracle.reports.rwclient.RWClient」のようなエラーのかわりに、ロードまたは検索できなかった実際のクラスの名前が通知されます。

JServおよびJSPで要求ディスパッチャ・アーキテクチャを使用するには、どうすればよいですか?
Apache/JServ上のJSPは、RequestDispatcher機能のいくつかをシミュレートして、JSPまたはHTMLページへの転送およびインクルードを可能にしています。ただし、JSPからServletに転送するには、JSPラッパーを作成する必要があります。詳細は、OJSPのドキュメントおよびFAQを参照してください。

JServのロード・バランシングのインストールでDNSが使用されるのはどうしてですか?
これは、JServ構成の構文が柔軟であるための副作用です。このフィールドは実際のホスト値にもなるため、mod_jservは常に無条件でこの文字列にgethostbyname()呼出しを実行します。その後、mod_jservは、指定されたプロトコルがbalanceであることを認識します。このため、この名前のIPアドレスが含まれているかどうかは関知しません。gethostbyname()呼出しが正常に実行されるかどうかは関係ありませんが、常にこの呼出しを実行します。

プロトコルがbalanceの場合は、この参照を行わないようにコードを変更することもできますが、この参照は起動時にのみ実行されるため、お尋ねの方のように名前解決が非常に遅く、起動に時間がかかるという経験をしないかぎり、だれも気にするとは思えません。

JServでのタイムアウトの問題
JServではApacheの「Timeout」パラメータを使用して、Servlet応答を待機する時間を判断します。この値のデフォルトは300秒です。この値を増やすことはできますが、増やすとサーバー全体に適用されます。つまり、どこから送信された要求の場合でも、Apacheは要求の失敗を宣言するまでにこれだけの時間を待機します。このため、非常に低速のクライアント(または応答の読込みを拒絶する誤動作のクライアント)では、失敗を宣言するまでの時間が長くなります。

JServでのServletのマッピング
jserv.confにApJServMount / /myServletZoneという行を作成します。
次に、my_servlet_zone.propertiesにservlet.MyURL.code=MyServletという行を作成します。

JServには監視スクリプトがありますか?
正式な監視スクリプトはありませんが、次のKornシェル・スクリプトが役に立つことがあります。これは、jserv.logに表示される特定のエラー・タイプを検出するために作成されたものです。定期的に実行するには、このスクリプトをroot crontabに設定する必要があります。

#!/bin/ksh

restart_cmd=/usr/local/apache/bin/apachectl restart
error_msg=男ava.lang.ArrayIndexOutOfBoundsException
Date=`date +%D`
Time=`date +%T`

output=`tail -20 /usr/local/jserv/logs/jserv.log | grep $error_msg`
if [[ $output != "" ]]; then
  $restart_cmd                                   # restart web server
  echo "$Date $Time: Restarting server" >> /usr/local/jserv/logs/serverCheck.log
else
  echo "$Date $Time: Server check was fine" >> /usr/local/jserv/logs/serverCheck
.log
fi

Servletのロード・バランシングの方法は?
詳細は、How to : Scalability - Load-Balancing - Fault toleranceを参照してください。概要は次のとおりです。

  • 通常どおりJavaサーバーを設定します。Servletをzone1というゾーンに入れます。
  • 残りのステップでApache構成ファイルを編集します。
  • JServのモジュールをロードします。次のような行を追加します。
    LoadModule jserv_module libexec/mod_jserv.so AddModule mod_jserv.c
  • 使用するJavaサーバーのURLを定義します。
    ApJservHost JS1 ajpv12://js1.my.domain:8007 ApJservHost JS2 ajpv12://js2.my.domain:8007 ApJservHost JS3 ajpv12://js3.my.domain:8007
  • これらのURLのそれぞれをセットに追加します。
    ApJServBalance set1 JS1 ApJServBalance set1 JS2 ApJServBalance set1 JS3
  • 各クッキーの終わりに追加された文字列を、各Javaサーバーにルーティングするように設定します。
    ApJServRoute JS1 JS1 ApJServRoute JS2 JS2 ApJServRoute JS3 JS3
    (この例で、最初のJS1はクッキーに追加されるテキストで、2番目はJServホストの名前です。)
  • Servletの「サブディレクトリ」をバランス・セットの特定のゾーンにマウントします。
    ApJServMount /servlet balance://set1/zone1

 

Servletを起動時にロードすることはできますか?
はい。zone.propertiesファイルのservlet.initに適切なパラメータを指定してください。

異なる開発者に対する異なる作業領域の作成
Servletゾーンを使用して、ユーザーごとに異なるディレクトリと、Servletリポジトリおよびクラスパスのセットをマップできます。

www.urlstuff.com/bob/<bob-servlets>
www.urlstuff.com/alice/<alice-servlets>
など

異なる開発者が1つのjserv.propertiesファイルを共有しますが、このファイルは、通常、開発者ごとに異なる指定をする必要のないものが含まれているため、非常に便利です。Servletゾーンごとにそれぞれ独自の構成ファイルがあります。

別々の仮想ホストを設定することもできますが、この場合、cgiやServletなどを実行するための環境は各開発者ごとにさらに多様になります。仮想ホストの設定は容易で、著者の場合もマシンのユーザーは自分1人ですが、仮想ホストを使用して作業しています。異なる仮想ホストの場合も、jserv.propertiesファイルを共有する必要があります。

そこで次にくるのが、「他の開発者に影響を与えずに自分のゾーンを取り除くにはどうすればよいか」という質問です。ゾーンを複数使用している場合でも、psには実行中のJVMが1つ表示されるだけで、jserv-statusにはゾーンを再起動する方法が提供されていませんでした。

これはできません。いずれは他の開発者に影響してしまいます。

AJP Protocol Error : java.io.IOException : Stream closed prematurely。または、Netscapeでの「ドキュメントにデータが含まれていません」。
これは、アクションを要求されたServletからの応答を待機中にブラウザがタイムアウトしたときに発生します。ほとんどの場合、ServletがJVMにより時間内にロードされていません。PrintWriterオブジェクトがまだ結果を返していないか、画面に結果を返すための処理中で、PrintWriterが閉じる前にブラウザがタイムアウトしています。

解決策はいくつかあります。

  1. 最もわかりやすいのは、マシンの仕様をアップグレードすることです。特にRAMを追加インストールします。
  2. 起動時にJServからJVMにより多くのメモリーを割り当てるようにします。これには、jserv.propertiesを編集し、wrapper.bin.parameters=-Xms64m -Xmx64mと指定します。64は、JVMが使用できるメモリーを表します(単位はメガバイト)。JVM用のデフォルトは32MBです。
  3. JServの起動時に要求されたServletをロードします。これには、your_zone.propertiesファイルを編集し、servlets.startup=your_servlet_to_be_preloadedと指定します。JServのロード時にこのServletがロードされ、ブラウザ経由でこのServletに要求が送られるまでにロードされるはずです。
  4. Servletのinit()メソッド内とPrintWriterオブジェクトが開かれる行および閉じられる行の近辺に、ログ・ポイントを指定します。これらのログ・ポイントはjserv.logに入れられ、jserv.logの日付スタンプにより、いつ何が起こったかがわかります。
  5. システムと設定で異なるJVMを試してみます。場合によっては、JVMがシステムを妨害していることもあります。

ajp12 errors - Emergency, Fatal
このエラーを受け取るのは、JVMが正しく起動できなかった結果です。


 

Copyright © 2001 Oracle Corporation All Rights Reserved.