<-
Apache > HTTP サーバ > ドキュメンテーション > バージョン 2.2 > モジュール

Please note

This document refers to the 2.2 version of Apache httpd, which is no longer maintained. The active release is documented here. If you have not already upgraded, please follow this link for more information.

You may follow this link to go to the current version of this document.

Apache モジュール mod_proxy_ajp

翻訳済み言語: en | ja

この日本語訳はすでに古くなっている 可能性があります。 最近更新された内容を見るには英語版をご覧下さい。
説明: mod_proxy で AJP をサポートするためのモジュール
ステータス: Extension
モジュール識別子: proxy_ajp_module
ソースファイル: mod_proxy_ajp.c

概要

本モジュールには mod_proxy 必要ですApache JServ Protocol version 1.3 (以降 AJP13) をサポートします。

AJP13 プロトコルを扱えるようにするには mod_proxy mod_proxy_ajp をサーバに組み込む必要があります。

警告

安全なサーバにするまでプロクシ機能は有効にしないでください。 オープンプロキシサーバはあなた自身のネットワークにとっても、 インターネット全体にとっても危険です。

トピック

ディレクティブ

このモジュールにディレクティブはありません。

参照

top

プロトコルの概要

AJP13 プロトコルはパケット指向です。 可読なプレーンテキスト形式ではなくバイナリ形式になったのは、 おそらくパフォーマンス上の理由によります。 ウェブサーバはサーブレットコンテナと TCP コネクションで通信します。 ソケット生成は重い処理なので、負荷を減らすために、サーブレットコンテナとの TCP 接続を維持し、複数のリクエスト・レスポンス処理サイクルに対して一つの コネクションを使いまわすようになっています。

あるリクエストにコネクションが割り当てられると、その処理サイクルが 完了するまで他のものに使われることはありません。 つまりコネクション上では、リクエストの同時処理は行われません。 このため、コネクション両端での実行するコードを簡潔にできる一方で、 同時に開くコネクションは多くなっています。

サーブレットコンテナへのコネクションを開いた後は、コネクションの状態は 次のどれかになります:

  • Idle
    コネクション上で処理されているリクエストはありません。
  • Assigned
    コネクションはリクエストを処理中です。

コネクションが特定のリクエストにアサインされると、基本的な情報 (例えば HTTP ヘッダ等) が圧縮された形 (例えば通常の文字列は整数にエンコードされます) で転送されます。詳細は下記の「リクエストパケットの構造」を参照してください。 リクエストにボディが存在 (content-length > 0) すれば、 基本的な情報の直後に別パケットで転送されます。

この時点でおそらく、サーブレットコンテナは処理を開始できるようになります。 ですので、次のメッセージをウェブサーバに戻して知らせられるようになります。

  • SEND_HEADERS
    ブラウザにヘッダを送信します。
  • SEND_BODY_CHUNK
    ブラウザにボディデータのチャンクを送ります。
  • GET_BODY_CHUNK
    リクエストのデータを全て受け取り終わっていないときに、 残っているデータを受け取ります。パケットにある定まった最大長があり、任意の 大きさのデータがリクエストのボディとして含まれうる場合 (例えばファイルのアップロードの場合) に必要となります。 (注: HTTP のチャンク転送とは関連ありません。)
  • END_RESPONSE
    リクエスト処理サイクルを終了します。

個々のメッセージはそれぞれ異なるデータパケット形式になっています。 後述の「レスポンスパケットの構造」を参照してください。

top

基本パケット構造

このプロトコルには XDR から受け継いだ部分が少しありますが、多くの点で 異なります (例えば 4 バイトアライメントでないことなど) 。

バイトオーダー: 個々のバイトのエンディアンがどうなっているかは、 私は詳しくないのですが、リトルエンディアンになっていると思います。 XDR 仕様でそうなっているのと、素晴らしいことに sys/socket ライブラリが (C で) そういう風にできているのでそうなのだと思いました。 ソケット呼び出しの内部についてより詳しい方がいらっしゃいましたら、 ご教授ください。

プロトコルには 4 つのデータタイプがあります: byte, boolean, integer, string です。

Byte
バイト一つです。
Boolean
バイト一つで、1 = true, 0 = false です。 (C のように) 非零を真として扱ってしまうと、ある場合は動くかもしれませんし、 動かないかもしれません。
Integer
0 から 2^16 (32768) の範囲の数字。高次の 2 バイトが 先に格納されます。
String
可変長の文字列 (2^16 が長さの上限) 。長さ情報のパケット 2 バイトの後に 文字列 (終端文字 '0円' を含む) が続く形式でエンコードされます。 エンコードされている長さ情報は最後の '0円' をカウントしない ことに注意してください――これは strlen と同様です。 これらの終端文字をスキップするために、あまり意味の無いインクリメント文 をたくさん書かないといけないのは、 Java の側から見ると少し紛らわしく感じられるかもしれません。 こうなった理由はおそらく、Servlet コンテナから返される文字列を読み出す時に、 効率よく C のコードを書けるようにする――サーブレットから返される 文字列は 0円 文字で終端されているので、C のコードではわざわざコピーをせずに、 一つのバッファへのリファレンスを取り回すように書くことができる―― ためだと思われます。 '0円' 文字がない場合は、C では文字列の規則に合うようにコピーしなければ いけなくなってしまいます。

パケットサイズ

多くのコードでそうなっているのですが、パケットサイズの最大サイズは 8 * 1024 (8K) です。パケットの実際の長さはヘッダに エンコードされて入っています。

パケットヘッダ

サーバからコンテナに送出されるパケットは 0x1234 で始まります。 コンテナからサーバに送られるパケットは AB (ASCII コード A と ASCII コード B) で始まります。この二バイトの後に、ペイロード長が (上記の形式で) 続きます。このため、ペイロード長の最大値は 2^16 にできるように思えますが、 実際にはコードでは最大値は 8K に設定されています。

パケット形式 (Server->Container)
Byte 0 1 2 3 4...(n+3)
Contents 0x12 0x34 データ長 (n) Data
パケット形式 (Container->Server)
Byte 0 1 2 3 4...(n+3)
Contents A B データ長 (n) Data

ほとんどのパケットで、ペイロードの最初のバイトがメッセージの型をエンコード しています。例外はサーバからコンテナに送られるリクエストボディパケットです ――これらは標準的なパケット形式 (0x1234 とパケット長) ですが、その後に続くプレフィックスコードがありません。

ウェブサーバは次のメッセージをサーブレットコンテナに送出できます。

コード パケットの型 意味
2 Forward Request リクエスト処理サイクルを後続のデータとともに開始する。
7 Shutdown ウェブサーバがコンテナに、コンテナを終了するように伝える。
8 Ping ウェブサーバがコンテナに制御を受け持つように伝える (セキュアログインフェーズ) 。
10 CPing ウェブサーバがコンテナに CPong で即座に応答するように伝える。
none Data サイズ (2 バイト) とそれに続くボディデータ。

基本的なセキュリティを確保するため、ホストされているマシンと同一の マシンからのリクエストに対してのみ、コンテナは実際に Shutdown を実行します。

最初の Data パケットは、Forward Request の直後にウェブサーバから送られます。

サーブレットコンテナはウェブサーバに、次のタイプのメッセージを送ることが できます :

コード パケットの型 意味
3 Send Body Chunk サーブレットコンテナからウェブサーバに (そしておそらくそのままブラウザに)、ボディのチャンクを送る。
4 Send Headers サーブレットコンテナからウェブサーバに (そしておそらくそのままブラウザに) レスポンスヘッダを送る。
5 End Response レスポンス (つまりリクエスト処理サイクル) 終了の目印を送る。
6 Get Body Chunk まだ全て転送されていない場合、残っているリクエストのデータを受け取る。
9 CPong 応答 CPing リクエストに応答する。

上記メッセージは、それぞれ内部構造が異なっています。詳細は下記をご覧ください。

top

リクエストパケット構造

サーバからコンテナへ送られるメッセージが Forward Request 型の場合 :

AJP13_FORWARD_REQUEST :=
 prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
 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)
 attributes *(attribut_name attribute_value)
 request_terminator (byte) OxFF

request_headers は次のような構造になっています :

req_header_name := 
 sc_req_header_name | (string) [see below for how this is parsed]
sc_req_header_name := 0xA0xx (integer)
req_header_value := (string)

属性 はオプションで、次のような構造をしています :

attribute_name := sc_a_name | (sc_a_req_attribute string)
attribute_value := (string)

もっとも重要なヘッダは content-length だということに 注意してください。コンテナは次のパケットを探すかどうかを、 それを見て決めるからです。

Forward Request 要素の詳細な説明

Request prefix

リクエストについては全て、この値は 2 になります。他の Prefix コードの詳細は 上記をご覧ください。

Method

HTTP メソッドは 1 バイトにエンコードされます :

Command Name Code
OPTIONS 1
GET 2
HEAD 3
POST 4
PUT 5
DELETE 6
TRACE 7
PROPFIND 8
PROPPATCH 9
MKCOL 10
COPY 11
MOVE 12
LOCK 13
UNLOCK 14
ACL 15
REPORT 16
VERSION-CONTROL 17
CHECKIN 18
CHECKOUT 19
UNCHECKOUT 20
SEARCH 21
MKWORKSPACE 22
UPDATE 23
LABEL 24
MERGE 25
BASELINE_CONTROL 26
MKACTIVITY 27

今後の ajp13 バージョンでは、この一覧にない、今後追加されるメソッドを 送るかもしれません。

protocol, req_uri, remote_addr, remote_host, server_name, server_port, is_ssl

これらはまさに文字通りのものです。どれも必要で、リクエストの毎回につき 送られます。

Headers

request_headers の構造は次のようなものです : まずヘッダの数 num_headers がエンコードされます。 次にヘッダ名 req_header_name / 値 req_header_value の組が続きます。効率のため、一般的なヘッダは整数でエンコードして転送します。 ヘッダ名が基本ヘッダの一覧に無い場合は、通常通り (文字列として、長さ プレフィックス付きで) 転送されます。一般的なヘッダ sc_req_header_name の一覧とそのコードは次の通りです (どれも大文字小文字を区別します) :

名前 コードの値 コード名
accept 0xA001 SC_REQ_ACCEPT
accept-charset 0xA002 SC_REQ_ACCEPT_CHARSET
accept-encoding 0xA003 SC_REQ_ACCEPT_ENCODING
accept-language 0xA004 SC_REQ_ACCEPT_LANGUAGE
authorization 0xA005 SC_REQ_AUTHORIZATION
connection 0xA006 SC_REQ_CONNECTION
content-type 0xA007 SC_REQ_CONTENT_TYPE
content-length 0xA008 SC_REQ_CONTENT_LENGTH
cookie 0xA009 SC_REQ_COOKIE
cookie2 0xA00A SC_REQ_COOKIE2
host 0xA00B SC_REQ_HOST
pragma 0xA00C SC_REQ_PRAGMA
referer 0xA00D SC_REQ_REFERER
user-agent 0xA00E SC_REQ_USER_AGENT

これを読み込む Java のコードでは、最初の 2 バイト整数を取り込み、 目印になるバイト '0xA0' であれば、ヘッダ名の配列の インデックスを使います。先頭バイトが 0xA0 でない場合は、 先頭 2 バイトは文字列長を表す整数であると解釈し、読み込みはじめます。

ヘッダ名の長さは 0x9999 (==0xA000 -1) 以上にならないという 仮定の下に動いていて、少しあいまいですが合理的な挙動になっています。

注:

content-length ヘッダはとても重要です。 存在していて非ゼロであれば、リクエストにはボディがある (例えば POST リクエスト) と推測し、そのボディを取り込むために 直後のパケットを入力ストリームから読み込みはじめます。

属性

? プレフィックスで始まる属性 (例 ?context) は。省略可能です。それぞれ属性の型を示す 1 バイトのコードと、 値の文字列が続きます。 これらは順不同で送ることができます (C のコードは常に下の一覧順に 送るようですが) 。 オプションの属性のリストの最後には、特別な終了コードが送られます。 コードの一覧は :

Information Code Value Note
?context 0x01 未実装
?servlet_path 0x02 未実装
?remote_user 0x03
?auth_type 0x04
?query_string 0x05
?jvm_route 0x06
?ssl_cert 0x07
?ssl_cipher 0x08
?ssl_session 0x09
?req_attribute 0x0A Name (the name of the attribute follows)
?ssl_key_size 0x0B
are_done 0xFF request_terminator

contextservlet_path は現在の C の コードではセットされていません。また、ほとんどの Java のコードでも、 このフィールドで何が送られても無視されます (これらのコードの後に文字列が 送られると壊れるものもあります)。 これがバグなのか、単に未実装なのか、歴史的経緯で残っているコードなのか 分かりませんが、コネクションの両側ともで見当たりません。

remote_userauth_type はおそらく HTTP レベルの認証を参照していて、リモートユーザのユーザ名と認証に使用した タイプ (例 Basic, Digest) についてやり取りします。

query_string, ssl_cert, ssl_cipher, ssl_session は HTTP と HTTPS の対応する部分を参照します。

jvm_route はスティッキーセッションのサポート―― ロードバランスしている複数のサーバ中の特定の Tomcat インスタンスと、 ユーザのセッションとを紐付ける機能――に使われます。

この基本属性一覧に無いものについては、req_attribute コード 0x0A 経由で属性を何個でも送ることができます。 属性の名前と値の文字列の組を、それぞれこのコードの直後に送ります。 環境変数はこの方法で伝えられます。

最後に属性が全て送信された後に、属性の終端を示す 0xFF が送出されます。この信号は属性の一覧の終わりを示すと同時に、リクエスト パケットの終端をも示しています。

top

レスポンスパケット構造

コンテナがサーバに送り返すことのできるメッセージ:

AJP13_SEND_BODY_CHUNK :=
 prefix_code 3
 chunk_length (integer)
 chunk *(byte)
AJP13_SEND_HEADERS :=
 prefix_code 4
 http_status_code (integer)
 http_status_msg (string)
 num_headers (integer)
 response_headers *(res_header_name header_value)
res_header_name :=
 sc_res_header_name | (string) [see below for how this is parsed]
sc_res_header_name := 0xA0 (byte)
header_value := (string)
AJP13_END_RESPONSE :=
 prefix_code 5
 reuse (boolean)
AJP13_GET_BODY_CHUNK :=
 prefix_code 6
 requested_length (integer)

詳細 :

Send Body Chunk

チャンクは基本的にはバイナリデータで、ブラウザに直接送られます。

Send Headers

ステータスコードとメッセージが通常の HTTP の通信にはあります (例 200OK)。レスポンスヘッダ名は、 リクエストヘッダ名と同様の方法でエンコードされます。 コードと文字列の判別方法の詳細に関しては、上記の header_encoding を参照してください。 一般的なヘッダのコードは :

名前 コードの値
Content-Type 0xA001
Content-Language 0xA002
Content-Length 0xA003
Date 0xA004
Last-Modified 0xA005
Location 0xA006
Set-Cookie 0xA007
Set-Cookie2 0xA008
Servlet-Engine 0xA009
Status 0xA00A
WWW-Authenticate 0xA00B

コードかヘッダ文字列の直後には、ヘッダの値がエンコードされます。

End Response

リクエスト処理サイクルの終了を知らせます。reuse フラグが真 (==1) の場合、現在使用している TCP コネクションは次の新しい リクエストに使えるようになります。reuse が偽 (C のコードでは 1 以外の全て) の場合は、コネクションを閉じることになります。

Get Body Chunk

(ボディのサイズが大きすぎて最初のパケットに収まらない場合や、 リクエストがチャンク転送された場合などには、) コンテナはリクエストからの データ読み込み要求をします。サーバ側はそれに対して、最小 request_length 最大 (8186 (8 Kbytes - 6)) の範囲で、未転送で残っているリクエストボディの大きさのデータを 送り返します。
ボディにそれ以上データが残っていない場合 (つまりサーブレットが ボディの最後を超えて読み込もうとした場合) 、サーバは ペイロード長 0 の空パケット(0x12,0x34,0x00,0x00) を送り返します。

翻訳済み言語: en | ja

top

コメント

Notice:
This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our mailing lists.

AltStyle によって変換されたページ (->オリジナル) /