/*************************************************************************** * 説明: Apache JServ 1.4の提案 * * 著者: Henri Gomez * * バージョン: $Revision: 1.3 $ * ***************************************************************************/ このドキュメントは、ajp13として知られていた現在のApache JServプロトコ ルバージョン1.3の改良の提案です。ここでは、プロトコルのすべてではなく、 ajp13に追加する部分だけを説明します。 この提案は、tomcat-devリストからのコメントと、開発中に発見された誤りを 含んでいます。 AJP13に欠けている機能 --------------------- ajp13は、TomcatのようなServletエンジンとApacheのようなWebサーバを繋ぐ 次の点で良いプロトコルです。 * リクエストごとに再接続する時間をなくすために、永続的な接続を使用します。 * ストリームサイズを減らすために、多くのHTTPコマンドをエンコードします。 * WebサーバからServletエンジンに、(SSL認証のような)多くの情報を送信します。 しかし、ajp13には、次のようなサポートが欠けています。 * WebサーバとServletエンジンの間のセキュリティ。 (ログイン機能が使用されないので、)誰でもajp13ポートに接続できます。 たとえば、telnetを使って接続して、何もデータを送信しなければ、リモー トのスレッドを捉えておくことができます(接続にタイムアウトはありません)。 * ServletエンジンからWebサーバに渡されるコンテクスト情報。 Webサーバコネクタであるmod_jkの設定の一部は、あるURLを処理するWebサー バを指定するためのものです。 mod_jkのJkMount指示子は、WebサーバにどのURLをServletエンジンに転送し なければならないかを指定します。 Servletエンジンは、すでにどのURLを処理しなければならないかを知ってい るので、TC 3.3は利用可能なコンテクストのリストからmod_jk用の設定ファ イルを生成する機能を持っています。 * ServletエンジンからWebサーバへのコンテクストの状態の更新。 ISPやバーチャルホスト提供サービスのような、多くのTomcatを使用する大 規模サイトでは、管理をおこなうためにあるコンテクストを停止する必要が あるかもしれません。このような場合は、手前にあるWebサーバは、そのリ クエストを他のTomcatに送るために、そのコンテクストが現在ダウンしてい るのを知らなければいけません。 * リクエストを送信する前の接続状態の確認 実際には、mod_jkはリクエストをServletエンジンに送信してから、そのリ プライを待ちます。しかし、Socket APIのうまい利用法の一つは、すでにク ローズした接続に対して、何もエラーをおこさずにwrite()することができ ますが、すでにクローズした接続に対するread()はエラーコードを返すこと です。 AJP13に対するAJP14の追加 ------------------------ では、ここでは、AJP14になるだろう、その機能とAJP13への追加を説明します。 このドキュメントは一つの提案であり、多くの混沌とした要求の中から、最初 の時点で妥当と思われる水準でなければいけません。 Tomcatリストの討論は論点と追加機能を明らかにするのに役に立ったのは確か ですが、現在のリストは「最低限必要」なものです。 * 接続時の進化したログイン機能 * 秘密鍵をWebサーバとServletエンジンで共有する基本的な認証システム、 * 将来的にAJP14に機能を追加する場合に、現在の実装の動作を保証するため の、基本的なプロトコルネゴシエーション。 * 「未知のパケット」のうまい処理。 進化したログイン機能 -------------------- 1) WEBサーバはLOGIN INIT CMD + NEGOCIATION DATA + WEB SERVER INFOを送 信します。 2) TOMCATは、LOGIN SEED CMD + RANDOM DATAで返答します。 3) WEBサーバはRANDOM DATA+SECRET DATAのMD5を計算します。 4) WEBサーバは、LOGIN COMP CMD + MD5 (SECRET DATA + RANDOM DATA)を送信します。 5) TOMCATはLOGIN STATUS CMD + NEGOCIED DATA + SERVLET ENGINE INFOを返 答します。 DOS攻撃を防ぐために、ServletエンジンはLOGIN CMDを15/30秒待ってから、管 理者が調査するためにタイムアウト例外を報告します。 loginコマンドは、圧縮機能、暗号化、コンテクスト情報(起動時)、実行時の コンテクストの更新(起動/停止)、SSLの環境変数のレベル、サポートしている AJPプロトコル(AJP14/AJP15/AJP16...)のような基本的なプロトコルネゴシエー ション情報を含んでいます。 Webサーバ情報は、Webサーバ情報とコネクタ名(例, Apache 1.3.19 + mod_ssl 2.8.2 + mod_jk 3.3 + mod_perl 1.25)を含んでいます。 Servletエンジンは、ネゴシエーションマスクをそれ自身のマスク(それが可能 なものを示します)でマスクしてから、それをログインが認められた時に返信 します。 これは、Servletエンジン側より新しいajp14が動作しているWebサーバや、そ の逆の場合で、基本的なajp14実装を使用するのに役立ちます。 AJP13は、コンパクト、高速で、Webサーバが持つ多くのSSL情報をServletエン ジンに転送しないように設計されていました。 私たちは、クライアントのSSLデータ(認証)、サーバのSSLデータ、使用する暗 号、そしてさまざまなデータ(タイムアウトなど)のより多くの情報を提供する ために、ここで4つのネゴシエーションフラグを追加します。 - メッセージストリーム - +-------------------------+---------------------------+---------------------------+ | LOGIN INIT CMD (1 byte) | NEGOCIATION DATA (32bits) | WEB SERVER INFO (CString) | +-------------------------+---------------------------+---------------------------+ +-------------------------+---------------------------+ | LOGIN SEED CMD (1 byte) | MD5 of entropy (32 chars) | +-------------------------+---------------------------+ +-------------------------+---------------------------------------+ | LOGIN COMP CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | +-------------------------+---------------------------------------+ +--------------------+------------------------+-------------------------------+ | LOGOK CMD (1 byte) | NEGOCIED DATA (32bits) | SERVLET ENGINE INFO (CString) | +--------------------+------------------------+-------------------------------+ +---------------------+-----------------------+ | LOGNOK CMD (1 byte) | FAILURE CODE (32bits) | +---------------------+-----------------------+ 秘密鍵は、次のように実行することで設定することができます。 - デフォルトのJkSecretKey 例: JkSecretKey myverysecurekey - ワーカによる JkWorkerSecretKey myworker myworkerverysecurekey シャットダウン機能 ------------------ AJP14は、AJP13のシャットダウンコマンドのセキュリティを強化することがで きます。私たちは、すでに送信データにMD5を追加しています。ログアウトが、 Servletエンジンにシャットダウンしたことを伝えます。 +-----------------------+---------------------------------------+ | SHUTDOWN CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | +-----------------------+---------------------------------------+ +---------------------+ | SHUTOK CMD (1 byte) | +---------------------+ +----------------------+-----------------------+ | SHUTNOK CMD (1 byte) | FAILURE CODE (32bits) | +----------------------+-----------------------+ 環境変数機能の拡張 ------------------ 注意: mod_jk内でAJP14を動作させる時に、"JkEnvVar"が使用できます。 以下の"環境変数機能の拡張"の解説は、AJP13ではすでに利用することができ ますが、AJP14には実装されていないかもしれません。 解説: 多くのユーザが、Webサーバの環境変数の一部をServletエンジンに渡したいよ うです。 ネットワークトラフィックを減少するためには、Webサーバは外部変数を示す テーブルを何らかの形で圧縮して送信することになります。 私たちは、すでにAJP13に存在する機能である、属性リストを使用します。 AJP13では、私たちは次のような情報を取得できます。 AJP13_FORWARD_REQUEST := prefix_code 2 method (byte) protocol (string) req_uri (string) remote_addr (string) remote_host (string) server_name (string) server_port (integer) is_ssl (boolean) num_headers (integer) request_headers *(req_header_name req_header_value) ?context (byte string) ?servlet_path (byte string) ?remote_user (byte string) ?auth_type (byte string) ?query_string (byte string) ?jvm_route (byte string) ?ssl_cert (byte string) ?ssl_cipher (byte string) ?ssl_session (byte string) ?attributes *(attribute_name attribute_value) request_terminator (byte) 圧縮した「Webサーバ属性名」を使用すれば、ネットワークトラフィックを減 少することができます。 +----------------------------+-------------------------------------+-----------------------------------------+ | EXTENDED VARS CMD (1 byte) | WEB SERVER ATTRIBUTE NAME (CString) | SERVLET ENGINE ATTRIBUTE NAME (CString) |... +----------------------------+-------------------------------------+-----------------------------------------+ 例: JkExtVars S1 SSL_CLIENT_V_START javax.servlet.request.ssl_start_cert_date JkExtVars S2 SSL_CLIENT_V_END javax.servlet.request.ssl_end_cert_date JkExtVars S3 SSL_SESSION_ID javax.servlet.request.ssl_session_id +-------------------+----+-------------------------------------------+ | EXTENDED VARS CMD | S1 | javax.servlet.request.ssl_start_cert_date | +-------------------+----+-------------------------------------------+ +----+-----------------------------------------+ | S2 | javax.servlet.request.ssl_end_cert_date | +----+-----------------------------------------+ +----+-----------------------------------------+ | S3 | javax.servlet.request.ssl_end_cert_date | +----+-----------------------------------------+ AJP14の転送中は、S1, S2, S3を含む属性名と、2001/01/03, 2002/01/03, 0123AFE56の属性値を見ることができます。 この例は、拡張されたSSL変数を使用する方法だけでなく、特別な認証変数の ような任意の「個人的な」Webサーバの変数を再使用できることを示しています。 このコストは、AJPトラフィックを数バイト増やすだけです。 ServletエンジンからWebサーバに転送するコンテクスト情報 ------------------------------------------------------ LOGIN PHASE終了後に、Webサーバは(AJP14_CONTEXT_INFO_NEGが設定されてい る場合に)コンテクストのリストとServletエンジンが処理するURLを受け取り ます。これは多くのサイトで、インストールを簡略化し、tomcat-userリスト の設定に関する質問を減らし、Servlet API 2.3に備えます。 このモードは、新しいJkAutoMount指示子によって有効になります。 例: JkAutoMount myworker1 Servletエンジンは、/examples, /admin, /testのような多くのコンテクスト を持つことができます。与えられたワーカに対していくつかのコンテクストだ けを使用したいかもしれません。以前は、たとえばApache HTTPサーバでは、 Apacheのそれぞれの領域内にJkMountを手で設定することでおこなっ ていました。 新しいJkAutoMountは、この目的にも対応しています。私たちは、JkAutoMount がこの要求を満たすように3番目のパラメタを追加しました。 例: JkAutoMount myworker1 www.myvirtualserver.com この場合に、Servletエンジンは、これらの特定の(servlet.xml内で定義され た)バーチャルサーバにマッチするURL/URIだけを返します。この機能は、ISP と負荷分散設定で多くのTomcatを使用している大規模サイトで有用です。 - メッセージストリーム - +--------------------------+---------------------------------+ | CONTEXT QRY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | +--------------------------+---------------------------------+ +---------------------------+---------------------------------+-------------------------------+ | CONTEXT INFO CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | URL1 [\n] URL2 [\n] URL3 [\n] | +---------------------------+---------------------------------+-------------------------------+ *) CStringはC言語の文字列であり、最後がnullバイト(/0)で終了している文 字の配列です。空文字列はnullバイト(/0)だけです。 *) VirtualModeが使用されていない時は、VIRTUAL HOST NAMEは空文字列であ り、Servletエンジンは存在するすべてのコンテクストを送信します。 ServletエンジンからWebサーバのコンテクスト情報の更新 ---------------------------------------------------- コンテクストの更新は、コンテクストが有効化/無効化されるごとにServletエ ンジンから送信されるメッセージです。この更新は、JkUpdateMount指示子を 指定した時に使用されます。この指示子は、AJP14_CONTEXT_UPDATE_NEGフラグ を設定します。 例: JkUpdateMount myworker1 また、このモードでは、使用するバーチャルサーバを処理するために3番目の パラメタを指定dkeimasu. 例: JkUpdateMount myworker1 www.myvirtualserver.com +-----------------------------+---------------------------------+-------------------------+ | CONTEXT UPDATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | STATUS UP/DOWN (1 byte) | +-----------------------------+---------------------------------+-------------------------+ *) VirtualModeを使用しない時には、VIRTUAL HOST NAMEは空文字列です。 Servletエンジンへのコンテクストステータスの問い合わせ -------------------------------------- この問い合わせは、Webサーバが与えられたコンテクストがUPまたはDOWNかを 決定するために使用します。 +----------------------------+----------------------------------+----------------------------+ | CONTEXT STATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | +----------------------------+----------------------------------+----------------------------+ +----------------------------------+---------------------------------+----------------------------+------------------+ | CONTEXT STATE REPLY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | +----------------------------------+---------------------------------+----------------------------+------------------+ *) VirtualModeが使用されていない時は、VIRTUAL HOST NAMEは空文字列です。 未知のパケットの処理 -------------------- 良く設計されたプロトコルであっても、片側(WebサーバまたはServletエンジ ン)が、理解できないメッセージを受け取ることがあるかもしれません。この ような場合に、受信側は処理できなかったメッセージを付加して'UNKNOW PACKET CMD'を送信します。 +-----------------------------+---------------------------------+------------------------------+ | UNKNOWN PACKET CMD (1 byte) | UNHANDLED MESSAGE SIZE (16bits) | UNHANDLED MESSAGE (bytes...) | +-----------------------------+---------------------------------+------------------------------+ メッセージによっては、送信側はエラーを報告し、可能な場合には別のエンド ポイントにメッセージを転送しようとします。 * UNHANDLED MESSAGE SIZEの追加 (開発) リクエストを送信する前の接続の確認 ---------------------------------- Socket APIの良い点の一つは、半分クローズしたソケットに書き込むことがで きることである。Servletエンジンがソケットをクローズした時に、Webサーバ はそのソケットに次のread()をおこなった時にだけ、クローズを検出できます。 基本的に、AJP13プロトコルでは、WebサーバはHTTP HEADERとHTTP BODY(POST では8Kまで)をServletエンジンに送信して、それから返答を受信しようとしま す。そのコネクションがクローズされた場合は、Webサーバはそれを受信時に しか知ることはできません。 私たちはバッファリング手法を使用することができますが、8K以上のデータの アップロード操作にServletエンジンを使用した時には、何が起るかわかりま せん。 AJP13プロトコルのハックは、そのサービスの最後の後に読む数バイトを追加 することでした。 WebサーバとServletエンジン間のやりとりの例 AJP HTTP-HEADER (+ HTTP-POST) (WEB->SERVLET) AJP HTTP-REPLY (SERVLET->WEB) AJP END OF DISCUSSION (SERVLET->WEB) ---> AJP STATUS (SERVLET->WEB AJP14) AJP STATUSは、Servletエンジンはリクエスト/レスポンス#Nの最後に読み込ま れずに、次のセッションの最初に読み込まれます。 この時に、Webサーバは読み込むデータが存在するかどうかを判断するために、 OS依存の機能(またはより良いAPR機能)を使用することもできます。そして、 そのデータはコンテクストを更新することができます(?)。 これによって、Webサーバがリクエストを無効化されたコンテクストに送信す ることを避けることができます。この場合には、負荷分散が使用されていれば、 そのリクエストを処理する別のServletエンジンが検索されます。 この機能は、ISPと多数のTomcatを使用する大規模サイトで、それらのServlet エンジンをサービスを中断しないで更新するために役に立ちます。 +---------------------+----------------------+ | STATUS CMD (1 byte) | STATUS DATA (1 byte) | +---------------------+----------------------+ おわりに -------- AJP14プロトコルの目的は、AJP13の制約の一部を克服することです。これには、 より簡単な設定、大規模サイトやTomcatの集合に対するよりよりサポート、簡 単な認証システムとプロトコルの更新に対する配慮などがあります。 これはmod_jk (ネイティブ)とServletエンジン (Java) の安定したajp13の実 装を使用しているので、よく知られているajp13の適切な改良になります。 AJP14のコマンドとID ------------------- - コマンドのID - AJP14_LOGINIT_CMD 0x10 AJP14_LOGSEED_CMD 0x11 AJP14_LOGCOMP_CMD 0x12 AJP14_LOGOK_CMD 0x13 AJP14_LOGNOK_CMD 0x14 AJP14_CONTEXT_QRY_CMD 0x15 AJP14_CONTEXT_INFO_CMD 0x16 AJP14_CONTEXT_UPDATE_CMD 0x17 AJP14_STATUS_CMD 0x18 AJP14_SHUTDOWN_CMD 0x19 AJP14_SHUTOK_CMD 0x1A AJP14_SHUTNOK_CMD 0x1B AJP14_CONTEXT_STATE_CMD 0x1C AJP14_CONTEXT_STATE_REP_CMD 0x1D AJP14_UNKNOW_PACKET_CMD 0x1E - ネゴシエーションフラグ - AJP14_CONTEXT_INFO_NEG 0x80000000 /* web-server want context info after login */ AJP14_CONTEXT_UPDATE_NEG 0x40000000 /* web-server want context updates */ AJP14_GZIP_STREAM_NEG 0x20000000 /* web-server want compressed stream */ AJP14_DES56_STREAM_NEG 0x10000000 /* web-server want crypted DES56 stream with secret key */ AJP14_SSL_VSERVER_NEG 0x08000000 /* Extended info on server SSL vars */ AJP14_SSL_VCLIENT_NEG 0x04000000 /* Extended info on client SSL vars */ AJP14_SSL_VCRYPTO_NEG 0x02000000 /* Extended info on crypto SSL vars */ AJP14_SSL_VMISC_NEG 0x01000000 /* Extended info on misc SSL vars */ AJP14_PROTO_SUPPORT_AJPXX_NEG 0x00FF0000 /* mask of protocol supported */ AJP14_PROTO_SUPPORT_AJP14_NEG 0x00010000 /* communication could use AJP14 */ AJP14_PROTO_SUPPORT_AJP15_NEG 0x00020000 /* communication could use AJP15 */ AJP14_PROTO_SUPPORT_AJP16_NEG 0x00040000 /* communication could use AJP16 */ ... 他のすべてのフラグは将来の使用のために予約されているので、0に設定しな ければいけません。 - エラーID - AJP14_BAD_KEY_ERR 0xFFFFFFFF AJP14_ENGINE_DOWN_ERR 0xFFFFFFFE AJP14_RETRY_LATER_ERR 0xFFFFFFFD AJP14_SHUT_AUTHOR_FAILED_ERR 0xFFFFFFFC - ステータス - AJP14_CONTEXT_DOWN 0x01 AJP14_CONTEXT_UP 0x02 AJP14_CONTEXT_OK 0x03