258N/A<?
xml version="1.0" encoding="UTF-8"?>
258N/A XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 258N/A This file is generated from xml source: DO NOT EDIT 919N/A XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 919N/A<
title>mod_proxy_ajp - Apache HTTP サーバ</
title>
919N/A<
p class="apache">Apache HTTP サーバ バージョン 2.5</
p>
919N/A<
div class="up"><
a href="./"><
img title="<-" alt="<-" src="/images/left.gif" /></
a></
div>
258N/A<
div id="preamble"><
h1>Apache モジュール mod_proxy_ajp</
h1>
258N/A<
div class="outofdate">この日本語訳はすでに古くなっている
493N/A 最近更新された内容を見るには英語版をご覧下さい。
810N/Aをサポートするためのモジュール</
td></
tr>
705N/A <
code>Apache JServ Protocol version 1.3</
code> (以降 <
em>AJP13</
em>)
493N/A <
p><
code>AJP13</
code> プロトコルを扱えるようにするには
258N/A <
div class="warning"><
h3>警告</
h3>
910N/A <
p><
a href="#access">安全なサーバにする</
a>までプロクシ機能は有効にしないでください。
258N/A オープンプロキシサーバはあなた自身のネットワークにとっても、
258N/A インターネット全体にとっても危険です。</
p>
<
div id="quickview"><
h3 class="directives">ディレクティブ</
h3>
<
p>このモジュールにディレクティブはありません。</
p>
<
li><
img alt="" src="/images/down.gif" /> <
a href="#overviewprotocol">プロトコルの概要</
a></
li>
<
li><
img alt="" src="/images/down.gif" /> <
a href="#basppacketstruct">基本パケット構造</
a></
li>
<
li><
img alt="" src="/images/down.gif" /> <
a href="#rpacetstruct">リクエストパケット構造</
a></
li>
<
li><
img alt="" src="/images/down.gif" /> <
a href="#resppacketstruct">レスポンスパケット構造</
a></
li>
</
ul><
ul class="seealso"><
li><
a href="#comments_section">コメント</
a></
li></
ul></
div>
<
div class="top"><
a href="#page-header"><
img alt="top" src="/images/up.gif" /></
a></
div>
<
h2><
a name="overviewprotocol" id="overviewprotocol">プロトコルの概要</
a></
h2>
<
p><
code>AJP13</
code> プロトコルはパケット指向です。
可読なプレーンテキスト形式ではなくバイナリ形式になったのは、
ウェブサーバはサーブレットコンテナと TCP コネクションで通信します。
ソケット生成は重い処理なので、負荷を減らすために、サーブレットコンテナとの
TCP 接続を維持し、複数のリクエスト・レスポンス処理サイクルに対して一つの
コネクションを使いまわすようになっています。</
p>
<
p>あるリクエストにコネクションが割り当てられると、その処理サイクルが
つまりコネクション上では、リクエストの同時処理は行われません。
このため、コネクション両端での実行するコードを簡潔にできる一方で、
同時に開くコネクションは多くなっています。</
p>
<
p>サーブレットコンテナへのコネクションを開いた後は、コネクションの状態は
<
li> Idle <
br />コネクション上で処理されているリクエストはありません。</
li>
<
li> Assigned <
br />コネクションはリクエストを処理中です。</
li>
<
p>コネクションが特定のリクエストにアサインされると、基本的な情報 (例えば
HTTP ヘッダ等) が圧縮された形 (例えば通常の文字列は整数にエンコードされます)
で転送されます。詳細は下記の「リクエストパケットの構造」を参照してください。
リクエストにボディが存在 <
code>(content-length > 0)</
code> すれば、
基本的な情報の直後に別パケットで転送されます。</
p>
<
p>この時点でおそらく、サーブレットコンテナは処理を開始できるようになります。
ですので、次のメッセージをウェブサーバに戻して知らせられるようになります。</
p>
<
li>SEND_HEADERS <
br />ブラウザにヘッダを送信します。</
li>
<
li>SEND_BODY_CHUNK <
br />ブラウザにボディデータのチャンクを送ります。
<
li>GET_BODY_CHUNK <
br />リクエストのデータを全て受け取り終わっていないときに、
残っているデータを受け取ります。パケットにある定まった最大長があり、任意の
大きさのデータがリクエストのボディとして含まれうる場合
(例えばファイルのアップロードの場合) に必要となります。
(注: HTTP のチャンク転送とは関連ありません。)</
li>
<
li>END_RESPONSE <
br />リクエスト処理サイクルを終了します。</
li>
<
p>個々のメッセージはそれぞれ異なるデータパケット形式になっています。
後述の「レスポンスパケットの構造」を参照してください。</
p>
</
div><
div class="top"><
a href="#page-header"><
img alt="top" src="/images/up.gif" /></
a></
div>
<
h2><
a name="basppacketstruct" id="basppacketstruct">基本パケット構造</
a></
h2>
<
p>このプロトコルには XDR から受け継いだ部分が少しありますが、多くの点で
異なります (例えば 4 バイトアライメントでないことなど) 。</
p>
<
p>バイトオーダー: 個々のバイトのエンディアンがどうなっているかは、
私は詳しくないのですが、リトルエンディアンになっていると思います。
(C で) そういう風にできているのでそうなのだと思いました。
ソケット呼び出しの内部についてより詳しい方がいらっしゃいましたら、
<
p>プロトコルには 4 つのデータタイプがあります: byte, boolean,
<
dt><
strong>Byte</
strong></
dt><
dd>バイト一つです。</
dd>
<
dt><
strong>Boolean</
strong></
dt>
<
dd>バイト一つで、<
code>1 = true</
code>, <
code>0 = false</
code> です。
(C のように) 非零を真として扱ってしまうと、ある場合は動くかもしれませんし、
<
dt><
strong>Integer</
strong></
dt>
<
dd><
code>0 から 2^16 (32768)</
code> の範囲の数字。高次の 2 バイトが
<
dt><
strong>String</
strong></
dt>
<
dd>可変長の文字列 (2^16 が長さの上限) 。長さ情報のパケット 2 バイトの後に
文字列 (終端文字 '\0' を含む) が続く形式でエンコードされます。
エンコードされている長さ情報は最後の '\0' を<
strong>カウントしない</
strong>
ことに注意してください――これは <
code>strlen</
code> と同様です。
これらの終端文字をスキップするために、あまり意味の無いインクリメント文
Java の側から見ると少し紛らわしく感じられるかもしれません。
こうなった理由はおそらく、Servlet コンテナから返される文字列を読み出す時に、
効率よく C のコードを書けるようにする――サーブレットから返される
文字列は \0 文字で終端されているので、C のコードではわざわざコピーをせずに、
一つのバッファへのリファレンスを取り回すように書くことができる――
'\0' 文字がない場合は、C では文字列の規則に合うようにコピーしなければ
<
p>多くのコードでそうなっているのですが、パケットサイズの最大サイズは
<
code>8 * 1024 (8K)</
code> です。パケットの実際の長さはヘッダに
<
p>サーバからコンテナに送出されるパケットは <
code>0x1234</
code> で始まります。
コンテナからサーバに送られるパケットは <
code>AB</
code> (ASCII コード A と
ASCII コード B) で始まります。この二バイトの後に、ペイロード長が (上記の形式で)
続きます。このため、ペイロード長の最大値は 2^16 にできるように思えますが、
実際にはコードでは最大値は 8K に設定されています。</
p>
<
td colspan="6"><
em>パケット形式 (Server->Container)</
em></
td>
<
td colspan="2">データ長 (n)</
td>
<
td colspan="6"><
em>パケット形式 (Container->Server)</
em></
td>
<
td colspan="2">データ長 (n)</
td>
<
p>ほとんどのパケットで、ペイロードの最初のバイトがメッセージの型をエンコード
しています。例外はサーバからコンテナに送られるリクエストボディパケットです
――これらは標準的なパケット形式 (<
code>0x1234</
code> とパケット長)
ですが、その後に続くプレフィックスコードがありません。</
p>
<
p>ウェブサーバは次のメッセージをサーブレットコンテナに送出できます。</
p>
<
td>リクエスト処理サイクルを後続のデータとともに開始する。</
td>
<
td>ウェブサーバがコンテナに、コンテナを終了するように伝える。</
td>
<
td>ウェブサーバがコンテナに制御を受け持つように伝える
<
td>ウェブサーバがコンテナに CPong で即座に応答するように伝える。</
td>
<
td>サイズ (2 バイト) とそれに続くボディデータ。</
td>
<
p>基本的なセキュリティを確保するため、ホストされているマシンと同一の
マシンからのリクエストに対してのみ、コンテナは実際に <
code>Shutdown</
code>
<
p>最初の <
code>Data</
code> パケットは、<
code>Forward Request</
code>
<
p>サーブレットコンテナはウェブサーバに、次のタイプのメッセージを送ることが
(そしておそらくそのままブラウザに)、ボディのチャンクを送る。</
td>
<
td>サーブレットコンテナからウェブサーバに (そしておそらくそのままブラウザに)
<
td>レスポンス (つまりリクエスト処理サイクル) 終了の目印を送る。
<
td>まだ全て転送されていない場合、残っているリクエストのデータを受け取る。
<
td>CPing リクエストに応答する。</
td>
<
p>上記メッセージは、それぞれ内部構造が異なっています。詳細は下記をご覧ください。
</
div><
div class="top"><
a href="#page-header"><
img alt="top" src="/images/up.gif" /></
a></
div>
<
h2><
a name="rpacetstruct" id="rpacetstruct">リクエストパケット構造</
a></
h2>
<
em>Forward Request</
em> 型の場合 :</
p>
<
div class="example"><
pre>
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
request_headers *(req_header_name req_header_value)
attributes *(attribut_name attribute_value)
request_terminator (byte) OxFF
<
p><
code>request_headers</
code> は次のような構造になっています :
</
p><
div class="example"><
pre>
sc_req_header_name | (string) [see below for how this is parsed]
sc_req_header_name := 0xA0xx (integer)
req_header_value := (string)
<
p><
code>属性</
code> はオプションで、次のような構造をしています :</
p>
<
div class="example"><
pre>
attribute_name := sc_a_name | (sc_a_req_attribute string)
attribute_value := (string)
<
p>もっとも重要なヘッダは <
code>content-length</
code> だということに
注意してください。コンテナは次のパケットを探すかどうかを、
<
h3>Forward Request 要素の詳細な説明
<
p>リクエストについては全て、この値は 2 になります。他の Prefix コードの詳細は
<
p>HTTP メソッドは 1 バイトにエンコードされます :</
p>
<
tr><
td>Command Name</
td><
td>Code</
td></
tr>
<
tr><
td>OPTIONS</
td><
td>1</
td></
tr>
<
tr><
td>GET</
td><
td>2</
td></
tr>
<
tr><
td>HEAD</
td><
td>3</
td></
tr>
<
tr><
td>POST</
td><
td>4</
td></
tr>
<
tr><
td>PUT</
td><
td>5</
td></
tr>
<
tr><
td>DELETE</
td><
td>6</
td></
tr>
<
tr><
td>TRACE</
td><
td>7</
td></
tr>
<
tr><
td>PROPFIND</
td><
td>8</
td></
tr>
<
tr><
td>PROPPATCH</
td><
td>9</
td></
tr>
<
tr><
td>MKCOL</
td><
td>10</
td></
tr>
<
tr><
td>COPY</
td><
td>11</
td></
tr>
<
tr><
td>MOVE</
td><
td>12</
td></
tr>
<
tr><
td>LOCK</
td><
td>13</
td></
tr>
<
tr><
td>UNLOCK</
td><
td>14</
td></
tr>
<
tr><
td>ACL</
td><
td>15</
td></
tr>
<
tr><
td>REPORT</
td><
td>16</
td></
tr>
<
tr><
td>VERSION-CONTROL</
td><
td>17</
td></
tr>
<
tr><
td>CHECKIN</
td><
td>18</
td></
tr>
<
tr><
td>CHECKOUT</
td><
td>19</
td></
tr>
<
tr><
td>UNCHECKOUT</
td><
td>20</
td></
tr>
<
tr><
td>SEARCH</
td><
td>21</
td></
tr>
<
tr><
td>MKWORKSPACE</
td><
td>22</
td></
tr>
<
tr><
td>UPDATE</
td><
td>23</
td></
tr>
<
tr><
td>LABEL</
td><
td>24</
td></
tr>
<
tr><
td>MERGE</
td><
td>25</
td></
tr>
<
tr><
td>BASELINE_CONTROL</
td><
td>26</
td></
tr>
<
tr><
td>MKACTIVITY</
td><
td>27</
td></
tr>
<
p>今後の ajp13 バージョンでは、この一覧にない、今後追加されるメソッドを
<
h3>protocol, req_uri, remote_addr, remote_host, server_name,
<
p>これらはまさに文字通りのものです。どれも必要で、リクエストの毎回につき
<
p><
code>request_headers</
code> の構造は次のようなものです :
まずヘッダの数 <
code>num_headers</
code> がエンコードされます。
次にヘッダ名 <
code>req_header_name</
code> / 値 <
code>req_header_value</
code>
の組が続きます。効率のため、一般的なヘッダは整数でエンコードして転送します。
ヘッダ名が基本ヘッダの一覧に無い場合は、通常通り (文字列として、長さ
プレフィックス付きで) 転送されます。一般的なヘッダ
<
code>sc_req_header_name</
code> の一覧とそのコードは次の通りです
<
tr><
td>名前</
td><
td>コードの値</
td><
td>コード名</
td></
tr>
<
tr><
td>accept</
td><
td>0xA001</
td><
td>SC_REQ_ACCEPT</
td></
tr>
<
tr><
td>accept-charset</
td><
td>0xA002</
td><
td>SC_REQ_ACCEPT_CHARSET
<
tr><
td>accept-encoding</
td><
td>0xA003</
td><
td>SC_REQ_ACCEPT_ENCODING
<
tr><
td>accept-language</
td><
td>0xA004</
td><
td>SC_REQ_ACCEPT_LANGUAGE
<
tr><
td>authorization</
td><
td>0xA005</
td><
td>SC_REQ_AUTHORIZATION</
td>
<
tr><
td>connection</
td><
td>0xA006</
td><
td>SC_REQ_CONNECTION</
td></
tr>
<
tr><
td>content-type</
td><
td>0xA007</
td><
td>SC_REQ_CONTENT_TYPE</
td>
<
tr><
td>content-length</
td><
td>0xA008</
td><
td>SC_REQ_CONTENT_LENGTH</
td>
<
tr><
td>cookie</
td><
td>0xA009</
td><
td>SC_REQ_COOKIE</
td></
tr>
<
tr><
td>cookie2</
td><
td>0xA00A</
td><
td>SC_REQ_COOKIE2</
td></
tr>
<
tr><
td>host</
td><
td>0xA00B</
td><
td>SC_REQ_HOST</
td></
tr>
<
tr><
td>pragma</
td><
td>0xA00C</
td><
td>SC_REQ_PRAGMA</
td></
tr>
<
tr><
td>referer</
td><
td>0xA00D</
td><
td>SC_REQ_REFERER</
td></
tr>
<
tr><
td>user-agent</
td><
td>0xA00E</
td><
td>SC_REQ_USER_AGENT</
td></
tr>
<
p>これを読み込む Java のコードでは、最初の 2 バイト整数を取り込み、
目印になるバイト <
code>'0xA0'</
code> であれば、ヘッダ名の配列の
インデックスを使います。先頭バイトが <
code>0xA0</
code> でない場合は、
先頭 2 バイトは文字列長を表す整数であると解釈し、読み込みはじめます。</
p>
<
p>ヘッダ名の長さは <
code>0x9999 (==0xA000 -1)</
code> 以上にならないという
仮定の下に動いていて、少しあいまいですが合理的な挙動になっています。</
p>
<
div class="note"><
h3>注:</
h3>
<
code>content-length</
code> ヘッダはとても重要です。
存在していて非ゼロであれば、リクエストにはボディがある (例えば POST
リクエスト) と推測し、そのボディを取り込むために
直後のパケットを入力ストリームから読み込みはじめます。
<
p><
code>?</
code> プレフィックスで始まる属性 (例 <
code>?context</
code>)
は。省略可能です。それぞれ属性の型を示す 1 バイトのコードと、
これらは順不同で送ることができます (C のコードは常に下の一覧順に
オプションの属性のリストの最後には、特別な終了コードが送られます。
<
tr><
td>Information</
td><
td>Code Value</
td><
td>Type Of Value</
td><
td>Note</
td></
tr>
<
tr><
td>?context</
td><
td>0x01</
td><
td>-</
td><
td>未実装
<
tr><
td>?servlet_path</
td><
td>0x02</
td><
td>-</
td><
td>未実装
<
tr><
td>?remote_user</
td><
td>0x03</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?auth_type</
td><
td>0x04</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?query_string</
td><
td>0x05</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?jvm_route</
td><
td>0x06</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?ssl_cert</
td><
td>0x07</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?ssl_cipher</
td><
td>0x08</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?ssl_session</
td><
td>0x09</
td><
td>String</
td><
td /></
tr>
<
tr><
td>?req_attribute</
td><
td>0x0A</
td><
td>String</
td><
td>Name (the name of the
attribute follows)</
td></
tr>
<
tr><
td>?ssl_key_size</
td><
td>0x0B</
td><
td>Integer</
td><
td /></
tr>
<
tr><
td>are_done</
td><
td>0xFF</
td><
td>-</
td><
td>request_terminator</
td></
tr>
<
p><
code>context</
code> と <
code>servlet_path</
code> は現在の C の
コードではセットされていません。また、ほとんどの Java のコードでも、
このフィールドで何が送られても無視されます (これらのコードの後に文字列が
これがバグなのか、単に未実装なのか、歴史的経緯で残っているコードなのか
分かりませんが、コネクションの両側ともで見当たりません。</
p>
<
p><
code>remote_user</
code> と <
code>auth_type</
code> はおそらく
HTTP レベルの認証を参照していて、リモートユーザのユーザ名と認証に使用した
タイプ (例 Basic, Digest) についてやり取りします。</
p>
<
p><
code>query_string</
code>, <
code>ssl_cert</
code>,
<
code>ssl_cipher</
code>, <
code>ssl_session</
code>
は HTTP と HTTPS の対応する部分を参照します。</
p>
<
p><
code>jvm_route</
code> はスティッキーセッションのサポート――
ロードバランスしている複数のサーバ中の特定の Tomcat インスタンスと、
ユーザのセッションとを紐付ける機能――に使われます。</
p>
<
p>この基本属性一覧に無いものについては、<
code>req_attribute</
code>
コード <
code>0x0A</
code> 経由で属性を何個でも送ることができます。
属性の名前と値の文字列の組を、それぞれこのコードの直後に送ります。
<
p>最後に属性が全て送信された後に、属性の終端を示す <
code>0xFF</
code>
が送出されます。この信号は属性の一覧の終わりを示すと同時に、リクエスト
</
div><
div class="top"><
a href="#page-header"><
img alt="top" src="/images/up.gif" /></
a></
div>
<
h2><
a name="resppacketstruct" id="resppacketstruct">レスポンスパケット構造</
a></
h2>
<
p>コンテナがサーバに送り返すことのできるメッセージ:</
p>
<
div class="example"><
pre>
chunk_terminator (byte) Ox00
http_status_code (integer)
response_headers *(res_header_name header_value)
sc_res_header_name | (string) [see below for how this is parsed]
sc_res_header_name := 0xA0 (byte)
requested_length (integer)
<
p>チャンクは基本的にはバイナリデータで、ブラウザに直接送られます。</
p>
<
p>ステータスコードとメッセージが通常の HTTP の通信にはあります (例
<
code>200</
code> と <
code>OK</
code>)。レスポンスヘッダ名は、
リクエストヘッダ名と同様の方法でエンコードされます。
コードと文字列の判別方法の詳細に関しては、上記の header_encoding
<
tr><
td>名前</
td><
td>コードの値</
td></
tr>
<
tr><
td>Content-Type</
td><
td>0xA001</
td></
tr>
<
tr><
td>Content-Language</
td><
td>0xA002</
td></
tr>
<
tr><
td>Content-Length</
td><
td>0xA003</
td></
tr>
<
tr><
td>Date</
td><
td>0xA004</
td></
tr>
<
tr><
td>Last-Modified</
td><
td>0xA005</
td></
tr>
<
tr><
td>Location</
td><
td>0xA006</
td></
tr>
<
tr><
td>Set-Cookie</
td><
td>0xA007</
td></
tr>
<
tr><
td>Set-Cookie2</
td><
td>0xA008</
td></
tr>
<
tr><
td>Servlet-Engine</
td><
td>0xA009</
td></
tr>
<
tr><
td>Status</
td><
td>0xA00A</
td></
tr>
<
tr><
td>WWW-Authenticate</
td><
td>0xA00B</
td></
tr>
<
p>コードかヘッダ文字列の直後には、ヘッダの値がエンコードされます。</
p>
<
p>リクエスト処理サイクルの終了を知らせます。<
code>reuse</
code> フラグが真
<
code>(==1)</
code> の場合、現在使用している TCP コネクションは次の新しい
リクエストに使えるようになります。<
code>reuse</
code> が偽 (C のコードでは
1 以外の全て) の場合は、コネクションを閉じることになります。</
p>
<
p>(ボディのサイズが大きすぎて最初のパケットに収まらない場合や、
リクエストがチャンク転送された場合などには、) コンテナはリクエストからの
データ読み込み要求をします。サーバ側はそれに対して、最小
<
code>request_length</
code> 最大 <
code>(8186 (8 Kbytes - 6))</
code>
の範囲で、未転送で残っているリクエストボディの大きさのデータを
ボディにそれ以上データが残っていない場合 (つまりサーブレットが
ボディの最後を超えて読み込もうとした場合) 、サーバは
ペイロード長 0 の<
em>空パケット</
em><
code>(0x12,0x34,0x00,0x00)</
code>
<
p><
span>翻訳済み言語: </
span><
a href="/en/mod/mod_proxy_ajp.html" hreflang="en" rel="alternate" title="English"> en </
a> |
</
div><
div class="top"><
a href="#page-header"><
img src="/images/up.gif" alt="top" /></
a></
div><
div class="section"><
h2><
a id="comments_section" name="comments_section">コメント</
a></
h2><
div class="warning"><
strong>This section is experimental!</
strong><
br />Comments placed here should not be expected
to last beyond the testing phase of this system, nor do we in any way guarantee that we'll read them.</
div>
var disqus_shortname = 'httpd'; d.write('<div id="disqus_thread"><\/div>'); d.write('<div id="disqus_thread">Comments are disabled for this page at the moment.<\/div>'); //--><!]]></
script></
div><
div id="footer">
if (typeof(prettyPrint) !== 'undefined') {